Last week we took an in-depth look at why mobile app performance matters. The key takeaway is that great performance is an essential part of great mobile experiences. Today I’d like to focus on one specific, often neglected piece of the app performance puzzle: offline capability.
Most of today’s mobile applications treat offline as an error state. All functionality breaks; the app is essentially useless. This is true even for otherwise great apps by companies with massive amounts of resources at their disposal. And this poses a problem, because an app that doesn’t function offline provides a bad user experience in a fairly common situation. Yet most app developers ignore offline functionality, and punish users for a variable which is, in most cases, completely out of the users’ control.
For example, take Slack’s mobile app, which I absolutely love using when connected. If I am offline, the app will let me compose a message, warn me that I’m offline, and tell me that a message wasn’t sent. But if I reconnect, the message will still be waiting with an error:
Bank of America’s mobile banking app – again, usually a joy to use with a network connection – just bounces me out of the app entirely if it can’t connect to a network. I’d love to be able to access some basic account information, but I can’t even get to a login screen:
So why is it, then, that companies like these, with millions of dollars and dedicated mobile teams allocated to supporting mobile user experiences, can’t get offline right? Simple: it’s really hard to do.
In “The Offline Mobile Challenge,” Forrester Research claims that “offline support is the mobile app feature continually underscoped by developers and oversimplified by stakeholders,” and that “the pain (and associated cost) of developing and testing the various facets of offline service causes this mid-project de-scoping phenomenon.” Yet the value for the user cannot be understated: in addition to providing offline functionality, a local cache supports sub-second app performance, since the frontend can display local data instead of having to query a remote database or file server.
3 different approaches to offline capability
One of the contributing factors to offline’s complexity is that there is no standard way to implement it. Different use cases call for different approaches, ranging from fairly simple to incredibly nuanced. Let’s take a look at what these are:
The easiest solution to the offline challenge is to simply create a read-only cache on the client device. This allows users to access content while offline, and the app can check in on the backend when it is connected to ensure all data is up to date.
I’m actually surprised how infrequently I see this implemented. It would be a perfect solution to my problem with the Bank of America app I pointed out above. Similarly, a sales enablement app that allows a salesperson to access pricing models, product catalogues, and other supplemental information on the road and in the absence of a network connection would be a great use case for this offline model.
The limitation, of course, is the read-only bit. While relatively simple to design and build, a read-only offline model only works if you’re delivering static content. It can’t support more complex use cases where users manipulate data on the client side – for that, you need a more robust architecture with sync capabilities.
Last write wins
In use cases where users need to be able to perform the full set of client-side CRUD (create, read, update, delete) operations, the simplest sync policy is “last write wins,” whereby the most recent update to data ultimately becomes the master record. This allows a user to make updates to data on the client while offline, and those changes get pushed to the backend once a network connection is reestablished.
This approach is well-suited for use cases with a low frequency of concurrent updates, or when changes come from a small set of predictable endpoints. Slack could benefit from this offline capability, for example, allowing my most recent sent messages to sync with the backend once my network connection is restored. And a Kinvey customer has actually launched an eDetailing app with this functionality, allowing sales reps to indicate that they had provided FDA-mandated information to clients while deep inside hospitals where network connections can’t be guaranteed.
The catch with last write wins is that it lacks any conflict resolution policies when making writes. If the use case requires that the application can prioritize concurrent writes based on a given set of criteria, last write wins will fall short.
Policy-based conflict resolution
This is the most comprehensive approach to offline cachning and sync, and predictably the most complex. An organization-defined set of rules determines through business logic which endpoints have write priority in certain cases; these rules can be as complex as required to support any use case.
This approach is required for omnichannel apps where data is manipulated from a large number of endpoints, and for just about any application that deals with physical goods. A field sales order placement app, for example, wouldn’t operate effectively with a last-write-wins sync system – if there are inventory changes or pricing updates while the salesperson’s app is offline, you would need a complex, custom approach to conflict resolution to ensure orders can be placed and the right people can be notified of any changes.
The drawback with policy-based conflict resolution for offline capability is simply the time and cost associated with creating it.
The auth problem
Authorization is a major pitfall in offline capability, often realized too late in the development process to fix. If your app accesses sensitive business data, it will inevitably connect to an enterprise authentication source. But those sources assume network connectivity in order to handshake with the client and grant authentication. No matter how robust your caching architecture is, if you’re still using standard enterprise auth your app won’t work offline, period.
The solution is to treat in-app authentication in a similar manner as MDM vendors. Require an initial authorization, and then grant a user cache access for n hours before an authentication handshake is required again. This ensures a level of security adequate for most use-cases without crippling offline capability.
Tying it all together
As I’ve said many times in this post, creating robust and functional offline caching and sync functionality is one of the most difficult pieces of app development. A quick GitHub search will net you myriad approaches to the problem, each one more nuanced and complex than the last. It is imperative that during your scope process you determine which of the three approaches best fit your needs and allocate resources accordingly.
Alternatively, you can turn to a managed service to do most of the heavy lifting for you. Kinvey’s client libraries allow you to add caching and sync to your app – with the specific policy tailored to your exact use case – with just a few lines of code: check out the dev center to learn more.