My first day of Physics class in high school, we were given English homework: find the definition of the word Parsimony. My teacher was trying to underscore a point about the study of physics–while it explained the most complex of phenomena, the underlying theories and equations usually boiled down to a certain level of simplicity. And as a corollary, if you found yourself trying to add in all kinds of complexity to an explanation, chances are you were running down the wrong road. Which is not to say physics wasn’t filled with contradictions, despite my teacher’s mighty attempt to make it all seem elegant and grand. I struggled with Quantum Mechanics because it violated every rule of simplicity learned to date in science. And String Theory too. Even Occam’s Razor is still one of my favorite things to trot out when folks are getting too mired in their own story.
Yet, we do the same things as developers all the time. Brian Kernigan of C language fame has a famous quote:
“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”
In other words, if you are at the limit of your skills in WRITING the code, you are far beyond your reach in debugging and MAINTAINING the code for the time to follow. Where does the complexity come from? That’s easy–we’re constantly trying to optimize the code. That nagging voice pops up in my head when I start appending Strings in Java–”Ooooh. That’s TERRIBLE. That could be performance bottleneck! You’d better optimize that…”
Take a deep breath and step away from the StringBuilder. Donald Knuth said it best:
“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.”
Yes, we mean that string code, or that database query, or whatever you’re working on. I mean MOST of code you write. We code for the unexpected and then accidentally mire ourselves deep in complexity all for the sake of optimization.
It’s easy to forget the 80-20 rule (80% of the program execution time will be spent in 20% of the code). There’s also a 90-10 variant of the rule (which makes the point even more harshly). Let’s put this rule another way. Your optimizations and complexity are completely wasted in 80% of your code.
Let’s figure out the real cost of this: Suppose you spent an extra 8 hours per week working, debugging and perfecting that kind of code for 3 months on the project (in addition to your regular work). You spent 96 extra hours on the project (a whopping two+ weeks!) and of those hours, almost all of them were a waste since they didn’t lend any real value to the end product.
The Rules of Simplicity are quite simple (c’mon, you knew it was coming):
- Make your code as simple as possible.
- If you think it needs to be optimized, run it through a profiler. And then see Rule #1.
Simple code yields clear benefits over complexity to everyone:
- Quicker maintenance
- Easier extension
- Fast bug fix times
- Shorter up-to-speed times with new developers
- Lower frustration levels with support engineers
Think any of those isn’t important? Try spending time as a support engineer of your product sometime and maybe you’ll feel differently. Or sit with a support engineer for a day and see how they have to work with, explain, and sometimes apologize for problems in the product. Or just wait six months and try, just try to fix that extra clever code of yours.
I can hear the whines coming already: “But what about an extra layer of indirection for database portability?” Or maybe “the communication layer abstraction so you could talk to an ESB in the future, surely I have to plan for it”? The answer is NO. Unless you need it NOW, you ain’t gonna need it.
Complexity is our mortal enemy as developers. It makes all of us dumber in the end.