Decisions, Decisions

Continuing the adventure of my move, I did a lot of furniture shopping. During university I never had to worry too much about furnishing a residence as I only spent at most a few months at a given place. However signing a long-term lease and purchasing furniture requires a lot more thought and responsibility. Furniture is expensive not only in terms of money, but also convenience since it is a hassle to deliver, install, and move. Mattresses and pillows are essential creature-comforts considering we sleep on them for a third of our lifetime which is why I believe thinking long-term is key.

Picking rooms

Houses are built with different layouts and features, making it difficult to split costs and assign rooms. Here is one solution to aims to provide a fair split: Everyone bids on a room in round robin fashion (if they skip then they cannot bid on that room anymore). The highest bidder gets that room and the process continues with the remaining rooms/people. This works well since the sum of all the rooms should equal the price of rent, so when bidding on any room, you are able to know how expensive the sum of all the remaining rooms are. Thus the price of a room will continue to rise as long more than one person thinks that price a good deal.

Amortizing furniture

Furniture can be expensive and the price tag by itself does not provide enough information to make a good decision. A different way to view the price is amortization, where the cost of an item is divided over several periods to better align the cost with usage. For example, an $800 couch can also be thought of as paying $80 per year, for the expected lifetime (say ten years). Putting it this way, wouldn’t you pay a fraction of a dollar per day to have a nice couch?

Sharing furniture

If multiple roommates are sharing furniture, what is the best way to also share the price? One idea is to have one owner per piece of furniture. This way it is clear who will be taking what when moving day comes. If costs are skewed, for example someone buys a $800 couch but the other only buys a $400 table, each person can pay the other a 15% “usage” fee for using each other’s furniture. This brings everyone’s expenses get closer to the average cost while maintaining the clear ownership.

At the showroom

Getting what you want

A common way for salespeople to greet customers is by asking “What brings you here?” This provides the salesperson valuable information about how likely they can make a sale, or the types of offers that might appeal. My initial reaction used to be to limit the amount of information I gave because I would then be the one holding the cards. However, after some experimenting and thinking, it is better to give clear specs of what I have in mind because now they have a better understanding of what I am looking for (who would have thought huh?). Nonetheless it is still important to verify the facts provided, for example asking rhetorically “New as in unopened?” can help ensure it is indeed what you think the salesperson meant.

Source of knowledge

Most people don’t shop for furniture very often so we don’t bother keeping up with the latest technologies or even the basic definitions. For example, what’s the best mattress for me, spring, latex, foam, or memory foam? Thus you should take advantage of their knowledge, getting immediate answers instead of wasting time scouring the Internet.

Sales (FOMO) tactics

The root of these tactics is how people react to uncertainty and deadlines. Even if a customer understands the different types of mattresses, how can someone determine for a given mattress whether it is right for them? Are you going to walk in a showroom in your PJ’s? How can anyone sleep with the lights on? How do you know if a mattress can maintain its original quality after a few years?

Difference in experience

One thing to be wary of is the difference in knowledge and experience of a salesperson. It is their job, they are probably good at it, but most importantly, they have all the time in the world. You don’t. I suggest noting down key facts, taking pictures of sales tags, and reading reviews/prices from online.


Salespeople get a bad rep for using pressure tactics like “i would be surprised if this remains in stock by the end of this week” to invite doubt and FOMO. Stores also use flash sales to create this urgency. Yes, you should definitely try to take advantage of the offer, however be wary as to whether the prices were first hiked up so that it looks like you are getting a good deal. Just remember that ultimately you are the one making the purchase and will be sleeping on it for a long time, so don’t settle for less. There are definitely salespeople who care about the customer, but at the end of the day they still need to meet their target and you need your sleep.

This requires a separate post but in short I think they are really good at marketing the product at the right audience online through a variety of targeted mediums. Their website is informative by highlighting individual features with simple graphics. Gorgeous pictures give light to what your life could be like by purchasing a Casper. The high prices in whole dollars provide the impression of respect and prestige. All of this is contributes to the branding and conveys a sense of quality and luxury.

