During the course of this article you will be presented with three different offline patterns. These are commonly used to create working offline scenarios for mobile applications. The first pattern will take the naive approach of porting an existing application to mobile as-is. The second one will be focused around caching in order to make the application more responsive. The final one is centered around selectiveness to create a personalized offline experience. Before diving into the patterns, we'll go over some of the reasons about why it's important that mobile applications remain functional when lacking network connectivity. We will also see why it's important to think about this topic. Keep in mind that everything mentioned here is not specific to a particular operating system.
Why Offline Matters
Your end users want to be a able to work offline for a myriad of reasons. Some examples are:
Lack of connectivity (e.g. in the subway) or no data plan.
Limited amount of bandwidth.
Slow and/or unstable mobile network.
Step back a couple of years and look at a typical business meeting. You will probably notice the prominent presence of paper reports with business metrics. In a sense this has been completely displaced with technology. Now during that same meeting, attendees can look at real-time data of the business. Paper was replaced with projectors, personal computers, and mobile devices (tablets and smartphones). In a similar vein, faxing things like expense reports have also been replaced by applications that send images of receipts to a server. When creating a mobile experience, it's important to solve the real business need instead of adapting the old process to mobile. For example, the problem is not that you can't print or send faxes with a tablet. The problem is that you need to re-evaluate what the mobile experience should be.
The most successful companies at providing great user experiences seem to have at least one thing in common. They did not just port their existing desktop or web application to mobile devices. They re-imagined the experience, taking into account the new form factors and the resource constraints found in these new devices. Part of this is the philosophy behind the "Mobile First" banner. You start by assuming limited screen real state, weak processors, unreliable connectivity, and limited amounts of memory. Market disruptors have thought long and hard about their key features and how to expose them in a mobile environment first. Then they can take it to more traditional systems if required. This allows them to gain market share and further enhance the experience.
Imagine you already have an existing desktop or web application and want to create a mobile application. Maybe the desktop application has a local embedded database that's used to query data at run time. The web application connects to a backend and queries data from one or more database servers. In both cases the database holding data is running on a relatively powerful system. Keep in mind there's always the tradeoff between memory access (fast) and disk or network access (slow). The first one is quite limited while the latter is more abundant.
First (Anti) Pattern: Load Everything
The first pattern we will discuss is the Load Everything pattern. At some point, generally after the user has authenticated, an application loads all the data the user will ever need to use. While this is happening we typically present some sort of busy indicator (spinner animation). Once done, when the user interacts with the application, he or she will most likely interact with the data that is stored locally.
I call this an anti-pattern (something to avoid), because it has the following drawbacks:
The initial download may be slow due to the scope of the data. Remember some users may start the application while on a slow and/or unstable network.
The process of loading and querying data may be slow. Remember that in general mobile devices are nowhere near as powerful as servers and personal computers.
First impressions matter. Telling your typical mobile user, who is likely impatient and easily distracted, to wait more than a couple of seconds is far from ideal.
Lack of scalability. As the data set grows, your application's performance may go down.
Second Pattern: Caching
The second pattern, caching, generally requests data from the server, but cached so it loads quickly if the user needs to access that data again.
Good examples for this are the many e-mail applications that are downloadable, or come pre-installed with the various mobile operating systems. Instead of loading a considerable amount of mail data, only the last 50 or so e-mails are loaded. Then those are cached, so when the user opens them again, they load quickly. The offline case is partially handled as long as you access one of the cached emails.
Other examples include applications that show map data. In this case as the user uses the application, map tiles are cached up to a certain number of bytes. The offline case is also handled as long as the map data required is in the cache.
Music player applications that get songs from the cloud are another example. Generally songs are cached once the user listens to them. This is because it's likely he or she will listen to a song more than once. This is yet another application that can be used offline as long as the user only listens to songs inside the cache when lacking network connectivity.
Caching typically involves two things: cache invalidation and keeping the cache up to date. Cache invalidation is the process in which data inside the cache is removed because it's not valid anymore. There's a plethora of documentation and algorithms about this that are beyond the scope of this article. A simple approach can be that data is always requested from the cache. At the same time when connected to the network, a separate thread is used to request the same resource from the backend and update the cache.
With regards to keeping the cache current, techniques such as iOS's background refresh and Android's services can be used to keep data up to date. Imagine a newspaper application in which the user subscribes to news categories (e.g. technology, finance). When the user is connected a background thread updates the cache, so the latest news articles are available even when there's no network connectivity. The same concept applies to RSS readers, social network feeds, and many others.
Third Pattern: Selectiveness
Data is generally requested from the server. It may also be cached following the second pattern described above. However, with the third pattern, selectiveness, the user is given control over the content he or she wants available offline.
Going back to the e-mail application, imagine a way to make certain e-mails or groups of e-mails available when there's no internet connectivity. The type of messages that you will likely want offline could contain content such as confirmation or ticket numbers; anything that contains information that will be useful beyond the current location. An airline ticket confirmation number is not useful at the current location (e.g. home, work), but it is useful when at the airport. Imagine we used the first pattern and loaded everything for offline use (e.g. junk/spam, messages from co-workers with funny pictures). Most of the data we're loading may not have a clear offline use case. We force the user to wait while everything is being downloaded. On top of that our application will likely be a lot slower. For example, instead of working offline with 100 messages, the application now needs to manage 1000 times that amount with the same limited resources.
Back to the Map application, now imagine the user is given an option to select an area of the map he or she wants available for offline use. The map may be a new city he or she will be visiting in the near future or a city of the country and thus out of the scope of the user's mobile carrier. Instead of downloading and storing all possible map data on the user’s device just to enable the offline scenario (First Pattern: Load Everything), the user can now choose which map sections he or she needs for offline use.
The music application mentioned during the second pattern can also be enhanced. One way to would be by having the user select some playlists or songs that will be available for offline use. That way the user doesn't have to depend on the cache when offline. It's also clear in the user's mind that he or she will have to wait for those songs to be downloaded. The user also realizes that having songs stored on the device will use more disk space than getting them from a server. In other words, the user recognizes that there is a trade off between disk space and bandwidth use.
Real World Examples
Take a look at the images below, on the left side we see Google Maps being used to store a portion of its map data so it can it be used while lacking internet connectivity. Then we see the Spotify application on the right side being used to make a playlist available for offline use.
Throughout the article we learned why it's important to think about the offline experience and touched on some patterns popular applications are using. It's worth mentioning that the answer to everything specific will probably be "it depends". You may want to explore a combination of caching and selectiveness for your application or something completely different. The intent of this article is to spark ideas, not be a series of steps to follow. If you enjoyed this article, please feel free to leave a comment and share it via your favorite social media website.