sudo fry rolls /* This blog is actually mobile-friendly! */

LensCulture Magnum Photos Award 2017 Submission Review

I submitted a series of images to a LensCulture competition last year.

Hanoi: A Journey of Rediscovery

These are selected from 10 rolls of film I shot in the street during my trip to Hanoi earlier this year (2017) for the Lunar New Year.

There was not much hope in winning anyway. I gave it up very quickly after I saw the competition highlights. But each entry is given a free review, and I thought that was still worth going for.

Then I completely forgot about it. Somehow LensCulture did not notify me when the review came out either (and that was 6 months ago). I only found it today by contacting their support after wondering what the hell I paid them for after going through some of my bank statements.

In the review notes, I asked what I should do to strengthen my narratives and improve story-telling in a body of work. I was not disappointed. Here it goes:

The review:

submission images

I am moved by this work and the personal nature of going home again. To make a visual record of a place you once knew well but are retracing requires some text which you have provided. It’s especially important in a few of the photographs like the motorbike and the family with cafe and home in one. You mention wanting to strengthen your storytelling here but in my opinion, it’s already pretty good! Your commentary seems to be about the city from a little bit of distance though and I found myself wanting to see someone you knew or family or something even more personal which you may have in other frames? If so, try including it in this edit. If I want to give a single piece of advice it would be to watch your framing. Sometimes it is really exquisite which raises the bar high and then some of the other images seem like they may have been rushed or taken without consent. #8 & 9 are in the top category for me where you have photographed a real moment in time in such a way that your viewer is drawn to examine the entire image. We want to see in the photograph itself as much as possible because it is such a strong depiction of this time/place/emotion. Beautifully done! #1,5,6 and 7 are also great in the series. The few that I take exception with are #2,3 and 4 and mainly the reason is that I want to add more to each of these scenes. I want to see the context in which each of these photographs is taken. In the Dominos photograph, the sign is a major part of the image but you are skilled photographer and with the method seen in image #9, you would be able to say something that shows the old vs. new in a more striking way.

I say this because again, you have some absolutely wonderful works here and your interest in pulling them together and elevating the narrative all point to wanting to have a cohesive body of work. These comments are meant to be encouraging in that direction. I am also wondering if there is a London component here. What is the counter point to your previous life in Hanoi where you live now? There is a photographer named Alec Soth who has done some personal work with his own life story that you might take a look at. Magnum photographs has a number of members who make personal stories especially someone like Guerogui Pinkhassov. Am also appreciating that you work with film here. This technique can slow photographers down but that can be a good thing, making you consider each frame and to economize with your material in a way that digital doesn’t often make us do.

Thanks for sharing this work and I wish you much success in the future with it!

Additional Recommendations (books & photographers)

  • The Decisive Moment, by Henri Cartier-Bresson
  • Street Photography and the Poetic Image, by Alex Webb and Rebecca Norris Webb
  • Street Photography Now, by Sophie Howarth and Steve McLaren
  • 18 Composition Rules for Photos That Shine (online article)
  • Photography as Activism: Images for Social Change by Michelle Bogre

Other Resources

Relevant Quotes from Past Jurors

“I’m looking for a clear expression of an idea; I ask why is the photographer asking me to look at this? When reviewing hundreds of submissions, exceptional, well-executed work that animates an idea and is visually exciting really stands out and deserves to be recognized.” — Michael Famighetti, Editor, Aperture Magazine, New York City, USA

“A good text with the pictures is short, concise, to the point, informed, descriptive. I find it helps to imagine you are speaking to a smart child who would rather be outside playing with friends: you have very little time to tell the story and explain WHY it matters. The same holds true for captions. 1st sentence: describe the image. 2nd sentence: why and how this image fits into the body of work.” — Daphné Anglès , Picture Editor, The New York Times, Paris, France

“I am interested in pictures that educate the viewer about a topic. I’m drawn to sociopolitical landscapes or personal human dramas that can be viewed in a wider context beyond the depicted subject, as well as art that pushes the boundaries of traditional photography.” — Natasha Egan, Executive Director, Museum of Contemporary Photography, Columbia College, Chicago, IL, USA

“Every great picture tells a story and should be able to stand on its own, but viewers are often eager to know a little bit more about what the photo is about. So a simple title or caption, or a few words, can make a great photo really come to life in someone’s imagination.” — Jim Casper, Editor & Publisher of LensCulture

SVUK Leader Camp 2018 notes

Here are my personal notes from the event yesterday.

Topic: “The goal is for young leaders to be inspired from your story and go back to their VietSoc and have that mindset of connecting ppl and their community”