Then, distinct market segments are targeted through different channels. For example, an ad on a podcast might be purchased where the host, whom the audience already has a connection with, reads an excerpt explaining the product and provide a promo code. Promo codes are important because it makes the audience feel special and provides FOMO because they don’t want the code to expire before they have taken advantage of it. This higher chance of purchase with a promo code is worth the slight decrease in margins and also means one more customer who can provide testimonials to friends.

I think they have done a really good job at marketing the product and I hope my analysis (not endorsement) doesn’t come off as being negative or judgmental.


1] DON’T FALL FOR PRESSURE TACTICS An old article yet still has some good tips

2] Boiler Room movie about pressure tactics. At least buying a mattress is tangible and offers a good night sleep

3] Did you know BOO stands for Boo October’s Over? Yes, it’s recursive

Driving in San Francisco Bay Area

I recently moved to California from Toronto and wanted to share some of my experience with the roads and driving conditions.

Driver’s license

California driver’s license has two tests: a written knowledge and a road test. Be sure to book an appointment or line up very early because the lines get packed real fast. Enterprise seems to be the only car rental company that allows their cars to be used for road tests (ask them to provide you a letter stating their car can be used). Instead of a parallel park (as with Ontario road tests), here you will be tested to pull beside the curb within a feet or so, then backup for a few car lengths. There’s no highway component and only one road test (Ontario has a two-stage graduated system).

Driving conditions

San Francisco and the South Bay have some of the worst traffic I’ve seen. The traffic lights seem to be optimized for major arteries, staying green for up to a minute or more. This helps alleviate rush hour traffic (it’s also possible to drive many blocks at night without ever stopping).

This does require some adjustments to the roads. Many roads have concrete dividers in the center so cars cannot simply turn left onto small roads (since this will block traffic). Thus U-turns are very common and major roads usually have two long stretches of left-turn lanes to deal with the buildup. These left-turn lanes have their own designated lights (whereas in Ontario the majority of intersections allow cars to turn left on a green light when it is safe). Overall it does seem like both systems work well for each cities’ own specific set of traffic patterns.

Many highways in California use meters (essentially a traffic light) to ensure sufficient gaps between cars while merging during rush hour. The on-ramps are usually very short and sometimes several merges are required before actually entering onto the freeway. One difference I’m still getting used to is when the rightmost lane merges into the one beside it. In California, the dashed lines between these two lanes just disappear, whereas in Ontario the lane markings make it obvious that the right lane is about to be merged.


There’s a lot of room for improvement for any road infrastructure because no one wants to be stuck in traffic. A zipper machine is useful when the direction of traffic alternates depending on the time of the day. There’s a lot of unused space underground and above ground for cars to travel, but this solution is likely more expensive.


1] Here’s a totally unrelated video about driving

World of Salad: Specialization and Being a T-Shaped Person

Normally when eating out I don’t venture into salad territory because it doesn’t seem filling to me. It wasn’t until recently that I discovered the world of salad bars - being able to add edamame, beets, carrots, grapes, fresh croutons, and more - was a game changer. Although it can be a bit daunting at first, the number of possibilities makes it hard to get old.

Salad is basically a regular dish except the veggies are raw.

When I had salad at home it was a side dish and, since we don’t prepare on the scale of a restaurant, this usually consisted of plain lettuce, tomatoes, cucumbers — and maybe some walnuts when we felt fancy. This is not to say we don’t eat veggies, just that we never could make a salad that could stand up as a meal on its own.


Food is no longer just a means of survival; it is a way to celebrate culture, tradition, and creativity. Recipes are passed down generations, some relentlessly refined, others persistently preserved. New recipes are always being developed and even the definition of what constitutes a meal is always evolving (although not always for the better).

How did we get restaurants that specialized in salads? One possible explanation is that entrepreneurs experiment with new ideas and see whether it sticks. Salad bars weren’t a thing until only a few decades ago which mainly catered to the health-conscious population. Recently there has been a surge in supposedly healthy foods (remember the kale superfood?) but in a way, whether these foods are healthy or not isn’t important. Instead, the fact that people are making a conscious effort of trying to live a healthy lifestyle means they are more likely to pay attention all aspects of their life1. This trend has allowed more restaurants to offer their own take on the salad bar concept.

Specialization also occurs in companies. Early-stage startups must be competitive with only a handful of people. Co-founders often split the work with one focusing on business development while the other in technology. As the company grows, new employees are hired to further specialize in each area: salespeople, marketeers, mobile engineers, data scientists, etc. These new hires are more knowledgeable, experienced, and efficient at their specialization. Working together, they can build products that the same number of generalists cannot.

T-shaped person

I first heard about this term a few years ago at Joist as a way to describe the depth and breadth of knowledge that someone has (vertical and horizontal lines of a T respectively). Here’s one description: being a domain expert (depth) means you can teach a whole university course, whereas having a lot of foundational knowledge (breadth) is like being able to give a hundred 5-min lightning talks.

You might be wondering "Shouldn't the foundation be at the bottom?". Welling Falsum⊥Shaped Person doesn't sound as good, now does it?

It can be satisfying to be the domain expert as there’s a feeling of accomplishment and mastery. However being knowledgeable in a variety of areas makes it easier to communicate with others and can make it easier to grasp new concepts by relating to previous knowledge.

This article does a good job of explaining how the t-shaped concept is applied to teams. However, understanding our own self and determining the best way to improve can be challenging. We are all constrained by time and energy when deciding where to focus. One helpful tip is to only concentrate studying topics of personal interest because curiosity and passion is what keeps us going through challenges. On the other hand, trying new things, even just briefly, helps broaden your view. This might sound like a lot of commitment but remember, breadth of knowledge can be just dipping your toe in the water - at least now you know whether or not it is for you.

All of this is just to say that the base for a good salad starts with lots of greens, but it’s crucial to have a good mix of additional toppings for colour, texture, flavour, pizaz.


1 ↩ And now we can get special blue-tinted glasses because we look at our screens too much because we are so focused on specialization.

Special thanks to Jonathan Truong, Sneha Patel for reading previous drafts and providing feedback.

Sunsetting Pronto Checker - What's Next and Lessons Learned

  • Apps
  • Indie
  • iOS

What this means for existing customers

I’ve released an update for Pronto Checker today which is likely the last. Just to be clear, the app will continue to work with this update. However because the app makes assumptions on how the PRESTO website is structured, the ability to check and refresh balance might not work in the future. Currently it still works and hopefully it continues to.

The reason for this decision was not made lightly. It’s been a while since the last update which was only necessary because of a major change on how the PRESTO website functions. Each time it changes requires a significant amount of time to update the app to continue working. Unfortunately there is no longer enough time for me to maintain the app anymore should another change occur, so I am letting everyone know in advance should another major change occur. In the meantime I’ve decided to make it free to download because I believe it is still useful to some people.


I’ve also taken this as an opportunity to discuss a few details about the development of the app for those interested. I’ve found behind-the-scene posts by other indie developers to be insightful and I hope this post provides interesting content as well. So beware! The rest of this post will be a lot more technical.

In-depth look behind the scenes

The PRESTO card supports the largest transit system in Canada, with over two million cards and a million taps every weekday. I’m a big supporter of public transit but my biggest annoyance was checking to see if I needed to reload money onto my card. I still remember talking to my coworkers whether creating such a single-purpose app was worth pursuing. Although it brings a lot of convenience to those who specifically face this problem, it certainly was a niche market (this would be an iPhone-only app, users can use the first-party website instead, auto-loading with credit card even removes the need for such an app). Nevertheless I had already hacked together a scraper so I thought how much more work can it be?

Screenshots of the current Pronto Checker app


I knew I had to build some kind of scraper because unfortunately there is no public PRESTO api, not even a private one from what I could tell. There were two main ways of doing so: I could either regex parse the html page myself, or let the browser do it for me.

