What if no one reads it?

You should favor readability

Among the books I am currently making my way through is "Exploring Computer Science with Scheme" by Oliver Grillmeyer. The publish date on this particular book is 1998. No matter how often it happens, I feel a twinge of despair for our profession when I read sound advice from a decade or more ago that has yet to be widely adopted; or worse is still hotly contested.

Grillmeyer contrasts a couple different functions that accomplish the same end. One terse, but obfuscated; One verbose, but transparent. In conclusion, Grillmeyer states, "In a tradeoff between readability and length of code, you should favor readability."

Damn straight.

Sure, you can use some Ruby-fu and get those four lines in the controller down to one. Yes, you can in-line the whole damn method call. But to what end? For what purpose? Why are you reducing the lines of code? What is your objective?

Favoring line count

I once completed the Bowling Kata in Ruby. It was approximately twenty five lines of code. It was readable. Each method had a clear and singular intent. I asked a non-developer friend to look at it and tell me what it did. It took him no more than 60 seconds to figure it out. I then told a Ruby developer about the Kata and without even looking at the code he said, "You should be able to do that in seven lines of Ruby."

So I set out to refactor the code down to seven lines. And it was an interesting exercise. I managed to get the code down to about twelve lines; I had cut the code in half. But then I stopped. The intent was no longer clear. One had to interpret the code in order to discern what was happening. My tests were a mess; I could not test behaviors in isolation.

I had sacrificed clarity at the altar of line count. And I was ashamed.

A (very brief) twitter discussion

So after reading the line from Grillmeyer, I tweeted it. Moments later, a buddy responded.

What if no one reads it?

Interesting question.

So you're working on a pet project; something that only you will ever work on. No other developer will ever see this code. And you're working on a feature where the desired behavior is so well known and immutable that you too will never, ever, under any circumstances need to change it. And the language and platform are absolutes; they too will never change - no new libraries, no change in any of your dependencies; not even a revision tick. You are certain that no one will read it; not even you.

And you can either write it in a terse manner, or a readable manner (but not both). Which is better?

Good code is efficient. Good code is testable. Good code displays an attention to detail. Good code has singular purpose and lacks duplication. Good code is expressive. Good code is written by developers who care. Good code is pleasing to read. Good Code is Clean Code.

Having worked on a system that manages over one hundred thousand purchases per day, I do not believe there are many situations which absolutely mandate performance at the cost of readability. So while I expect the argument, I believe it to be an outlier at best, if not completely fictional.

Given the definition of good code and the likelihood that what we are working on does not require obfuscated code for performance gains, there is no other possible consideration.

Code must be written for readability. If it is not; it is not good code.

Certainly, one can opt to knowingly write bad code, but I cannot comprehend the motive.





5 comments:

  1. Really interesting post. I agree with you good code is readable, intention revealing.. So in write Ruby code meta magic is strictly kept out of application development part :).

    Have you ever felt that this problem is easy to creep up in functional paradigm than in object oriented?

    Example:

    factorial n = if n > 0 then n * factorial (n-1) else 1

    or

    factorial n = (foldl (.) id [\x -> x*k | k <- [1..n]]) 1

    ReplyDelete
  2. Cool post - the discussion about favouring readability really reminds me of this post by Reg Braithwaite - http://weblog.raganwald.com/2008/05/narcissism-of-small-code-differences.html

    I think with stuff you're playing with on your own it's a playground for making mistakes and investigating ideas so it's no big deal if you try to make it as terse as possible just to learn the language features.

    Even then though I found that when I came back to F# code I'd written a few months ago I couldn't understand it at all because it was so non-intention revealing.

    Certainly when in a team I think we should aim to write the most obvious code - http://www.markhneedham.com/blog/2009/03/18/coding-make-it-obvious/ - so that when someone else has to look at it they're easily able to understand what you've done and then add to it.

    ReplyDelete
  3. Absolutely agree with this, and I write as one who has, in the past, gleefully reduced code to unreadable single-line C for loops but who has seen the error of those ways.

    Regarding the performance argument: it is easier to come back to unoptimised-but-readable code and optimise it for performance (if a need to do so is identified) than it is to come back to optimised-but-unreadable code and make changes for any of the myriad other reasons that code changes are often required.

    ReplyDelete
  4. As you said, it's been established for a long time that first you're writing code for humans to read, not machines.

    Usually, more efficient code comes from a better understanding of the algorithm.

    Get it right, then make it fast. If it's too slow, instrument to find where the code is spending its time, then optimize there. Anything else is probably going to be sub-optimization.

    ReplyDelete
  5. You lack macho. Don't you understand that with fewer lines per feature, you get more macho points? Hello! That is why your FRIEND pointed out that to you "... in seven lines ...".

    Myself I use "extract to local variable" to break up long lines of Java code. I use "extract method" when there are several lines forming a chunk of something. But I am a sissy.

    ReplyDelete