“Đoàn kết” (unity) in its purest sense is virtually impossible

  • Each person within a community has a different idea
  • It is impossible to please everyone
  • A good community is one that empowers its member
  • A good community is also one that has a strong core team - inspiration is contagious
  • Vietnamese communities and student communities have a great advantage: naturally we are drawn to each other
  • Politics is an inevitable part of the community building experience. Unity is built, not taken for granted
  • VietStartup is built around this principle. I also wished for Oxford to have been like this, but back in the day we never really had the vision to go out of our way to do such things even though we had more spare time. The furthest we ever got to was probably study groups or playing football
  • Tip: find a purpose for your community. When people have a common goal to work towards, it is an easier challenge

Leadership comes in many shapes and forms

  • There are leaders who are aggressive and will try to reach for the extremes, but there are also pacifiers
  • Extremes evolve the community, the very progressive & extreme leaders are perfect for this, but it is important to find a balance - the pacifier handles this.
  • VietStartup utilises this mechanism: the community needs to be always moving forward, and a constantly changing community needs pacifiers to resolve the differences and reach a consensus.
  • VOX lacked the radical leader in all of the years I was there. It might have made sense at the time, but now I think of it as a waste given the amount of potential that we had
  • Tip: give a thought to how your leadership team is structured, their personalities, assess your society needs and split your tasks accordingly

A functioning community or society is one that is actually social

  • And it should not only be so amongst its own members but also with other communities/societies
  • The reality is that for highly-purposed community like VietStartup, we can never fulfil the needs of all of our members at all times so we need to venture out
  • It is what I regretted not doing more when I was president at VOX. A prime example would be days like today where we all gather, or VietPro doing events that are impossible for VietStartup to pull off

Have fun

  • Part of the bonding experience is to be connected on different levels
  • It could be as simple as a drink after work or study groups or field trips or sports
  • Cater to what your people like and feel the most comfortable with. This not only applies to your society/community as a whole but also even more importantly to your core team.

A physical postcard in a world of virtual goods

No matter how much we advance in our technology and migrate more and more aspects of life into the virtual realm, there is still this strange attachment to physical objects. I still like keeping small photobooks of my own photographs, and I enjoy shooting film very much. To me, being able to appreciate the physical embodiment of one’s work is a magical feeling, given my complete opposite digital lifestyle.

Long story short, I whipped up an MVP for Esplorio Postcards when we were on a coding trip in Sri Lanka out of the frustration of having to find a post office, hunting for a generic card (as a photographer I want to send the gift of my own creation and experience) then trying to communicate which stamps I want. Instead, now that I’ve already had an Esplorio feed of organised pretty photos, a customised physical postcard to my loved ones is a tap and an Apple Pay touch away on the new version of Esplorio iOS app. See how easy it is:

This is why I love working in a startup - going from ideas to production is a very quick journey.

If you are interested in my work, please go ahead and check out

How TechCrunch Japan broke our app - Handling local calendars in Swift


“Timezone”, “calendar”, “region”, “locale” are 4 words that strike fear into my mind

I am writing this blog entry as a note to myself for future reference in case other people have the same problems as well, especially if you use DateTools and CoreData in your app

Time format plays a big role in our application. We not only need to be able to make requests to our backend servers with the right format (let’s say something like “get all data before 1 Jan 2016”), but also need to show the user the date in a consistent way. Now since we suddenly got a big feature in TechCrunch Japan and had an influx of new users from the other side of the planet, I thought maybe it is a good idea to switch to the Japanese calendar to see if our app still works correctly.

This uncovered a whole world of hurt given that we have not done any proper localisation yet, and are really keen on keeping Gregorian calendar as the standard across our codebase.

Problem 1

Unless specified, the default locale for any dates in the system will obey the locale of the local region. This is a well-known problem - even Apple has an official documentation here stating that you should really use en_US_POSIX if you want to keep everything consistently Gregorian. This was solved easily by setting all our date formatters to use that locale.

Problem 2

Like many other apps, we use CoreData as the backend for our client-side database and DateTools to handle many datetime-related tasks. The issue starts with NSDate instances stored in CoreData obeying the system calendar. It means this piece of code:

    let today = <A date value retrieved from CoreData>
    let formatter = NSDateFormatter()
    formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
    formatter.dateFormat = `dd MMM yyyy`

would result in 04 Jan 0028 once the phone is set to use Japanese calendar, and today will think of itself as if it is the year 0028 in Gregorian. If you then use it to perform calculations/manipulations or send it as it is to your backend API to process, it will be wrong.

The solution is to actually be using the en_US_POSIX locale but set both the default calendar identifier in DateTools and the calendar identifier on each formatter to the default system identifier. If you do not use DateTools, do make sure that whatever date/calendar solution you go with in the end does this as well!

    // The DateTools method to set default calendar
    // (do this once at app launch)

    // Rest of the code
    let today = <A date value retrieved from CoreData>
    let formatter = NSDateFormatter()
    formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
    formatter.dateFormat = `dd MMM yyyy`

It means that any NSDate instances retrieved from CoreData would always point to the right point in time, i.e. 04 Jan 0028 in Japan calendar now always points to the same point in time as 04 Jan 2016 in Gregorian calendar (having the same Unix timestamp 1451865600). Then, the effect of using the en_US_POSIX locale would in turn cause the date instance with timestamp 1451865600 being formatted into the right Gregorian format that we want: 04 Jan 2016.