I chose the latter option because most programmers are lazy (plus a few other reasons, of course). This turned out to be a good choice because the process of checking a balance is split into two network requests: login and fetch card summary. To complicate things, I discovered that the webpages included some dynamic session token which meant that the app always had to query the homepage to get a fresh set of tokens just to login1.

Once I got back the HTML containing the card balance, the tricky part was parsing out the balance. This was done by injecting JavaScript into the page, finding the right DOM elements, and relaying that data through WebKit message handlers. (Good thing I’m not using UIWebview anymore :)

Here’s a few other tidbits:

  • An optimization I added was to use WKUserContentController (on iOS 11 and later) to prevent the browser from retrieving unnecessary content, thus reducing bandwidth usage and achieve faster page loading times.
  • Since a user might have multiple accounts the app must be careful to use an ephemeral web session to clear cookies between logins.
  • I was curious what I could add to make the app easier to use. I experimented with adding OCR so users don’t need to enter the 17 digits by hand. After adding some simple optimizations and being smart about the formatting of the card I got it working fairly reliably. The irony was that in early 2016 PRESTO redesigned their card slightly so that the card number was grouped together into four blocks (previously it was one contiguous string) which made the OCR less reliable.


All of this is done on the users device for several reasons. I did not want to store any of the information on a server because that would be a lot of onus on me to keep everything secure. It also meant a central point of failure in that all PRESTO would have to do to prevent this from working (if they wanted) was to block my ip2. The downside is that I would have to update the app should the PRESTO website change its structure, but I thought it was worth this trade off.

An important aspect of building reliable software is to be able to monitor it. The app anonymously reports when a user is unable to login, as well as other analytics to get insight. I chose not to use a third-party analytics library/service because it was overkill for what I needed. I didn’t want to bring along a blob of binary3 which I had no idea what else it might be collecting.

The way I sent my analytics was very straightforward. The app generates an anonymous unique id on first launch, then sends GET requests that includes the relevant information as part of the URL. I simply log those requests to a file and take a look every so often. Although there’s no fancy GUI, there just wasn’t much need.

Obviously this solution is too simple for the majority of use cases and it takes a lot of work to build additional features and scale out. However one thing I would point out is that there’s probably only a few key statistics that really matter in the initial growth stage. It’s important to identify and focus on surfacing that information to stakeholders in the easiest way possible.


One other technology that I would say is crucial to have once the basic features are completed is the ability to present service status information to user (eg. system downtime or app version out of date). This could be a simple popup or just presenting a webpage. Having such a system in place allows one to prepare for the unexpected.

Recent popup from iTunes Connect app

Code quality

I’ve been working on this project for a bit more than two and a half years and the cadence of work was very different from other projects I’ve worked on in the past. I mostly worked in short bursts where I focused on shipping a fix or adding a new feature, then left the project for several months. This provided for a few interesting observations.

Commit history for Nov 15, 2015 – Jul 7, 2018

The first time I jumped back into the project it took me a while to figure out how everything worked, almost as if I was reading someone else’s code. A bit of this was due to the gap in time, but a lot was also my relative lack of experience of software engineering back then.

This app is a prime example of basic separation of concerns, for example breaking the app into 1) core balance checker, 2) model/persistence of the balance, 3) UI to display balance. Thus I took the chance in my first rewrite to clearly mark the boundaries of each section of the app. I defined new structs to make it more explicit about how different sections of the app could interact with each other, and tried to anticipate properties I would need in the future. A related problem I had to consider was the compatibility of the persistence layer between versions.

There was a benefit, however, to working on the app every couple of months. It was easier to identify the improvement of my ability to write quality code because in each subsequent reread I could always find places where I now had a better solution or way of organizing the code. It can be exhilarating to be able to rewrite some code in a way that avoids a hidden problem that my past self did not anticipate. However there’s also been a few times where I was pleasantly surprised that I had already handled a few special cases when rereading code. It’s also an interesting experience to see the progression of the Swift language. I started working on the app initially in Swift 1.2 and went through several migrations (remember 2.0?), seeing the language mature and get better over time.

Pricing, marketing, promotions

