Properly Building Persistent Programs
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:
- Local variables persist for the lifetime of a particular function.
- Object-level variables persist for the lifetime of the object.
- Global variables persist for the lifetime of the application.
- Stored information persists across multiple runs of the application.
- 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.