DEV Community

Jonathan Hall
Jonathan Hall

Posted on • Originally published at jhall.io on

Readability is paramount

I grew up, as a software developer, in the world of Perl. Perl’s motto is There’s more than one way to do it, (abbreviated to TIMTOWTDI and pronounced: Tim Toady).

As the thinking goes, this flexibility allows the programmer to write more concise statements, as well as choose a style that fits the context, or their whims.

But is this a good idea?

I distinctly remember the day I was trying to explain some Perl code to a colleague. The beautiful one-liner ellegantly iterated a list through a map function, and utilized the a subtle side effect to trigger an update to a variable, which was later read for its state.

After stepping him through everything it did, and him still shaking his head, I re-wrote it into a 3-line form that anyone could understand.

I’ve come a long way since then.

I once felt that writing short, clever code was the proof of my superior coding ability.

But what value is short, clever code that nobody understands?

People are usually the most expensive part of any IT system, so we should optimize for people’s time.

This means writing readable code, rather than clever code.

This usually means writing readable code rather than efficient code.

The same principle applies, of course, to non-code artifacts as well. Config files, diagrams, documentation. Optimize for readability.

Readability should usually be the first priority in any technical artifact you write. Of course there are exceptions, and I’ll talk about some of those in the coming days.

It’s harder to read code than to write it.

— Joel Spolsky

Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. …[Therefore,] making it easy to read makes it easier to write.

— Robert C. Martin

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

— Martin Fowler


If you enjoyed this message, subscribe to The Daily Commit to get future messages to your inbox.

Top comments (8)

Collapse
 
matthewpersico profile image
Matthew O. Persico

Wouldn't comments solve the problem? That's what I do in my Perl: you need to grok what map and grep so, but if I stream a bunch of them together, I'll use whitespace and comments to clarify what's going on.

Comments allow you to use the more efficient code and also to "teach a man how to fish". Why do we insist on dumbing down languages instead of smartening up programmers?

Collapse
 
jhall profile image
Jonathan Hall

Comments are a really bad way to solve this problem, because comments are easily ignored, easily separated from the code they reference, and frequently fall out of sync.

Good code should be easily read and understood without comments. If you need to explain your code with comments, it means your code is confusing. As I've written before: Comments are like appologies to the next programmer: jhall.io/archive/2021/02/14/commen...

There are of course appropriate uses for comments. But they should almost always explain the WHY of code, not the HOW of code.

Collapse
 
davebaird profile image
Dave Baird

It depends. There's a tension between the number of bugs in code, and its readability. Powerful languages like Perl allow you to get more done in fewer lines, and that's a Good Thing. Bugs are proportional to the number of lines, not the number of things those lines get done. So powerful, correct code is terse. Readable, verbose code is buggy.

So there's a judgment call. If I write something that's powerful but terse, and I don't want to expand it into a buggy monstrosity of nesting and logic, I'll add a comment that documents not the WHY or the HOW but the WHAT. Nine times out of ten I'll put it into its own subroutine. I write lots of very short subroutines. Then the subroutine name becomes the comment. I write long subroutine names!

My own guideline for when to make the judgment call is if the terse code is readable for an experienced programmer, I'll keep it, possibly with added comment or broken out into its own sub. If an inexperienced programmer would need to puzzle over it, well, that's part of becoming an experienced programmer. But if even an experienced programmer would need to puzzle over it, then it's gone too far down the terse plughole and needs to be broken out a bit.

TL;DR write self-documenting code, but don't be shy to show your chops.

Collapse
 
jhall profile image
Jonathan Hall

Aside from that, readability is not primarily about reducing bugs (although it may help with that). It's about reducing the cognitive burden to understand the code. It's about optimizing for developer time over machine time.

My rule is to optimize my code for the least experienced developer who is likely to need to understand it. For most projects, that usually means optimizing for people with bootcamp graduate level understanding. In some cases, it's fine to optimize for "experienced programers" (whatever that means in context).

Collapse
 
jhall profile image
Jonathan Hall

I'd love to see some reference for your claim that "Bugs are proportional to the number of lines, not the number of things those lines get done. So powerful, correct code is terse. Readable, verbose code is buggy."

Collapse
 
davebaird profile image
Dave Baird

There's a good discussion here - mayerdan.com/ruby/2012/11/11/bugs-...

And some more sources here - stackoverflow.com/questions/289857...

Nothing is ever absolute, readability vs terseness is a trade-off. But my point is that readability is not as clear a win as people assume. If you are asking your best developers to write to a standard that is easily understood by your least experienced developers, then the benefits you gain from making life easy for beginners are costing you by reducing the efficiency of your best developers, and by introducing extra bugs because of the extra lines of code.

Thread Thread
 
jhall profile image
Jonathan Hall

Thanks for the links.

I don't see supporting evidence for the claim in those links.

What I do see, from SO (and referenced in the other):

  • The claim that the defect rate per LOC is roughly equivalent across languages. This appears mostly to be speculation, not actually substantiated by evidence--unless you consider several orders of mangitude your margin for error, which makes one wonder why bother with such a claim?

In the Mayer piece:

  • A conflation of two important concepts: readability and simplicity. That is, he claims that making the code "less readable" made it less error prone, when in reality, what he's describing is refactoring the code to be simpler. The conflation is best summarized in this quote: "I think so many incredibly smart engineers who enjoy the beauty of code move from writing verbose ‘readable’ explicit code with big objects and reusable modules, to condense and succinct but powerful code. Often favoring simpler objects, relationships, and data structures."

He appears to be making the claim that "long, verbose, duplicated, over-abstracted" code is more readable. I disagree. Of course "readability" is subjective, so if someone thinks that muddling through extra abstraction layers is "more readable", then I guess I can't argue with thier opinion.

Then he goes on to explain how they reduced cognitive load by simplifying the code.

To me, reducing cognitive load is the practical definition of making code more readable.

So I think he and I are advocating for the same outcome, but with different terminology. And IMO, his terminology is confusing, if not backwards.

Now all that said, I'm still doubtful of your claim that terser code inherently leads to fewer bugs. But I can't say conflusively that you're wrong, either. It certainly seems counter-intuitive, but then the best ideas often are.

I'll need to see more data.

Thread Thread
 
jhall profile image
Jonathan Hall

But let me ignore all that for a moment, and take your argument at face value, and assume that more readable code == more verbose code == more bugs.

This would naturally lead to a balancing act. Not much different from the trade-offs often made between "readability" and "performance".

I would still tend to weigh readability higher, for the parts of code that change frequently, because they are read the most often.

So I don't think this changes anything fundamentally. It may tilt the scale slightly toward less readable code on a few edge cases. But I don't think much.

It would really depend on how much your code bloats by making it "readable". Let's say, turning a 1,000-line function into 10 100-line functions. This will probably bloat the code by, say, 5%, for the extra function calls.

Is a 5% increase in bugs worth it for code that's easier to read, reason about and, ironically, debug?

Of course it depends on particulars. But in general, probably it is, I expect.