OK now onto the businessy side of things. Back then I listened to a few podcasts and followed indie developers who made their living by selling software. Creating apps is comparable to an investment (time is money right?). I thought it was a good opportunity to start with something small and build out a variety of different apps to provide a diversified income.

The feature I was bringing with this app is convenience and ease of use, which I hoped was enough of a reason for this to be a paid app. It would also be a lot easier to lower the price of an app than increase it4. And if I’m being honest, I would personally consider it a lot more impressive if I saw a steady stream of paid downloads with good reviews because this directly proves that people find it useful.

Initially after the launch I gave Google Adwords a try because I was curious what kinds of results I could get. I tried a variety of keywords, tweaking the landing page or linking directly to the App Store, etc. However I believe (it’s been a while) that I was barely breaking even because the CTR was pretty low. It was also more work than value when it came to testing different variations. I found it really draining to keep track of each hypothesis between testing (since it took time to see the results), or trying different layouts.

I also tried reaching out to press but didn’t get much response back. Thinking back there were several factors. Since this was a very niche app it’s hard to find the right customers when going to reporters, and reporters know this so it’s not worth their time. Furthermore, even if a person wants an app that can do this, there’s a high barrier due to the paid pricing. Realizing this, I tried making the app free in conjunction to cold-emailing. Eventually I got a link on the iPhoneinCanada blog.

Asking for reviews

When iOS 10.3 introduced an in-app review dialogue I knew immediately I wanted to add it in. At the time I didn’t have too many many reviews, which can be especially helpful to paid apps. This was in part because I didn’t add any invasive popovers because I wanted to create a pleasant experience for users. (Yet even if I did, I doubt the click-through rates would be high. The old process of leaving a review on the App Store was just too much to ask of users.)

There was a lot of small subtleties that I added to try to reduce user disruption and gain the best result. First the user must have successfully checked their balance a few times among several days. Satisfying this, the app then waits a few seconds after the next successful refresh so that the user can see their balance before they get prompted. This reduces the disturbance and hopefully results in the best possible result. Users will only see this popup at most once per version. Furthermore, the App Store now allows developers to keep the previous reviews after releasing new updates, reducing the need to continue showing these dialogues.

Process of sun setting

This brings us to the final topic of sun setting an app. I have a few vague memories of other apps doing this, but I’ve never really paid attention to the details of how other teams approached it. In my case however, the app will continue running as I am just giving everyone a heads up that no future app updates are planned.

I did debate if I should pull the app from the store. I didn’t want to continue selling it since I am no longer actively developing it. However at the same time I still see value in making it available to people. Thus I decided to make the app free to download instead.


Thanks for reading! If you have any feedback you can always reach me on Twitter.


1 ↩ the dynamic token requirement was added around july of 2016. Previously, without the requirement, I was able to include a cached version of the login page with the app, skipping the first request

2 ↩ if I was responsible for PRESTO website, seeing a single ip performing that many unique logins that would definitely be a red flag

3 ↩ the scariest libraries are those that don’t require any code since they hook directly into the dyld load process

4 ↩ unless your app is Sketch :)

Deciding Who to Vote for Is Hard - Here Are Some Suggestions

  • Elections

This upcoming June 7 is the Ontario elections (and you should vote). Yet I haven’t figured out how to see through the veil of optimistic hot air on each party’s website, speech, and interview. Party leaders give off this impression of “my party is always right” as a way to show strength and assure their voters that they made the right choice to support their party.

However in today’s fast-paced environment where the need to act on incomplete information invariably leads to mistakes no matter who is behind the ship. The critical test is actually how leaders react to new information and address the problems that do arise. It can take a certain level of courage and respect for the public to acknowledge the big failures. Moreover, governments should learn from previous mistakes and success to do even better in the future.

I am reminded by two shows that I’ve been watching recently, Salvation and Lost in Space (no spoilers here). There’s quite a few themes in common with what leaders face today: Lack/asymmetry of information, bad communication, and deadlines (how anything in life gets done). For example in Salvation, if the asteroid hits earth, who gets to choose what course of action to take? Everyone is impacted in varying ways depending on the action taken. Or, for Lost in Space, whether someone should risk their own life to save another’s? To save all the remaining survivors? Each decision will arrive at a different conclusion and so careful consideration must be given (unless you live in Edeard‘s world where everyone reaches enlightenment, although technically, this too has side effects on the normal world).

