NeverSawUs

Towards Readable Code

A friend of mine came back from a local user group a few days ago and described a talk to me about a particular design pattern. One of the properties lauded about this pattern was that it made code more readable than an alternate pattern. A strawman of the other pattern had been presented for the purposes of comparison. As the presenter intended, the strawman was less readable than code using the pattern.

There's a secret to readability, though.

It's not tied up in patterns — though it can be related to them. Using a pattern does not automatically increase readability: a book solely comprised of idioms would be unreadable. Patterns, like idioms, can aid understanding for those "in the know" when used appropriately. Attaining readability in code is a far simpler process then picking the correct idiom in the correct location.

So, how do you write readable code?

Slow down.

The number one way to make your code more readable is to slow down when you're writing it. It feels great to fly through a problem — to go from point A to point B as quickly as possible, using whatever tools are at hand — but it rarely, if ever, leads to readable code.

I've found this to be true in all languages I've used; but the relation between ease of writing and ease of reading is especially bad in a few. JavaScript is most certainly a language that bears deliberation: it can be very expressive, and using all of that power usually results in code that's too clever by half.

You've probably seen this before (or written it yourself!); a function that declares a variable, and sets its initial value to the result of a multiline IIFE, and goes on to do some other work.

function contrivedExample(input) {
  var lines = (function() {
    var output = [];
    var idx = 0;
    while((idx = input.indexOf(0)) !== -1) {
      output.push(input.slice(0, idx));
      input = input.slice(idx);  
    }
    return output;
  })();

  // real code continues below...
}

When you're moving quickly, you want the input in the shape it should be, and the quickest route to doing that is to slice it up in-place. Is that the most readable route, though?

Build a Theory.

Read code — other projects, your code from a year ago, code with different style guides, etc. Don't just read "good" code, read a lot of code. Keep track of where you're pausing to try and understand what's going on. Try to form a hypothesis about what's making your code hard to read. Make it testable. Write code that attempts to prove or disprove your hypothesis. For best results, don't re-read that code until a few days or weeks later. When you go back to it, keep your hypothesis in mind.

Lather, rinse, repeat — this process takes time, but after a while, you'll have a pile of proven and disproven hypotheses: you can build a cohesive theory about what readable code is to you.

For example, over time, I noticed what most often slowed me down when reading JavaScript was trying to determine what variables an anonymous function was using in scopes (vs. what it had available to it). My hypothesis was that if I avoided closing over variables unnecessarily, my code would be easier to read. Months later, when re-reading files written with this in mind, I didn't have to pause to consider what variables a given function has available.

Have Discipline.

Have discipline when you're writing code. Keep the theory you've built up in mind at all times. It will always be tempting to take the easier route — to write code like we saw before — to get through with the problem quicker. When you feel tempted, remember that the amount of time you spend writing the code is a pittance compared to the amount of time that code will be read by other humans — a glass of water compared to an ocean.

If what you just wrote works, but it isn't obvious, throw it away and try again. If it works, but violates your personal theory of readability, clean it up now.

Resist the urge to use comments to explain what's going on. They're a poor proxy for that information — at best they're a copy of what's going on, and at worst they're an outright lie. Comments are for when the code is unavoidably surprising, not for use as a crutch to make your code make sense.

Remember, it's possible to make the best pattern unreadable; to write code that lints correctly but is unassailably confusing; to take well-intentioned tools and compose something horrible out of them. You can't cede the responsiblity of writing good code to a library, a linter, or a pattern. These tools can help you, but ultimately it's up to you to have an opinion, and see it through.