Properly Building Persistent Programs

Wednesday May 28th 2003 by Mike Gunderloy

Imagine that every time you turned the computer on, it reverted to its original settings. Not a very happy thought, is it? Yet, there are applications that ignore user preferences and go back to defaults all the time. Learn about persistence: what it is, when you should use it, and some of the practical techniques for implementing it in your applications.

Remember the last time you installed a new operating system on your computer? Everything was set to its defaults: colors, fonts, menu items, speaker volume, and hundreds of other things. Over time you've gradually set all of those things to match your own personal preferences, and now your computer works just the way you like. Now imagine that every time you turned the computer on, it reverted to its original settings. Not a very happy thought, is it? And yet I see applications ignoring user preferences and going back to defaults all the time. The quality that the operating system has (and that some applications lack) is persistence. In this article, I'll discuss the basics of persistence from a developer's point of view: what it is, when you should use it, and some of the practical techniques for implementing it.

What is Persistence?

Persistence is the quality of persisting. In programming terms, persistence refers to information which remains available even when it's not being actively used by your application. Like many other concepts, persistence isn't a binary choice; there are levels of persistence. For software, persistence flows directly from the notion of variable lifetime. You can identify a scale of information persistence, from least to most persistent:

  1. Local variables persist for the lifetime of a particular function.
  2. Object-level variables persist for the lifetime of the object.
  3. Global variables persist for the lifetime of the application.
  4. Stored information persists across multiple runs of the application.
  5. Permanent information persists across multiple installations of the application.

For this article, I'm concerned only with stored and permanent information: things that persist even after you shut down and restart the application. This is the information that makes the application itself appear persistent to the user.

Persistence and Preferences

Persistence is often tied to user preferences, but they are two distinct concepts. User preferences allow the user of an application to dictate how the application works. Most applications persist user preferences, but in some cases you might want to implement a non-persistent user preference. For example, you might allow a user to choose to run a document transformation application in a test mode such that its user interface is functional but no changes are written back to the document. In such a case, you probably wouldn't want to persist the preference for the next time that the application is run; such testing is likely to be an occasional activity rather than a permanent user choice.

The classic mistake in user preferences is to have too many of them. Sometimes programmers just can't make a decision, and so they add another checkbox to the user interface, usually on a cluttered Options dialog box. If you're expecting users to make hundreds of such decisions, you need to seriously rethink your approach to user preferences. Possibly you can take some rare settings, of interest to only 1% of your users, and migrate them to an initialization file where the 99% won't need to look at them on the user interface. Better yet is to just figure out the best decision and make it for the user. Flexibility in software is good, but it can easily be carried to extremes.

Whether you allow the user to tweak a setting or not, you should always make sure that the default, un-tweaked setting is appropriate for the majority of your application's users. If the application is run with the default setting for everything, then it should still work sensibly.

What Should You Persist?

I've already mentioned user preferences as a category of information that lends itself to persistence. Here are some other things that you should think about persisting in your next application:

  1. Transparent preferences. Sometimes user actions result in a change to the internal state of an application that it makes sense to persist. For example, if you allow the user to customize the toolbars in your application, they probably do so via drag-and-drop rather than through an Options dialog box. But even though they don't think of this as something to be saved, you should be smart enough to save the changes behind the scenes. The size and location of your application's main window is another example of a transparent preference that you might decide to persist.
  2. User history. Sometimes it makes sense to give the program some memory of what a user was doing when they last left the application. A weak form of this sort of persistence is the most recently used (MRU) list of documents you'll find in many document-centric applications. A stronger form is to simply open the last document that the user was working with automatically when they launch the application in the future.
  3. Logging with playback. Ordinarily, I don't consider logging or tracing of a program's actions to be a part of its persistence layer. That's because the log is normally not meant to be read, only written to. But there's a special case when you can consider logging as a form of persistence: when you offer playback. Imagine a complex graphics program that let you decide to suspend an editing session in progress without saving the changes to the image. You might log all keystrokes up to that point so that the user could return to where they left off.
  4. User limits. This is a case where permanent storage, even if the application is uninstalled and reinstalled, can make sense. The classic example is limits on shareware: if your application is designed to be used for thirty days without payment, you don't want the user to get another thirty days just by reinstalling it. In this case, you'll want to persist (and probably encrypt) the starting date somewhere. Note, though, that not removing your information from the computer at uninstallation time may violate the guidelines for various logo programs.

The Problems of Programming Persistence

After you've determined the information that your application will persist, there are two main implementation details to consider: where to persist information, and how to structure the persistence layer in the application.

There are a wide variety of places that you can persist information: in the Registry, in disk files (whether ones of your own design, or old INI files) or in a database - and that's just on Windows. There are several factors you need to consider when determining where to persist user information:

  • Is your application used by multiple users? Do you need to keep them from "stepping on each other" by overwriting persisted information?
  • Is the information sensitive? Does it need to be encrypted to protect the user's privacy or security?
  • Is your application already using a data store (such as a database) for other data storage? Can you leverage this to persist user information with minimal code?
  • Is your application used by non-administrative users? Can these users open the store you've chosen?
  • Is your application used by roaming users? Does your chosen data store roam with these users so that they get their preferences wherever they log on?

Whatever you choose, I urge you to make use of any persistence features built in to your operating system and coding environment. Don't reinvent the wheel if there are good facilities available. If you're working with Microsoft .NET, for example, take a look at the Isolated Storage feature, which automatically handles security and roaming issues for you across all of the supported Windows operating systems.

Finally, some advice on structuring your persistence layer:

  • First, whatever you do, do create a persistence layer that presents an abstract view of persistence to your application, and hides the implementation details. This will allow you the freedom to change the underlying storage medium without rewriting the rest of the application.
  • You'll usually want to read the persistent information at startup and write it out at shutdown. Be sure you take into account all code paths out of the application; if something goes wrong, and the application needs to exit abnormally, you should still persist information if possible.
  • Always assume that the data isn't actually persisted when you're reading it in. That is, if the call to read the data fails for any reason, you should supply good defaults to the application.
  • When you're running in debug mode, add checks to make sure that persisted information has reasonable values. This will help shake out bugs where you're saving the wrong information.

The Benefits of Proper Persistence

Why go through all this bother when you're designing a new application? The answer is simple: users expect applications to be intelligently persistent. Properly implementing persistence translates into an easier to use application with happier users. Ultimately that translates to either sales or job security (or both!) for the developer. Look at it this way: having an application without persistence is like going out to sleep every night at a hotel. The furniture is always in the same place when you get there, whether you like it or not. Wouldn't you rather sleep at home, where you've moved the couch and the bed to just the right spots, and they stay there when you're away? That's what persistence can do for your applications: make the user feel right at home.

About the Author

Mike Gunderloy is the author of over 20 books and numerous articles on development topics, and the lead developer for Larkware. Check out his MCAD 70-305, MCAD 70-306, and MCAD 70-310 Training Guides from Que Publishing. When he's not writing code, Mike putters in the garden on his farm in eastern Washington state.

Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved