Return to Home Page
      Blog     Consulting     Seminars     Calendar     Books     CD-ROMS     Newsletter     About     FAQ      Search
 

11-21-03 SPO: Solve the Problem Once

Dave Thomas and Andy Hunt, authors of The Pragmatic Programmer, have a principle they call DRY: Don't Repeat Yourself. The phrase suggests repetition in code, such as duplicate code that could be refactored into a single function. This would make it a different way of saying "Once and Only Once." However, based on comments they've made in interviews, I suspect that (despite the cleverness of "dry" as an acronym) they would rather have called it "SPO: Solve the Problem Once."

In this interview, Dave said that "The idea behind DRY is far grander than that [you shouldn't duplicate code]... DRY says that every piece of system knowledge should have one authoritative, unambiguous representation." (This sounds more like a description of the SPOT rule: Single Point Of Truth.) To me, this says "when you solve a problem, solve it so that you don't have to solve it again, later."

Since finishing Thinking in C++, Volume 2 (in print this December), I've been doing a little retrospective to discover what could be improved in the process, especially since I was working with a coauthor, Chuck Allison. Over time, I've discovered tools to be one of the foundations of the book development process, or any process, so that's one of the things I've been trying to improve.

One of the tools that remains part of my core toolset is make, despite the existence of all sorts of open-source attempts to "make a better make." I applaud these attempts and hope that I can switch to something better someday, but in the meantime, make is what works. You can test and invoke just about anything with make.

One of the issues with make is configuring it to know where your various programs and directories live. This is generally accomplished with macros:

TOOLLOCATION:=C:/MyTools/Buzzer.exe
DIRLOCATION:=D:/TestDirectory/code
As long as these are on my own machine, I can just set them in the makefile and not worry about it. Of course, when I move the project from my desktop to my laptop, the paths might be different, and when the project directory gets copied to Chuck's machine, everything is different.

My first solution was to "separate the things that change from the things that stay the same" by extracting the directories that seem to change from machine to machine, and put them in their own .defs file, which the makefile would then include. There was a desktop.defs, laptop.defs and Chuck.defs file. This sort of worked, but it seemed like maintaining all three files in the same directory didn't quite work. When I sent Chuck a new version of the directory, his old settings would get overwritten with whatever I had. I do find it very helpful to keep everything about a project in a single directory — that way, "installing" it on another machine is simply a matter of copying the directory. The simplicity of that approach is quite valuable, but if important information is getting erased in the process then it isn't working.

Platform-specific information needs to be separated from project-specific information, and the project always needs to know where to go to find the platform-specific information — you need a repository. The single point of truth is a recurring theme in program design, and is the proper justification for the Singleton design pattern (as opposed to using it as an excuse for global variables).

My first thought was to use the Windows registry. Python has tools to read and write this, and while the book code works on other platforms, the tools to build the code tree are designed for Cygwin under Windows. Fortunately, this impulse passed — why should I take the responsibility for messing up someone's registry and possibly whacking their machine? And for what? ("Let's try something complicated" always seems to be my first impulse, so I try to sit down and breathe until I remember "Do the simplest thing that could possibly work.") However, the concept of the registry as a single point of information is still valid, so why not just make my own variation of the registry — a plain text file whose name and location is specified by a single environment variable, containing configuration information, and the tools to read it. (under a *nix environment, you can just put your configuration file in your home directory; note that I call the python function os.path.expanduser in case you use a ~ in your path).

I did this, and then discovered that Python already has a module called ConfigParser that automatically parses Windows-style configuration files. This even includes parameter substitution.

The final tool consists of a general-purpose config file reader called ConfiguratorParser (this can be used within any Python program to produce configuration information), and a very simple tool, Configurator, that uses ConfiguratorParser and creates a def file which can then be included into your makefile. You invoke the program inside your makefile, and include the resulting .def file, with the following makefile lines, assuming PROJECT has already been defined as the name of your project:


$(PROJECT).def: $(CONFIGFILE)
	Configurator.py $(PROJECT)

include $(PROJECT).def

The problem that this solved was, in the grand scheme of things, a relatively small annoyance. But my experience is that the little annoyances build up to throw you off track enough during critical junctures — such as when you are in the heat of problem solving, trying to figure something out, and then you try installing a new version of the whole project and have to stop and reset your configurations — that it's worth the day that it took (in this case) to research and solve the problem once so you don't have to solve it again and again. Solving the little problems once may be the key to achieving productivity.

    Links I Read
Cafe Au Lait
Artima
Daily Python URL
Martin Fowler
Joel on Software
Paul Graham
Cringely
Search     Home     Web Log     Articles     Calendar     Books     CD-ROMS     Seminars     Services     Newsletter     About     Contact     Site Feedback     Site Design     Server Maintenance     Powered by Zope
©2003 MindView, Inc.