Proof of concept
Unless you’re building an app very similar to apps you already built, you will probably need to explore certain areas to get the data you need to make good decisions. A common mistake is to settle on a design or an architecture without verifying that it performs and scales as needed. Your requirements should specify the key scenarios for the app and the expected performance of these given specific volumes of input. You need to know ahead of time what kind of data loads you expect to see and make sure your app can handle these.
Building a prototype or a proof-of-concept app is a great way to try out various approaches and collect information on what works and what doesn’t work. You want to make sure the app can handle all the relevant key scenarios with the expected performance before you settle on a design and an architecture.
Some designers build prototypes to test usability issues as well. That’s a great idea, but typically these prototypes are not useful for measuring performance. Usability prototypes are often built around limited, hard-coded datasets, which provides enough functionality for the users to interact with the app. However, to properly assert performance, you need to use real data sources, and you need to test with data volumes that match your expected usage scenarios. Real data sources have latency that might affect the user experience. Similarly, most designs and algorithms work well as long as the input is limited. If you want your app to be able to handle specific quantities of input, your prototype must verify that your design and architecture are capable of doing so.
The time you spend up front verifying your assumptions about the design and architecture is a good investment. Any shortcomings you can spot at this stage can be addressed, and the cost of doing so is far less than it will be if you have to fix those problems at a later stage.
In the remainder of this chapter, I go through a number of common app scenarios, look at the design challenges they present, and provide guidelines on how to address these. The scenarios are
- Live content
- Handling a lot of content
- Handling media
Getting these scenarios to perform well can be a challenge, but if you think about the performance during the design, you can address the biggest issues at this stage. You might still have to tune the implementation later, but getting the architecture right is paramount.
Many social apps, enterprise apps, and so forth need the user to log in before they show relevant content. If you’re building an app like that, realize that launching your app consists of the following phases:
- Show content
The launch part is really simple. Your app just needs to present itself to the user and offer a login experience. Obviously, the login screen should present the visual identity of the app, but other than that there’s really no reason to do any kind of work at this point. The login screen is simple, and consequently the launch experience should be simple and very fast. Yet, I have seen several apps that go through elaborate setup prior to displaying the login screen, which makes the launch experience much longer than it needs to be. There are really no good reasons that this shouldn’t be fast.
Once the login screen shows, the app will most likely sit idle for a while—possibly for a long time before the user enters her credentials. If your app needs to perform additional setup steps or fetch resources, this can run in the background as the app is waiting for the user to log in. Launching work at this point means the app can prepare resources while the user enters her credentials.
Authentication itself requires interaction with your app back end, and this interaction might involve a noticeable delay. If your app waits for authentication to complete before proceeding, this latency delays the login experience. While you obviously don’t want to present sensitive content to nonauthenticated users, the app can still do a lot of work while waiting for the authentication to complete.
If your app waits until the user is authenticated, you’re optimizing for the case where the login is unsuccessful. A better approach is to optimize for the case where login is successful. After all, this is the scenario your users care about and it is probably the most frequent scenario as well. Go ahead and do as much work and render as much of the UI as possible under the assumption that the login will succeed. This reduces or even eliminates the latency of the authentication. If the login doesn’t succeed as expected, you can implement a fallback to handle that. It is much less important to get the performance of the failed login scenario right, because fundamentally this scenario isn’t very valuable to the users.
Login is an interesting scenario because it includes a lot of time where the app is simply waiting. The key to optimizing the experience is using this delay to your advantage by doing as much as possible while the app is waiting.