Sunday, June 16, 2013

Don’t Be Clever (When Programming)

Programming is an art. And as with any art, the artist feels compelled to show off how intelligently they can handle their tools, how well they understand their field, and how skillful they can express their ideas. At the same time, programming is engineering. Programs are written for a purpose, need to run, need to be maintained, and need to be extended. Those two faces can, and do, conflict regularly.

Clever and Pragmatic

A while back, I wrote the following piece of code in Emacs Lisp:

(defun get-cache-value ()
  (or cache-variable
      (setq cache-variable (calculate-cache-value)))

This works because, in addition to changing the binding of a variable, setq also returns the new value. A feature that is rarely used. Together with the short-cut operator or, this is a very clever use of lesser-known features of Emacs Lisp to achieve the same as the following definition:

(defun get-cache-value ()
  (if cache-variable
      cache-variable
    (setq cache-variable (calculate-cache-value))
    cache-variable))

Or even:

(defun get-cache-value ()
  (if (not cache-variable)
      (setq cache-variable (calculate-cache-value)))
  cache-variable)

(For Emacs Lisp hackers, yes, when would have been nicer, but I’m trying to make it accessible to non-Lispers, too.)

Let’s compare the first version with the last. The clever solution as I’m going to call it is shorter. It’s concise, does not have duplicate code, and, indeed, is quite clever. The pragmatic solution is slightly longer, references the variable one times more, and is more elaborate. It’s also less efficient. An artist might say, it’s kind of boring.

On the other hand, the pragmatic solution does not use any rarely-used features, as it does not rely on the return value of setq.

Boring is Good

And that is its advantage. I argue that the pragmatic solution is preferable in every case. The most important insight for good programming is that programs are read more often than they are written, and code should be written to facilitate that.

When hunting a bug, the clever solution will cause a programmer to halt. Even if it’s just for a short moment, the programmer’s flow of reading will stop as they need to dig out the rarely-used information on the return value of setq. Is it the new value, or the old? Some lisps used to return the old value. Some do not return any value. Which one is Emacs Lisp? Is this a bug? Ah no, it’s not. Oh, nice, that’s some clever piece of code!

This last piece of admiration is the reason why artists prefer the clever solution. The preceding pause in reading flow is why engineers prefer the pragmatic solution.

Art in Engineering

I love clever code. It’s great to look at and, slowly, trace how clever it uses obscure features to achieve something. It’s impressive. But most programs are not meant to be art displays. Instead, they are meant to achieve a goal. And once that is the case, I want good engineering done in them.

That does not mean that they can’t be art at the same time. Like bridges and skyscrapers can be beautiful to behold even though they are impressive works of engineering, programs can be beautiful, too. But just like beautiful bridges are not more fragile for the sake of beauty and skyscrapers do not sacrifice safety for beauty, neither should programs.

Find art in the way you optimize your program for true readability. There is plenty to be found there. You do not need to try and impress the reader by making them stop to think about your code.

Conclusion

Always prefer idiomatic code using well-known semantics. Avoid code that uses obscure semantics for show or for irrelevant improvements in speed or minor improvements in conciseness. They make your program harder to read for other programmers and even for yourself half a year down the road.

Don’t fall for the need to impress the reader with your cleverness. Impress them with your engineering skill instead.