Ultimately, the point of an election is deciding the leaders who will bear the burden of making these difficult trade-offs. With the great power of democracy, it is thus each citizen’s duty to cast their vote. However this can be challenging since it requires each citizen to perform their own research and due diligence.

Even though we say technology makes the world so much more convenient to live in, there’s only so little time in the day. Think of the people who work two jobs just to get by: The fact that they have two jobs means that it’s highly unlikely they can afford to splurge on technology. How can they then possibly have the time and access to information to learn more about each candidate? At this point, it’s more likely that which ever candidate can do their best to appeal to emotions, or which ever is the most relatable, is the candidate that will score a tick beside their name. And that might not be the best choice.

This might sound extreme but according to one government report, 30.4% of Ontario workers are vulnerable (income is less than half of the median income). This was more than I expected. Another report shows that younger voters (mainly 18-24) are among the least likely to vote. Thus it makes sense to make information more accessible to everyone.


For me there’s two main signals I look for in candidates, both of which I think are equally important. The way the leader handles interviews and debates gives me a sense of their values and long-term direction. On the other hand, the policies provide the details of how they will turn their long-term vision into reality. I tried to think of suggestions that would make it easier to identify and analyze candidates based on these two signals.

Better access to information

One thing I hate about debates is that every topic is discussed at such a high-level that there’s no easy way of determining who’s right. When candidates do pull out a fact, I wonder how much weight actually holds. Thus there should be an easy way for citizens to have access to objective data regarding each major issue so that they can make a decision for themselves. This is a challenging problem due to the massive amount of data to be gathered, fact-checked, and organized. Some data is not even publicly available.

News websites should provide more in-text citations so that readers can read the original source for more information if they wanted to. Governments should publish more details about the projects that are currently ongoing. Most importantly, governments should make it easier for people to find what they are looking for by improving search and creating a unified website where all government reports can be found.

A better debate format

Whenever a controversy (or bragging point) is presented, the other side will interrupt to disagree, which puts an immediate roadblock on the conversation. (Just look at the skirmishes between Ford and Horwath). Instead, what if debates occurred one-on-one? Two candidates, along with a moderator, can discuss a variety of issues, how their policy will solve that issue, and pose questions for each other. This allows room for the conversation to get into more details, and puts the focus on just the two parties.

Standardized policies

A standardization of how policies are presented would allow citizens to easily compare the policies of each party. Some mandatory items include policy name, amount of money, where funds come from or are going to. Policies should have a short title, followed by detailed explanation of a) why this policy is important, b) who/how many people will be affected by it, c) how will it improve these peoples’ lives, d) what are the side-effects of this policy. There should be an easy way to search by each property (as mentioned above) of the policy. A further enhancement would be a way to show competing policies from each party regarding the same issue. This could be a table to highlight the similarities and differences of how each party plans to address the issue.

Accountability and continued improvement

Once elected, it is key to have party leaders accountable whenever they make a promise. Thus, these policies should be archived once a premier has been elected. Furthermore, there should be some way for the premier to provide status updates on each of the policies outlined in their campaign. However, verification of the effectiveness after the policy has been implemented is a hard problem. Leaders also need to address what processes they have in place to deal with contingencies and how they plan on conducting retrospectives at the end of every project in order to learn and improve.


Elections are one of the foundations of a democratic system. In some ways it is actually good that it takes time to change because this allows for the community to voice their opinions and fully analyze new ideas to ensure the trajectory is on a positive slope. The important aspect is that citizens are persistent to make continued progress. Elections happen every few years, which provides a good opportunity to evaluate the progress made. Let’s schedule a retrospective in four years.

Special thanks to Bryan Qiu, Jonathan Truong, Mary Hu, Matthew Yoon, Sneha Patel for reading previous drafts and providing feedback.