July 24, 2009
Writing a computer program is like traversing a tree. Going deeper into the tree means filling in methods with more detail. The breadth of the tree is all the work that needs to be done.
My impatience leads me to a breadth-first programming style. I quickly write a minimal program that accomplishes the task (a quick pass of the breadth at a high level), then fill out more and more detail (descend into the depth of the tree), adding minor functionality, error checking, edge case handling, comments, documentation, refactoring, etc.
Another approach is depth-first programming, where you write your first method perfectly, handling every error condition and special case, writing copious comments, and so on. Then you move on to the second method. It’s exhausting to work this way. There’s no feedback to keep you motivated. You can’t run the program at all until you’ve written every line.
In theory both methods lead to the same program, just in a different order. In practice, though, they each have different problems. The major problem with the breadth-first approach is that, at some point, the program will be “good enough” and you’ll move on to another program. From your boss’s point of view this makes sense: there’s more value in your starting something new than polishing your current program. Programs written this way don’t bottom out the tree.
There are two problems with the depth-first approach. The first is that if you run out of time, you have nothing. This happened to a co-worker who worked for three months on a program and when the deadline came he hadn’t yet implemented the “save” feature. The rest of the program was gorgeous, but the client couldn’t use it for his project and another program was used instead. During the same three months I wrote a program breadth-first; it was used immediately and is still being used 14 years later.
The second problem is that if you realize part-way through that you designed your program poorly, or to changing requirements, then you’ve wasted a lot of time polishing routines that get thrown out altogether.
So what’s the best way to write a program? I’ve spent the last 15 years trying to move from breadth-first to depth-first, despite its two drawbacks. I find it easier to bottom-out each routine one at a time, rather than later finding the permission or self-motivation to go back and do a polish pass. The quality of the resulting program is therefore higher. The code looks better. There are fewer bugs, less unfinished business.
What about the two drawbacks? It’s true that you might run out of time, but I’ve only seen that once and presumably it’s manageable with either a flexible deadline or a conservative schedule. The second problem is wasted effort, but that’s acceptable to me if the result is of higher quality.
Avoiding “unfinished business” is important, at least in a work environment. After you’ve been at a place for a few years you are haunted by every little missing comment, missing error check, missing little feature, unpolished routine, every unhandled edge case, sloppy parsing, outdated documentation, unreproducible crash. You do nothing but apologize for and fix your old code. It’s dreadful. You leave the company in frustration and your successor convinces your manager to rewrite everything you’ve done, because “it would be easier than fixing it.”
My co-worker had the last laugh, because four years later he was writing new code while I was cursing that original program I’d written sloppily in a breadth-first way.