Monday, December 6, 2010
Windows Phone 7 and Data Persistence - Not As Simple As You Might Think
Posted by Don Sorcinelli in "Windows Phone Developer" @ 07:00 AM
Now that users are getting their hands on Windows Phone 7 devices, many of the applications submitted to the Windows Phone Marketplace are getting their first real tests out in the field. While many of the applications are meeting or even exceeding user expectations, there have been some complaints. If you were to categorize the issues across applications, one area that seems to be a pain point among users has been some applications and their saving - or not saving - data properly, or at least to the expectation of the user.
While Microsoft has done an admirable job in explaining and detailing the process for Windows Phone 7 developers for data persistance and the Windows Phone 7 architectural model, I can't help but think that some of the messaging hasn't made it to all developers. The simple concept of ensuring that data that needs to persisted or saved can be quite complex to implement. Not taking the proper care in this matter can result in a very poor user experience and very disgruntled users.
With all the talk happening around why data is not being saved, I thought it would be a good time to discuss some helpful reminders and tips around data persistence from a Windows Phone 7 development perspective. Hopefully, these friendly reminders from "your old Uncle Don" will make your application behave a bit better and make your users a bit happier.
Don't Rely on the Windows Phone 7 Default Behaviors
Yes - Microsoft has explained it time and time again. It's the way that Windows Phone 7 manages applications that lose focus when the user moves away. By default, an application that loses focus will be put into a sort of "history stack", and data in memory will be persisted. The idea here - if the user leaves your application to go to another application and then returns (using the Back button, for example), your application could be found on this stack and data restored.
There is a lot of information on this process, but perhaps the most important message to take away from this model is that nothing is guaranteed here. While there is an application stack, it is not infinite in nature. As a matter of fact, there is no guaranteed maximum number of applications on the stack. All of this is managed by the operating system based on different factors. Conclusion? Do not count on the OS handling everything for you. As a developer, you need to take greater care in this regard. There are ways to do this, with programmable events to trap and respond to. It is in your best interest and the interest to use them if necessary.
Don't Assume Your Application Will "Activate" When First "Deactivated"
As I mentioned previously, developers can respond to events around the leaving of an application. Microsoft provides four of these higher-level events; "Deactivating" (when an application is being left by the user pressing the Start button or launching a Chooser), "Activating" (when a user is returning to a previously deactivated application by use of the Back button), "Closing" (the user is leaving the application by pressing the Back button from the page default page for the application - a possible "gotcha") and "Opening" (the application is launched from its icon or is not on the application history stack). A possible problem arises when the application is coded to presume that any deactivation will result in an activation. In other words - code is focused on these two events.
It's very possible that a deactivation event can happen - and an application will persist data - and then the application start again without an activated event firing. One such scenario: as a user, I leave the application using the Start button (deactivated), do some things and then go back to the application by pressing on its icon from the Programs list (launching). There are a few ways a developer can account for these scenarios, and if the data is important they should program accordingly.
Size Matters! (No Giggling, Please)
A simple rule of data and applications is "the greater the amount of data, the greater the complexity of management". That includes saving data. When it comes to size and data, the larger the amount is the more likely the risk of an error during a read or write operation. In addition to this general rule, there is the factor of the time it takes to save the data. In the Windows Phone 7 world, time can have a serious impact.
There is a rule in the Windows Phone 7 execution model that some developers may not know about. When a deactivation event occurs, the application has 10 seconds to execute code within that deactivation event. At the end of that period, the application is terminated regardless of what it is doing. While 10 seconds may seem like a long period of time, complex application logic or calls to the Internet can eat up that 10-second time limit quite quickly. Termination in the middle of a saving process can (and likely will) result in incomplete or corrupted data. I have heard reports of Windows Phone 7 applications that, when restarted, begin to load data and then just disappear. Without access to the means to personally debugging these applications, I can't help but hypothesize that there might be some unanticipated data corruption involved. Size may, of course, be playing a factor.
For every scenario that requires the saving of data, developers should ask the simple question "what might possibly need saving and how much effort will be required to save it?" If the amount of data or the complexity of the saving of data could lead to issues, coming up with alternative approaches to saving that data may be required. This leads to...
Determining What Makes A Logical Transaction
If you've worked in the world of databases for any period of time as a developer, there are usually certain principles of programming that are ingrained into your programming mentality. One of those principles revolves around the idea of a transaction. From a database perspective, a transaction is a logical unit of work that must be completed in its entirety or not at all. While a translation is usually associated with a database application, the same principles apply to applications that persist data, database or not.
There are always two ways to look at a transaction. There is the technical implementation of a transaction, which includes how a programming language or database management system defines the scope of a transaction and handles things (when to commit or roll back changes). The other aspect of a transaction is conceptual - from a business rules perspective, how big or small should the defined boundaries of a transaction be? An example scenario may help to explain.
Suppose I am writing a simple To-Do list application. I allow the user to create, modify or delete one or more To-Do list items. From a business perspective, I would likely consider each To-Do list item interaction a transaction. In other words, if a user creates, modifies or deletes a To-Do list item, they must complete the operation entirely. When they finish adding one item and confirm completion, the application should save that one item. If they are halfway through modifying a To-Do list item and exit the application, the "half-baked" changes should not be applied. Sounds simple, right?
I heard recently of one Windows Phone 7 application that provided functionality similar to the one just described. A user reported the following:
"I added three items in the user interface. I was on the screen to add another when I decided I was done for now and exited the application. When I returned to the application, none of my items were restored."
While there may have been other issues at play here as we have already discussed, I couldn't help but think about the transaction implications. Ideally, after each item was completed, it should have been persisted to Isolated Storage. Only the fourth iteration should have been discarded. My concern with all of this is simple - in all of the talk about persisting, storing and restoring data, folks have been treating a session of the application running as a single transaction, not the more appropriate actions that occur within a session as more atomic (and logical) transactions. There has also been quite a bit of talk and documentation on "in-memory database models" from Microsoft and in the community. While this is important, it is not everything to an application. Persisting data from memory to disk at logical intervals to preserve data integrity is as (if not more) important than techniques for performace. If my application loads data into memory and is blinding fast but doesn't properly preserve data to disk, then...
I can't encourage developers enough to take a step back from their applications and consider the logical and technical considerations of transactions. In addition to potentially increasing data integrity, periodic saves of data at logical points may also help to reduce the "size" issues previously discussed.
There are a tremendous number of Windows Phone 7 applications hitting the market; there are even more coming to the Windows Phone Marketplace on a daily basis. The majority of these are running problem-free and receiving loads of praise from the user community. For those applciations that are having data issues, revisiting some of the principles around the Windows Phone application lifecycle and some common-sense thinking may result in happier users and developers.
Don Sorcinelli is a Microsoft MVP for Mobile Devices and a consultant with 20 years of enterprise software development experience spanning a variety of technologies and platforms. He has spent much of the last decade focused on mobile technologies for both business and personal productivity. He is currently a Product Engineer focused on mobile applications across mobile device platforms.