The Right and Wrong Strategies When Taking Your App Offline
Monday, February 9, 2015
Once there was an elevator inspector. Into an elevator shaft he climbed with his tablet, taking pictures and making notes. Twenty minutes later, he climbed down, went into the hall, and his tablet got service. His inspection app immediately tried to synchronize his notes and pictures with his company’s inspection database.
After a couple of minutes, he saw an error box: Elevator ID does not match building name
When he pressed the OK button, he was presented with a blank form. His entire inspection form had been discarded.
What had happened? Multiple errors. When he downloaded the elevator data at work before leaving for his inspections, the building had been listed as “Bahnad.” After he went on the road, a sharp-eyed office worker had corrected the database to “Barnard,” the building’s actual name, rather than the way the building owner with the South Boston accent had called it into the inspection company.
When he exited the elevator shaft and his tablet got service, the building name on his tablet no longer matched the building name in the database at work. Unfortunately, the programmers who had created the inspection app had coded their conflict resolution tactic as “server wins.” Equally unfortunately, the coded action after a conflict was to download the whole “correct” record from the server, overwriting twenty minutes of careful fieldwork from the tablet.
In the words of the army training film, “Men, don’t let this happen to you!”
What Else Could go Wrong?
One of the hallmarks of good programming is anticipating everything that could possibly go wrong, and handling it in a graceful way. We’ve just described a case where the server data was changed while the mobile client was disconnected. What are some other cases we need to handle?
Let’s see: The tablet could have rebooted at any time, or run out of battery power. If it were a phone, it might have rung at any time, causing the user to switch away from the data entry application. And the server could reboot at any time. We could go on, of course. But let’s think about right and wrong ways to design a mobile application for these cases.
Right and Wrong Offline Strategies
As we saw earlier, “server wins” can be a bad strategy for data conflict resolution in an intermittently connected app. “Client wins” and “last update wins” can also be bad strategies, especially on a smart phone with a small software keyboard and an aggressive auto-correction algorithm. After all, “actions speak louder than wombats.” You really don’t want mobile typos to get into your server database – that’s one of the reasons that the database client detects conflicts in the first place. All that’s left after we’ve ruled out the easy conflict resolution strategies are “let the user decide” and “write a custom algorithm.” We’ll talk about both of these a little later on.
What about the case of a mobile device reboot? Potentially, this can cause the user to lose all of his or her work if it happens while the data only resides on the mobile device. You can remediate this by persisting the data on the device as it is entered, and reloading it when the app restarts. For a mobile web app, you can use HTML5 Local Storage; for a native or hybrid mobile app, you can use the SQLite database on the device. The mobile device reboot can also lose a web app’s state, unless you program a web app to use state caching, or turn the web app into a hybrid app with a wrapper such as PhoneGap.
When a device battery dies, the situation is essentially the same as a device reboot, as far as the software is concerned. Of course, the user has to take the extra step of plugging the device into power to get to the point of rebooting.
When a mobile phone rings, the focus switches to the phone app. If data entry was going on using a web app without data persistence and state caching, all the data will be lost along with the web app’s state. This isn’t a problem with a native or hybrid app.
When a server reboots, a number of mobile application errors become possible, depending on the type of server and the state of the mobile application. If the mobile app is not actively trying to use the server when the server reboots, and is programmed to recover from an invalid session with the server, then no harm is done. On the other hand, if the server crashes and/or reboots after the mobile app has transmitted its data but before the server has committed the data to permanent storage, there is a potential for data loss unless the mobile app has been programmed to be pessimistic about the data commit.
We mentioned earlier that we’d discuss data update collisions at greater length. We’ll start by describing two possible collision resolution tactics.
Conflict Resolution Strategies
We said that the two viable strategies for resolving data collisions are “let the user decide” and “write a custom algorithm.” Let’s see what these entail.
Let the user decide
In an ideal world, in the event of a data collision, a mobile app and its back end would, between them, know what data to keep. In the real world, that isn’t always going to happen, and the decision needs to be left up to human beings, who are capable of applying judgment and information not available to the computer.
The general idea of this tactic is that the app presents the user with a form containing all the relevant information, including both conflicting values for fields in question. Then the user should be able to pick the correct value, apply additional edits, and save all the data.
The challenges here are to present the choices in an understandable way on a mobile device with limited screen space, and to walk the fine line between empowering the user and allowing any mistakes the user makes on a mobile device to propagate into the server database.
Write a custom algorithm
Sometimes, however, the mobile app and its back end do know what data to keep, given a few business rules. These rules are likely to change from business to business and app to app, but one way to think of them is in terms of role-based permissions. For example, the ID field for a company may have been assigned at the home office, and there could be a rule that says that it can’t be changed from the field. On the other hand, in our elevator inspection case, any direct observations made by the inspector should probably override data entries from the office; for example, the office staff may have marked the elevator as being made by Otis, but if the inspector reads the identity plate and it says Hitachi, then Hitachi it is.
Even a well-thought out set of business rules could run into problems in some unforeseen cases. It’s probably a good idea to combine the custom conflict resolution algorithm with some human oversight – and a good audit trail.
Technologies Underlying Data Conflict Resolution
How might one implement such a process? There are many possibilities, but the two major ways of supporting the problem are maintaining a replica of the database system on the mobile device, and tracking all the intended database operations locally and applying them later.
Local database synchronization
Running a replica of the server database on a mobile device might seem like a simple solution. In principle, it is: the developer will never have to think about synchronizing the mobile and server databases, as that is handled by the database software.
In practice, however, the off-the-shelf synchronization software does not always do the right thing. Unless the software provides hooks that allow you to fix the cases that don’t work correctly, and few if any do, then you wind up with an unsatisfactory result.
In contrast, tracking all the intended database operations locally and applying them to the server later sounds complicated in theory, but in practice gives you more control than local database synchronization. Unless your platform takes care of the CRUD (create/retrieve/update/delete) tracking and the UI generation for user resolution of data conflicts – and in a moment we’ll discuss one that does – there’s a lot of code to write to implement this deferred updating scheme. On the other hand, you can provide complete knowledge of the data conflict situation to the user with this method, and offer the user fine-grained control of the remedy.
Going back to our elevator inspector, your application could tell the inspector that he was using the old value of the building name, what that was (“Bahnad”), tell the inspector the current name of record in the database (“Barnard”), leave it to the inspector to either know or find out the name of the building where he was currently working through non-computer channels, and completely avoid any loss of entered data.
Offline Apps with Alpha Anywhere
Alpha Anywhere, starting with version 3, implements the deferred database-updating scheme for offline mobile applications that we described here. As a bonus, it also handles local data persistence for forms, and application caching, to address all of the possible runtime problems we identified earlier. Alpha Anywhere builds on a long history of soup-to-nuts database application development on the desktop, the web, and mobile devices.
You can see the offline capabilities of Alpha Anywhere in 90 seconds here, and view an hour-long discussion of how this all works from a developer’s viewpoint here. If any of this strikes a chord with you, you can download a free trial of Alpha Anywhere from the Alpha Software website.
Read more: http://www.alphasoftware.com/
This content is made possible by a guest author, or sponsor; it is not written by and does not necessarily reflect the views of App Developer Magazine's editorial staff.
Become a subscriber of App Developer Magazine for just $5.99 a month and take advantage of all these perks.
MEMBERS GET ACCESS TO
- - Exclusive content from leaders in the industry
- - Q&A articles from industry leaders
- - Tips and tricks from the most successful developers weekly
- - Monthly issues, including all 90+ back-issues since 2012
- - Event discounts and early-bird signups
- - Gain insight from top achievers in the app store
- - Learn what tools to use, what SDK's to use, and more