Problem 3

Right, so we have solved that problem with CoreData, what is going to happen to dates created inside the app but not saved to CoreData? The answer is that it is totally messed up as well since you have done NSDate.setDefaultCalendarIdentifier(NSCalendar.currentCalendar().calendarIdentifier) at the beginning

The problem is now when creating new NSDate instances within the app, the local system calendar will be used by default

    // Notice the `NSDate()`
    let today = NSDate()
    let formatter = NSDateFormatter()
    formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
    formatter.dateFormat = `dd MMM yyyy`

The above code will result in the string 04 Jan 0028. To work around this problem, I temporarily fall back to the Gregorian calendar in the formatter for all of these dates which we need to show the user in the UI but are not created/retrieved from CoreData itself, then reset it to the system local one using defer. The full code is then:

  // A date formatter used for display views
  private static let displayDateFormatter: NSDateFormatter = {
    // Remember this following call is put here for illustration
    // In reality it should be in app launch
    let formatter = NSDateFormatter()
    // Use the default calendar identifier but with the en_US_POSIX locale
    // This will avoid weird dates from popping up
    formatter.locale = en_US_POSIX
    formatter.calendar = NSCalendar(identifier: NSDate.defaultCalendarIdentifier())
    return formatter


   Given a date (NSDate), it returns a string representation of it with only the date
  class func dateToDayDisplayString(date: NSDate, withFormat format: String,
    withTimeZone timezone: NSTimeZone? = nil, withCalendarIdentifier calendarIdentifier: String? = nil) -> String {
      if let timezone = timezone {
        displayDateFormatter.timeZone = timezone
      } else {
        displayDateFormatter.timeZone = NSTimeZone(name: "UTC")

      displayDateFormatter.dateFormat = format

      if let calendarIdentifier = calendarIdentifier {
        displayDateFormatter.calendar = NSCalendar(calendarIdentifier: calendarIdentifier)
      // This next line says always reset the calendar to the default one even after the return
      defer {
        if let _ = calendarIdentifier {
          displayDateFormatter.calendar = NSCalendar(identifier: NSDate.defaultCalendarIdentifier())
      return displayDateFormatter.stringFromDate(date)

If you are interested in my work, you can find out more about our product at

How I almost screwed up the Esplorio iOS launch and fixed it with duct tape

Team Esplorio officially launched the iOS app


Meet Polo - The Esplorio GPS Kitty

We first built our tracking app a long time ago. In the past few months, we put a beautiful UI on it and re-engineered the whole platform in the process.

We went from this simple one-page tracker prototype:

to a beautiful trip recording/sharing app:

this awesome app

With a bit of luck, we got Hunted and featured on the top of the Tech featured page for the day. Now that we’ve launched on the app store plus a shiny ProductHunt badge, it is pretty awesome.

What happened behind the scene?

For the 2 days leading up to the launch, we camped at Tim’s place to work our ass off. The first day we called it a day at 3am, and the second day we pulled an all-nighter trying to get all the launch stuff together then stayed up until late afternoon to respond to all the new traffic. That was almost 40 hours of work for the 2 days - which is pretty much a week equivalent for most people. It is insane! I do not recommend it.

And I almost f*cked it up

When shit hits the fan just before launch, it hits real hard.

About 13 hours before launch, I was doing usual maintenance on our servers, restarting some machines since the OS required a server restart for some security updates. One faulty restart then took out our whole database cluster. The cluster seemed to get into a very bad race condition and never recovered afterwards no matter what we did to save it. We then decommissioned it, spinned up a new production cluster to replace it using the latest backup that we had at the time. However, by the time the backup data was in place, it was already 3 hours before launch time, but our database views still had not finished indexing yet - which means the site and the app are both unusable.

Tim, Essa and I then had to make a call to whether we should keep going with the launch. It was a Thursday, the coming weekend would be the last weekend before Christmas, so we thought launching any time later than this (even on the Friday) would be a bad idea. At this point, we realised that we still have a staging database, which has the data replicated from production along with all the views being warmed up already, lying there ready to be used. We quickly tested it, everything seemed to work, the only risk is that since these are just staging servers, we have no replications set up, so we run the risk of having a bigger screw-up if one of the boxes fail.

We bit the bullet and used that cluster anyway. It worked flawlessly for the whole launch period. We then ran an XDCR during the launch from this substitute staging cluster to that new production cluster that we built overnight to make sure it always has newest data, with the hope that the view indices will be ready later in the day or maybe the day after at worst.

This afternoon, we confirmed that the new production cluster was ready. We made sure all the data is in place, switched all our servers to use that cluster and reversed the XDCR like it was before (production -> staging).

Yes, that’s right. We just fixed our app launch with duct tape and it worked - you can now get it at!

Startup life is fun.