Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. Code for readability.

- Martin Golding

Many coders have run across this statement and dismissed it as a bit of folklore, but it rings true. You will almost certainly never be the only person to look at code you've written. Even if that time is many months or years down the road, you owe it to future developers to write code that is easy to read, even if the logic behind it is complex.

Inevitably you will run into people who say "who cares, my code works, that's the bottom line, right?"  Well, yes and no. Of course your code should work -- even the most beautiful code is rendered ineffective if it contains a crippling bug. Unless you're coding in a vacuum though, you or someone else will have to look at it again. If you can't understand what's going on because the code is written poorly you are costing yourself (and likely your clients) time. You also increase the chances of introducing bugs and/or syntax errors which further slow you down. Not good.

So how do we get the job done and still have readable code?

Use a Sensible Indentation Scheme

This one might seem obvious, but you should choose an indentation scheme that makes sense and stick to it. Typical schemes include hard-tabs, two- or four-space soft-tabs, or whacking the space bar a couple of times. Whichever method you choose though, be consistent. Being able to vertically scan a section of code and see where indentation levels match levels of code is extremely useful.

Maintaining consistency is easy if your editor of choice supports a macro or keybind so that indenting is reduced to a single keystroke. Hard-tabs are already done for you. If you go the soft-tabs route, set your editor to use your chosen number of spaces whenever you press Tab for maximum convenience. Indent each code block or logical function so that things visually line up.

Block Separators

Where you place block separators is entirely up to you, but again be consistent. For example, both of the following are acceptable:

while ($condition) {
    # code
}

... or ...

while ($condition)
{
   # code
}

If your language of choice allows it, you should also do this for function calls with significant numbers of arguments, such as:

my $result = super_awesome_function(
    color => 'red',
    awesome => 1,
    frogs => [ 'out', 'gonk' ]
);

You might have noticed a tendency to avoid long lines here. This is intentional. One stat often trotted out is that "stock" terminal windows are 80 characters wide, and therefore you should not go over this for a single line of code. That's a good starting point, but instead try to think in sensible chunks. If you have a long string being passed in as a function argument, then don't sweat having that wrap the terminal window. Just don't put all your arguments on one giant line. That's hard to read, and difficult to deal with.

Crack the Whip Now and Then

So you're doing your best to write consistently readable code, with a sensible indentation scheme and well laid out lines. Your project grows and a couple junior developers come on, and let's say they're not quite as consistent as you are. Consider using a style enforcement tool on your code to keep things in line.

Perltidy is a good example. JSBeautifier is handy to drop blocks of JavaScript into. Other languages have their own, and if you use a GUI to code, consider using one that auto-indents for you so you don't have to worry about it. You can get creative here too -- source control programs like SVN support commit hooks which could auto-prettify your code before check-in, or you could set up a cron job. The idea here is that once you embark down the road of maintaining a readable codebase, try your best to stick with it. Use tools to your advantage.

Use Descriptive Variable Names

Large blocks of code with variable names like, $x, $y, $thing, $o, will certainly work, but give very little insight into what's actually going on. You should use variable names that describe the type of value being stored.

So instead of these:

  • $res
  • $c
  • $rv
  • $o

Use these:

  • $reservation
  • $row_count
  • $return_value
  • $customer_object

This will make your code significantly more readable and provide in-line, semantic hints when tracing logic.

Similarly, if your language supports implicit function arguments and loop variables, avoid these. For example, in Perl, the following doesn't tell you much.

foreach (@stuff) {
    $_->do();
}

But this does:

foreach my $record (@customer_records) {
    $record->process();
}

It should always be easy to tell what's going on, and what is being acted upon, implicitly. Non-obvious variable names that are used consistently across your application are fine as long as this is well-documented. For example you might want to use $c for a database connection handle to save typing, or $u for a user object. Shortcuts are fine as long as everyone speaks the same language.

Use Natural Language for Subroutine Names

Similarly, your subroutine names should describe the actions being taken as descriptively as possible. This helps to not only segment program functionality, but to find relevant functionality when enhancements need to be made. Consider the following code:

foreach my $record (@customer_records) {
    $record->verify_eligibility();
    $record->process_enrollment();
    $record->check_for_and_process_errors();
    $record->finalize_and_archive();
}

It is very easy to follow exactly what's going on there. No functionality is hidden behind obscure subroutine names, and each action being taken on a customer record is clearly defined. If business rules change, for example, requiring additional customer data before enrollment, it's clear where something like $record->populate_secondary_customer_data() would have to go.

Making defined breaks like this also helps with proper code design -- you wouldn't put archiving code in $record->process_enrollment() for example, but you might be inclined to do so if it were simply named "process."

Write Code Comments for Non-Obvious Things

Very often, as we're in the thick of things, we write complex bits of code that seem perfectly fine, but turn out to be incomprehensible blocks of logic later. You should get into the habit of writing code comments for each logical chunk of code unless it's painfully obvious what's happening. Adding comments to your code costs nothing, but improves the readability of your code considerably. Don't go overboard though. Too many comments will clutter your code, and can actually have a more serious drawback -- teaching your colleagues to ignore your comments. It's sort of like the alarm that keeps going off and just gets acknowledged without being looked at. When developers are routinely forced to wade through lots of unhelpful comments, they'll miss the good ones. Quality over quantity is the rule of thumb here.

You should definitely comment in situations that seem obvious but have their roots in non-obvious business logic. Yes, we can see that you're adding a dollar to the transaction charge on Fridays. But why? Document that business logic; maybe the client has a specific need to do so that won't be so obvious later on.

Know When To Write Many Smaller Statements Instead of One, Huge One

This one is a particular problem in languages like Perl that make it easy to chain many things together using implicit parameters into one monolithic statement. Consider the following code.

my @result = grep { $_->{priority} > 2}
map { { priority => get_priority($_->id()), customer => $_ } }
grep { $_->last_name() =~ /^H/ } @customers;

Basically, we're looking for all customers with a last name beginning with H, who are at priority level 3 or higher and jamming this into some temporary struct. This works great -- but the following is much easier to read:

my @customers = subset_customers('last_name', 'H', @customers);
my @result = find_customers_at_priority(3, @customers);

Now you can hide the complex logic inside your utility functions, and the main program flow is much easier to follow. This is marginally slower to execute given we're storing results and making subroutine calls instead of passing through transient loop variables, but the gain in readability outstrips the loss.

Why You Should Do All of This

Writing readable code makes you a better team player. The next person who picks up your code will be able to tell what's going on, how your design flows, and will know the reasons behind any tricky bits. You'll reduce ramp-up time and the inevitable "what's going on here" questions. Consider that if the next person on your project can't figure out what's going on, they're probably going to call you and make you help. It's in your best interests then to make sure that doesn't happen.

And remember: the violent psychopath who comes along next just might be you.