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?
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.
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.
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.
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
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.
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.
I had a great time traveling around Iceland with friends for my grad trip during the end of April. Here’s rundown of our nine day itinerary - maybe you will find some interesting tidbits :)
- We used Blue Car Rental to book our cars. It bundles in gravel protection which is highly recommended. The wifi hotspot was also very convenient. A 4x4 vehicle is required on some rural (and F-roads) roads so plan ahead.
- We alternated cooking ourselves (which saved us some money) and dining at restaurants (which allowed us to taste the local cuisine)
- The major budget groceries stores are “Bónus” and “Nettó”. If you buy their sandwiches, definitely go for the salmon one! Also the chocolate tastes better in Iceland (but maybe it’s just a Europe thing).
- If eating out, try to find restaurants that serve fresh fish or lamb, as these are among the best foods in Iceland
- The road infrastructure was a lot better than I expected considering there are so many rural regions. Another challenge is that every year the rivers may shift, requiring new bridges to be constructed.
- We drove counter-clockwise around Iceland which aligned nicely with our itinerary in that the majority of our attractions were earlier in the trip when we had more energy
- Reykjavík, Iceland’s capital, is home to 126,000 out of 350,000 in all of Iceland. For comparison, it’s estimated that there’s over 800,000 sheep!
- Some of the Airbnb’s were very modern with expansive glass windows. I especially liked the bathrooms with doorless walk-in showers and stone tiling.
- Blue Lagoon: Geothermal spa with mud masks - be sure to book a few weeks ahead of time!
- Sægreifinn Restaurant: Small cozy restaurant offering variety of skewers and hearty soup
- Öxarárfoss Waterfall nice scenic hike
- Kerið Crater There wasn’t much vegetation when we went
- Gullfoss Waterfall Home of Iceland’s first environmentalist who prevented a hydroelectric dam from being built
- Geysir These geysers erupt every so often. Look closely and you can see a beautiful blue bulge of water before it erupts.
- Seljalandsfoss Waterfall The main attraction is a waterfall that you can walk behind, but there’s two hidden gems to discover if you continue walking North along the path to Gljúfrabúi, a hidden waterfall.
- Sudur Vik Restaurant Their apple pie with ice cream was delicious!
- Skógafoss Waterfall There are stairs that you can climb up. And the railing is made out of polished wood.
- Sólheimasandur Airplane Wreck Park here and walk to the wreck (about 7km round trip)
- Dyrhólaey Lighthouse This lighthouse was renovated to accomodate guests - not sure if it is still in service. Need an AWD to drive to the top.
- Sólheimajökull Glacier Guided tours are available
- Svartifoss Waterfall and Glacier The visitor center is pretty high tech: Just enter your license number (it even knows your vehicle model) when paying for parking. The (shorter) trail on the right takes you to the glacier, while the left takes you to several waterfalls.
- Fjallsárlón Glacier Small patches of clear ice scatter the lake, and boat tours available
- Pakkhús Restaurant Great decor and fresh food
- Weywadt House This was a unique house (especially for its time) because it was constructed out of tar, which gave it its contrasting colour
- Kirkjubær Church This church was renovated to accommodate guests!
- Grjótagjá Cave There’s a natural hot spring inside this cave
- Hverfjall Crater To be honest there wasn’t much to see at this stop. Luckily we had a few lateral thinking problems.
- Ásbyrgi Trails There’s a variety of trails (including a 2-day hike!). Best enjoyed on a sunny day and pack lots of water.
- Goðafoss Waterfall Known as “God’s Waterfall”, the myth says this was where lawspeaker Þorgeir Ljósvetningagoði declared Christianity as the new religion of Iceland by throwing the old statues of Norse Gods down the waterfall.
- Noa Restaurant This restaurant has a unique style of cooking fish and veggies together. Do you like the sauté or baked version better?
- Brynja Icecream A few swirls and is then dipped into chocolate
- Pylsuvagninn Hotdog Stand They have a crispy topping and makes for a great late night snack
- Hlíðarfjallsvegur Ski Resort Highest point in the town for viewing the Northern Lights
- Sundlaugin Outdoor Swimming Pool with mountains in the distance
- (Lots of driving today)
- Sjávarpakkhúsið Restaurant Relatively small restaurant known for it’s pot of mussels
- Ölkelduvatn Mineral Spring We got to taste some fizzy mineral water
- Londrangar Lookout View a pair of towering rocks and powerful waves from atop a cliff
- Gestastofa Visitor Center Get more information about the Snaefellsjoekull National Park.
- Djúpalónssandur Beach Known as Black Pebble Beach for the smooth rocks. Parts of the shipwrecked fishing trawler Epine have washed up here and still remain today. There’s also Lifting Stones to test your strength!
- Saxhólar Crater I found this cool aerial shot of the crater
- Skarðsvík Beach Also known as the White Sand Beach
- Kaffivagninn Cafe This place was packed when we went in the morning. They also served salmon for breakfast - why not?
- Hallgrimskirkja Church Iceland’s largest and arguably most iconic church.
Plastic egg cartons provides better protection than cardboard, and since they are so strong, why not reuse them so we don’t have to keep making more?
A couple of years ago Costco introduced plastic egg cartons, which are stronger and prevented yolk from broken eggs from contaminating the cartons below. While these are made from 100% recycled plastic (props to them), I still feel guilty about how much energy went into the manufacturing of the plastic. They are also surprisingly bulky, taking up more space in recycling bins than should given their weight. Furthermore it requires still more energy to recycle these cartons again; Why not just reuse the cartons instead?
Consumers can drop off old plastic cartons and these can be densely packed and shipped - in the same truck that carried the eggs to Costco - already returning back to the packaging facility. Cleaning and inspection of these cartons are definitely required, but this should be less resource-intensive compared to both manufacturing completely new cartons, as well as to recycle the old cartons.
Costco can benefit in several ways by doing this. Reusing these cartons means they don’t need to manufacture as many new ones. They can either pass these savings to consumers (albeit probably only a few cents), and create a marketing campaign to spread awareness about reusing and recycling plastics.
One drawback is the slight inconvenience that this brings to customers. However, Costco customers almost always drive a car, so they can easily store old cartons in their trunk. The cartons are light and don’t take up too much space so one can even drop these off every other week when they do their shopping.
Another necessary change is that reused cartons need to have an updated expiry date on the container. This can be solved by using stickers instead of etching the expiry date on the side; The cleaning process will get rid of any gunk and old stickers.
Nonetheless the biggest challenge I see is for someone with authority to get behind this project since it involves changing Costco’s distribution logistics, potential legal considerations about reusing customer-provided cartons, and working with other vendors to clean and inspect the reused packaging. However, if Costco is able to put this into practice then I think this represents a significant step in companies recognizing the importance of finding ways to reduce their environmental impact. Other stores, such as UK’s Tesco (they sell 1.3 billion eggs yearly!), have also adopted plastic cartons for several years already, so other stores can benefit from a trial run. Let’s start with eggs and see what this grows into!
This post is about my recent experiences using wireless charging and AirPods, and thoughts about future interaction models.
My iPhone 7 battery life has been on the decline for the last few months. Although the physical hardware is aging, there’s a few other factors at play too. I noticed that I was using my phone more for emails and browsing, as well as for listening to podcasts over bluetooth. It is also the winter season at Waterloo, which has a small impact when I use my phone outside. On occasion I’ve charged my phone with a 12W iPad charger, but now I try to avoid it since it is bad for most phone batteries since they have less capacity. Remembering to plug in my phone in the afternoon is not something I want to constantly think about.
Instead, I got a wireless charger and a wireless adapter for my phone. If you previously asked me to estimate the increase of convenience and comfort of wireless chargers I would probably have predicted it would be negligible. (How hard is plugging and unplugging a cable???)
Yet once I started using the wireless charger there was no going back1. There’s no need to aim the connector to align with the port, even though it’s second-nature already; the unconscious effort of making sure the cable doesn’t knock over objects is eliminated; walking out the door with my phone is instantaneous.
Now, whenever I sit down at my desk, I just drop my phone on the charger so it is always charging. All this might seem like a tiny increase in convenience, but I wouldn’t be surprised if by doing this that most people wouldn’t need to worry about battery life anymore.
AirPods are great. The most obvious benefit is, of course, the lack of wires. I’ve always wrapped my earphones “over-under” method which reduces the tension on the wires. Nonetheless I found that as wires age, they get tangled more easily, which is why I usually carry with me my (relatively) new lightning EarPods.
I’ll admit I have a pretty unusual use case: Although the majority of the time I would listen on my phone, the problem was I would switch to my computer to do meetings every week. This meant I had to dig out my old 3.5mm with adapter earbuds, which I always keep with me in my bag.
Now I could’ve solved this by getting any pair of bluetooth earbuds but buying the AirPods was so much easier: I didn’t have to do any comparison of detailed tech specs. Furthermore when it comes to tech gadgets, I think that having a deep integration within an ecosystem is the biggest selling feature, which in this case meant it was easier to switch between devices. And of course, the charging case is elegantly designed and makes a wonderful snap sound as it closes. It’s the little details that matter.
I’ve heard many people worry about how easy it seams to lose them, but in most cases there isn’t much to fear - for one, audio playback automatically pauses (except phone calls) if one AirPod falls out. The only rule is to make sure each AirPod is either in your ear or in the case.
I do have to mention a few nitpick details because as good as any product is, there can always be improvements. Hopefully these issues can be addressed in a future update.
- When I first used AirPods I didn’t have as good of an understanding on how switching between devices work. I thought that because it was already linked to my iCloud account that if I play music from my phone, then play from my computer, then the AirPods would automatically do so too. Eventually I realized that I had to explicitly switch the audio source 2.
- I would like to have the ability to switch audio source when the charging case gets opened right beside that device, saving the user from 3D-touching into the audio settings.
- When an audio source does get switched, sometimes it takes just a tad longer than what seems like it should take.
- Sometimes there is a buzzing sound when there is no sound being played, which is especially noticeable when scrolling through video because it seems to prime the audio driver (even though no sound is being played yet).
It all comes together
Improvements in hardware is often the driving force behind device upgrades because customers want the newest features. However, the existing hardware we have today is already very capable. Suppose a consumer wants to see a 15% improvement before they upgrade their phone. However a 15% improvement from an iPhone X might be equivalent to several model jumps back in say the iPhone 4 days. It is a much higher bar today.
Yet another approach of developing new features is to support a different paradigm of interactions. Two obvious examples we see today are voice assistants and virtual reality. No doubt hardware plays a critical role, but the importance of software and integration in an ecosystem also cannot be understated for these paradigms. Both use personal and public data, coupled with the current context, to provide and act upon requests by the user. The hardest part is achieving a near-perfect accuracy and responding fast enough to overcome the habit of how users currently accomplish their tasks today.
The overall theme over the past two years is the trend towards all things wireless, and that’s something I would like to see and hear taken to a whole new level in the upcoming years. Let’s go build a wireless connected world!
2 ↩ Thinking back, of course this is necessary because it’s not possible for computers to fully read our thoughts (yet)