March 17th, 2012
[This is an essay I wrote in November, 2004; I found it recently in an archive. I decided that it was worth publishing here.]
Saving time by doing it the hard way
The other day I ran into a nasty programming problem with Java. I needed to build a jump table, a data structure that would allow me to route program flow to one of many different methods, depending on the value of an index. One could use the simple SWITCH statement, but I needed nearly 500 cases, and SWITCH statements merely set up a long string of internal IF-statements; with lots of cases, they bog down badly.
It’s not particularly hard to correct this problem in C; you just set up a table of pointers to the various functions. But for security reasons Java does not allow pointers. Now, I’m just a beginner with Java, and I must confess that, with my background in ancient languages like FORTRAN, BASIC, FORTH, assembly, Pascal, and C, I’m still not truly up to speed on object-oriented programming. So I pulled out the training books and read for a few hours. Unable to find a solution, I consulted the on-line documentation; that didn’t help me much; one solution I found was impossibly arcane. I’m sure that a good answer is out there on the web somwhere, but searches on Google for “Java jump tables” return a couple of hundred thousand hits. So I called my old friend Dave, who’s a much better programmer than I. Java isn’t his strong suit, but he seemed to recall a way to do it. He said he’d work on the problem.
By this time, however, I had given up on finding the correct solution. I knew a perfectly simple solution: a hard-wired binary search. It’s just a binary search implemented through explicit IF-statements – hundreds of them! The result took up some 2400 lines of code. But it executes pretty fast, requiring only nine tests to reach any particular leaf in the tree.
When I mentioned this to Dave, he was horrified. Writing 2400 lines of code seemed idiotic when the task could be done with a few dozen lines at most. I reminded him, however, that the job could be carried out with lots of copying and pasting. He still thought I was crazy, and went back to researching the elegant solution.
I decided to go ahead and implement my nitwit solution while he researched the elegant solution. It took me about four hours of tedious work spread over an eight-hour period. The next morning, I had an email from Dave containing Java code that solved the problem. His solution certainly looked clean and elegant. I tried it out; it didn’t work on my system. It worked fine on his system, but not on mine. After several hours of further futile effort, I gave up. Dave couldn’t understand why my Java implementation was balking at code that worked just fine on his machine.
So here we have an ideal case history highlighting two radically different approaches to solving a programming problem: the dumb way and the right way. The dumb way took about four hours of work; the right way took about ten hours and still wouldn’t work on my system. The dumb way wastes maybe a millisecond or two compared to the right way. The dumb way probably eats up 10K more code space than the right way. Let’s face it: a millisecond of execution time is negligible; and 10K of RAM is microscopic. It would appear that, in overall cost-benefit terms, the dumb way was better than the right way.
Of course, doing it the right way advanced my understanding of Java and makes me a better programmer. That’s always good – if you can afford the extra time it takes to learn the language.
What about maintenance? Wouldn’t the elegant code be easier to revise than the clumsy code? Not really. Because the elegant code is more abstract, it’s harder to understand and easier to misread. The dumb code is plodding but plain as day. Dumb code for dumb programmers, that’s what I always say.
So what’s the lesson to learn from this experience? I won’t claim that this anecdote proves beyond doubt that dumb code is superior to elegant code. I still haven’t decided which of the two approaches to use in my program, and the dumb code might eventually turn out to be too dumb even for me. The lesson is:
dumber ain’t necessarily worse; sometimes it might be better.
You’re probably squirming in your chair as you read this heresy. Everybody knows that elegant code is always better than dumb code – right? But I raise the question: do you know that elegant code is always better, or do you merely believe it? Have you carried out empirical tests to determine the superiority of elegant code?
Programmers set up meritocratic hierarchies: the smartest programmer is the top dog, and everybody occupies a slot corresponding to their technical prowess. This is all very logical and orderly, but why must our code organization mirror our social organization? When we assume that elegant code is superior to dumb code, aren’t we succumbing to the same kind of silly prejudice that animated the European aristocracies a few hundred years ago? If a dumb piece of code is fast enough, small enough, and maintainable enough, who cares if it’s clumsy? It gets the job done.
Let’s now extend this idea to you. How technically knowledgeable are you? Do you know everything there is to know about the programming language you use, the development environment you use, the target machine’s hardware and operating system? Of course not! Nobody could know all that stuff!
In 1976, when I first got interested in microcomputers (as they were then known), there was just one book to read: An Introduction to Microcomputers, by Adam Osborne. By 1980, reading the equivalent of about a dozen books was all you needed to be a world-class expert in your chosen field of microcomputing. But then things started exploding. I just today received a catalog of technical books. That catalog is 66 pages long; it contains 51 books about Java – and this is the offering of a single publisher!
It simply is not possible to keep up on any given topic. You have to become something of a generalist. As part of this, you’ll have to come to terms with the common belief that more technical expertise is always better. Face it: the Oasis of Technical Mastery is really a shifting mirage you can never reach. Chasing it will only rob you of the time to learn other, more important lessons. A good game designer has a well-rounded mind and knows more than just the latest coding tricks.
Since my earliest days as a programmer, I have watched as colleagues went through Programmer Burnout. It’s always the same: some young hotshot bases his self-esteem on how much technical information he can memorize. It’s easy to keep all that technical folderol in your mind when you’re young, but as you age and the tidal wave of technical information keeps flooding over you, you have to learn to adapt. Many young hotshots never master the trick of treading water in the Great Ocean of Knowledge; they keep swimming against the current. Eventually they burn out, throwing up their hands and sinking beneath the waves. But there’s always some fresh new kid straight out of college ready to take his place. Old farts like me and my friend Dave keep treading water, keeping our heads above the waves. You’ll either learn to tread water or burn out. Take your pick.