The Captain Obvious guide to writing readable code

readable

This blog post details some tricks of writing readable code at the code file level. There may or may not be a follow up post talking about ways of organising your code at higher levels to make it more understandable.

As coders we spend a lot of our time reading code. More so than writing it sometimes. Well written code helps us in this task as we have to spend less time trying to figure out things that are obscured by the writing style and can concentrate on the higher level tasks at hand. Unfortunately it’s not the easiest thing in the world to write code in a style that’s easy to read. There are even books on the subject, notably Clean Code by Robert C. Martin. You can go ahead and read his book, it’s a good book. But in the meantime I’ve written some possibly helpful stuff which you are welcome to read if you wanna.

I gotta warn you that this is my opinionated take on a few rules for how to write readable code that will get you 80 percent of the way there without too much effort. Opinionated means I get to say stuff and not back it up because “It’s just my opinion maaaan”. It also means you get to disagree and we can fight a holy wa-… er… and that’s perfectly OK.

Readable code means… code that is easy to read. It means that it must read like reading a book. It must be easy for the reader to understand. In support of this goal, we need understand what humans are like.

  • Humans have a short attention span.
  • Humans don’t deal well with complexity.
  • Humans don’t deal at all well with multiple levels of complexity.
  • Humans can hold only a few things in their minds at a time.

Remember, you might be the person cursing yourself in six months time if you write something horrific and then have to track down a bug or do some other maintenance. Save yourself the effort and write something nice so that your future self can feel proud. I say this as a guy who has frequently cursed myself for past coding shortcuts and “clever ideas”.

Rule 0: Don’t be too clever

You can’t debug code that’s too clever. If you write code that’s clever, you have to be even more clever to debug it. If you write code that pushes the limits of your cleverness… you won’t be able to debug it. You know that ultra awesome one liner of boolean logic which perfectly captures the condition, updates the variable and launches the spacecraft? Don’t do it. Use a few more lines of code. Someone else or probably you is gonna have to figure out what you did a few months or years down the line. C and related languages allow you do do all kinds of bit-twiddling tricks and they can be extremely clever and even useful, but they can also be mind-bending and as coders we don’t want our minds bent.

Name things carefully

Your primary tool for communicating with your reader is the way you name things. Names need to reflect the purpose for which they are used. Boolean variables should have names using words like is and has to show that they reflect logical conditions. Functions should be named according to what they do like this: database.save(employeeRecord).

Sometimes especially with things like database tables people get clever and decide to reuse a name that was previously used for something else. DO NOT DO THIS. Future readers will waste valuable hours of their time figuring out the lies that you are telling in your code.

Use the correct brace style

I’ve mucked around with a few languages now and I’m dead convinced that there is only one true brace style which is like this:

void doSomething()
{
    // the users of other brace styles are infidels
}

You have to be able to match braces at a level of indentation. If you avoid too many levels of indentation then you can indeed work with a more disgusting style like this:

void doSomething() {
    // this brace style is bad and you should feel bad
}

But it’s adding needless complication to your life. What do people do this for anyway? I can’t understand it. You save one meaningless newline in exchange for making your code more unreadable. tanya rivera verizon Nevertheless some languages even go so far as to require this style, presumably because their designers are horrible people who want everyone else to be miserable.

Use comments judiciously

Some coders don’t like comments because they go “stale” – in other words the comment becomes obsolete when the code changes because no one bothers to update it. The issue is that with most other aspects of coding the code won’t compile if you’ve stuffed it up sufficiently, but comments are not like that. I think comments have their place. cost of ivermectin in the philippines You just gotta be professional about it and make sure that you change them if the code changes. The key thing is that a comment must aid the readers understanding. stromectol® If it doesn’t do that, delete it. Also, you can avoid a lot of comments by writing obvious code in the first place.

First some things not to do:

Don’t just make a comment that says what the code is doing:

// make something
var something = makeSomething();

Don’t comment out large chunks of code and leave them commented out in the codebase. It’s fine if you’re commenting stuff out in testing or whatever, but DO NOT keep commented out code in the codebase. They just make things hella confusing for later readers.

void doSomething()
{
    // see how the comment below is confusing? That's why you never 
    // commit commented out code
    int count = getCountFromUser(); // = getCountFromDatabase();

    // the rest of the function
}

The best write up of comments I’ve come across so far is here. The summary at the end is:

  • At the library, program, or function level, use comments to describe what.
  • Inside the library, program, or function, use comments to describe how.
  • At the statement level, use comments to describe why.

Refactor your code into short, descriptive functions (with few parameters) that do one thing only

You’ve got some monster function that does a thousand things. Reads from a TCP connection, writes to a database, validates incoming data, returns error messages, logs exceptions, processes valid data and spits out a response.

Split the function into lots of little ones, even one line functions, with appropriately chosen names to show what you’re doing. You can keep the original function except that now instead of doing everything inside it you do each sub-task in a private function.

The general rule is: don’t write functions longer than about ten lines. One line functions are OK, they’re even to be encouraged. Just keep the end goal in mind – improved readability.

If you have to pass a monstrous list of arguments to a function, consider making an object to hold them all and passing that. But in general a large number of arguments in your function indicates that something is wrong and is a code smell.

Use guard clauses

In general, avoid multiple return statements in your functions. There are times when code with multiple returns can be more readable, just use your judgement. But in general, avoid it. There is one situation where it is good to use multiple returns though, and that is when you use guard clauses.

Consider this:

void doSomething(int count)
{
    if (count >= 0)
    {
        // do something with the count
    }
}

Compare it to this:

void doSomething(int count)
{
    if (count < 0)
        return;

    // do something with the count
}

The second way is better because you avoid an unnecessary level of indentation.

Don’t use multiple levels of indentation

Often you see multiple levels of indentation in a function – something with validation, a bit of logic and some loops can easily get complex – rather split it into smaller functions. The general rule is that everything in a function should be at the “same level of abstraction” somehow.

Use whitespace to break up large blocks

My general rule is that every three to five lines there must be a line break. It sounds stupid, and if you just apply the rule without thinking then it is stupid, but if you group logically related things together then it can dramatically improve the readability of your code.

For instance you often see classes with huge initializer lists like this:

    var foo = new Submarine
        {
            name = "Bar",
            cost = 1_000_000,
            length = 400,
            submariners = 20,
            captain = "Obvious",
            periscope = false,
            torpedoes = 4,
            topSpeed = 5,
            color = Color.Yellow,
            // even more properties etc
        }

If you break up the list into logically related groups it makes it easy to see what’s going on:

    var foo = new Submarine
        {
            cost = 1_000_000,

            // physical attributes
            name = "Bar",
            color = Color.Yellow,
            length = 400,
            topSpeed = 5,

            // crew
            submariners = 20,
            captain = "Obvious",

            // optional extras
            periscope = false,
            torpedoes = 4,
            // even more properties etc
        }

Conclusion

Well, that’s it. It ain’t rocket surgery. Feel free to disagree with all or part of it. I think a lotta this stuff is sort of personal. It takes years to absorb some lessons, to experiment and see what works for you.

About the Author