Thursday, September 6, 2007

How to do preferences

Recently, codinghorror ran a blog entry under the title of Was The Windows Registry a Good Idea?

Now I don't want to be caught dead defending the registry so I won't defend it. What I want to tackle are the various comments to the blog posting which suggest alternatives that are clearly inferior or, alternatively, blame the registry for other issues entirely.

First up Jeff Atwood himself:

How appropriate. I post about the aggravating nature of the registry last night, today I get to "fix" a DVD-R drive that mysteriously fails to load with error code 39, by making this cryptic registry change:

(see post #4 -- remove "LowerFilters" from the "{4D36E965-E325-11CE-BFC1-08002BE10318}" key under HKLM\System\CurrentControlSet\Control\Class)

Works like a champ now. :P
Jeff Atwood on August 29, 2007 06:10 PM

I too have had problems with lower filters causing problems. This isn't the fault of the registry this is a design flaw in windows.

Installers have the ability to make changes to settings that are not available to the user. In my case an installer (probably iTunes) added a lower filter then the un-installer neglected to remove it. It's a good thing I had read Mark Russinovich's blog posting which, among other things, mentions that..

"...Unfortunately, although you can view the names of registered filter drivers in the “Upper filters” and “Lower filters” entries of a device’s Details tab in Device Manager, there’s no administrative interface for deleting filters. Filter registrations are stored in the Registry under HKLM\System\CurrentControlSet\Enum so I opened Regedit and searched for $sys$ in that key. I found the entry configuring the CD’s lower filter: ..."

..other wise I would have assumed that the CD-ROM had died. The lower filter registry key problem is one of not having any interface in the GUI proper for managing lower filters properly.. OR that the system is so blinding stupid that it can't .. well.. I'll let Mark explain this one:

"When I logged in again I discovered that the CD drive was missing from Explorer. Deleting the drivers had disabled the CD. Now I was really mad. Windows supports device “filtering”, which allows a driver to insert itself below or above another one so that it can see and modify the I/O requests targeted at the one it wants to filter. I know from my past work with device driver filter drivers that if you delete a filter driver’s image, Windows fails to start the target driver. I opened Device Manager, displayed the properties for my CD-ROM device, and saw one of the cloaked drivers, Crater.sys (another ironic name, since it had ‘cratered’ my CD), registered as a lower filter:..."

Essentially if you have a CD-ROM with a lower filter thingy and you delete the file on the HD containing the filter thingy's code, then windows tends to disable the entire device and not give the user any useful feedback as to what is going on. This, not the registry, was Jeff's problem.

Ways of screwing up user preferences. Here's a bad suggestion:

"I personally like XML and ini configuration files, but they should be kept in the dir with the rest of the application's files IMO."

User's preferences can never go in the same directory as the app. If they did the application would not work with multiple users. Consider the two cases:

1 - Multiple users with multiple accounts sharing the same app. Every time one user would change a pref, all the other users would get it.
2 - A user running an app off a remote hard disk. Like the previous case all setting would be shared.. oh and there are also concurrency issues that will result in corrupt preferences.

Here's an note of interest: Applications on the mac used to store their settings inside themselves. They actually wrote their settings into their application files. This isn't as crazy as it sounds because the Mac had a way of storing resources like strings, images etc.. as real resources (as opposed to ad-hoc twiddling inside a binary file) inside the application program binaries and these things could be modified while the application was running. This was deprecated when appletalk became available and people started launching applications over a network. It caused race conditions if two people were running the same app and modified a setting at the same time.. oh and both users would interfere with each others settings.

(It actually had quite a few other problems too, not the least of it was was the possibility of corrupting the application file.)

Here's a point about speed:

"Yep, go with those ini files (or xml)!

Then deal with the performance hit of searching out keys or trying to update values. "

Someone once told me the key to bending a spoon is to realize there is not spoon. It's much the same problem when optimizing code.

There's no significant overhead with using a "ini" or "xml" file approach. This is especially true when it comes to making changes and writing them out.

What you do is you read the whole config file into ram and turn it into a data structure. You then use the data structure and make changes to it. You can then re-encode this data structure back into an ini file (or whatever) and flush it to disk at your leisure. I prefer to do flush it on a separate thread so it doesn't block the thread making the changes. You can also extend this system to automatically save/flush the preferences for you by simply detecting any changes made to the data structure, setting a timer for, say, 30 second (to batch any changes that might occur slightly after the first change), then write out the data structure in a background thread. It's loads of fun. I've implemented such a beast at least twice now. The net result is all your accesses to the prefs are super fast 'cause they are in memory..

"Don't forget to implement proper locking logic to handle multiple users hitting the same ini file."

Multiple users will not hit the same file because you've got one files per user per app as I've already mentioned.

"I'm sorry, I left off this gem:
"The registry is a single point of failure."

If you have a bunch of configuration files in a directory somewhere, and you delete those files... Isn't that a single point of failure?"

No that would be "n" points of failure skillfully dispatched with one stroke. You can simulate this in another way by getting a gun and shooting your hard drive. Go ahead; try to find a way of saving preferences on a had-disk that gets around that baby.

The point of having different programs save their settings in different files is that if a program is, let's say, writing to the registry and the power goes out or it crashes, that it doesn't leave the entire registry file in an indeterminate state. Microsoft has had to almost re-invent the concept of a journaled file system in registry form to get around this little problem. No wonder it took them so long.

"As others have pointed out, .INI files have their issues to (inconsistent format, can be scattered around, multi-threaded access), but *nix has made it work relatively well. That said, I pity the fool who has to look at for the first time."

First off, no preferences file, whether it be .ini or XML should have to be edited by the user. It is up to the GUI application itself to offer a way of accessing its preferences.

Secondly, preferences file should not be scattered around! If they are then they will, most assuredly, not be in the right scope. That is, user preferences must in a place that is associated with the user so that users don't tread on each other. They cannot be in the same folder as the application.. They cannot be in the same folder as a neighboring application. They can not be one level up or one level down. They cannot be in any of these places for the same reason; a reason I explained above: multiple users. User preferences files must be in some sort of user specific folder.

Thirdly! (I thought I'd surprise you by using an exclamation mark on that one) As an operating system designer, you're going to want to offer an API for doing preferences. As has been made obvious by the comments posted to Jeff Atwood's blog, most programmers don't have a deep understanding of how to do preferences properly and, for that matter, writing a good preferences API is not an easy thing. Since your system is going to offer an preferences API, you might as well make the FORMAT for the files it produces standard. Why not XML? Yeah, yeah I know...

"Your article reminded me of this quote;-

Those who do not understand Unix are condemned to reinvent it, poorly.
-- Henry Spencer"

Given that UNIX is very poor to begin with that's pretty bad.

Yeah, ok so that was an off-topic unix jab.. I'm allowed 1.

"For instance, when I upgrade and reinstall Windows, most of the games I have installed on my secondary drive are instantly broken because they store cd-key and (redundant) path information in the registry. The game vendors' support teams will tell you to reinstall all your games and patches. Personally, I'd rather search forums and spelunk through the registry to manually recreate the two or three registry keys the game is looking for."

This isn't so much the registry's fault as it is an asinine windows convention. Quite a few programs tend to store, what are really string resources or required configuration information in the registry. This belongs in applications DAMMIT!

I suspect this whole thing got started when you absolute needed to register things like dlls or go knows what other type of thing in the registry. You see, the windows not only stores user preferences but also stores system configuration information as well. One could argue that this was its original purpose, really, and it just grew to contain preferences information as well.

There is a huge habit of using installers and de-installer do play with system settings both in the registry and to add icons to the desktop, the start menu, that quick launcher thing etc.. or to do things like install DLLs or some other damn thing (low filters!). This is a major irritation on windows and the primary reason why installers exist. If you look at the mac, installers are rare. This is because mac programs tend to be self contained and there's no cultural convention for installers installing icons in the docs or desktop. In fact, one could argue that you treat applications as icons and just drag them to you applications folder to "install" them. This is much better than an installer system in which so much can go wrong. Even after years of work on the windows installer system it still sucks balls. Sure it's not hopelessly broken any more as it was in the windows 95/98 days but it's still really bad. Installation is something the Mac really gets right.

"Ever tried to make a single entry in an ini-file readonly for the user?
I wish you lots of fun...

Only with the registry you could administer hundreds of machines in an easy and consistent way.
Only with the registry there is a way to double-click a .reg-file and enter its content automatic into the registry.
and on an on and on.
Registry is like a database, ini-files are like chaos."

People did this sort of thing with our application InteleViewer. This configuration is not supported! If you do this with our apps then phone our support line we will not support you. In the end what we did was write the functionality people were trying to reproduce into our app in an decent, easy to use way. It's also far more powerful too since it does what you were trying to achieve in an explicitly supported way! It's called roaming user preferences and it rocks.

Also, I think I should point out the existence of LDAP.

"...I do wish they'd adopt the same plist configuration format found in OSX, its XML based, very flexible and easy to work with.

Ini is kinda primitive when compared to plist, and Unix's convention of having no convention here is a poor idea."

Actually I agree with this one.. Come to think of it, the way MacOS X stores user preferences is exceptional. It does everything I've advocated here.

1 - It stores user preferences in the user's home folder under a special folder which is actually accessible to the user.
2 - Each app stores its preferences it their own files.
3 - The files is and XML format called a p-list.. There's even an editor with the development tools.. Which is good since while XML is, in theory, human readable/editable without an editor, no human would ever want to actually try.
4 - It's got a nice API baked in for dealing with application preferences.
5 - There's a well understood convention that no application should ever put a setting in its preference file that is essential to the functioning of that app.. All this to say that if you get fed up you can simply trash everything in the preferences folder and be assured that nothing will break.. You can also trash a spefic preferences file of a single malfunctioning app if you suspect it to be the source of problems.. I've actually done this many, many times while on the mac and it's amazing how often corrupted preferences files are problems.
6 - There's also a convention that you're not supposed to edit these preferences files by hand!!!!

Anyways... I suppose my main point here is that if you're going to try and build the ideal user preferences system you'd better bone up on the way the Mac does it.. Same deal if you want to look at creating a better installation system.

Ok I'm done..

No comments: