How to Write Readable Code

How to Write Readable CodeEric DamtoftBlockedUnblockFollowFollowingJun 14Avoid Code That Looks Like This — Photo by Markus Spiske on UnsplashOne of the best classic pieces of advice for developers is to write your code as if the next person to maintain it is a violent psychopath who knows where you live.

Having occasionally been both the person to write unreadable code, and the person to have to sift through a pot of overcooked spaghetti code, I can’t agree with this more.

Readable code is code that’s easy to comprehend, quick to scan, and simple to maintain.

Here are some concrete tips I’ve found to help a future developer (or a future you) understand what you’ve written.

The examples below use C#, but the concepts will work in any language.

Comment Why, Not WhatComments are useful, but comments should describe why you choose to do something, not express a human-readable explanation of the code.

Only programmers will be reading your code, and programmers (hopefully) already know how to read code.

If you need lots of comments to explain what it’s doing, it’s probably not well factored.

Also, when changes are made, these comments are often not updated, leading to comments which are simply wrong.

The hardest part of combing through legacy code is often trying to figure out why a past developer made a particular choice and if it was deliberate or not.

Unit Tests Are The Best DocumentationAs a follow-up to that, unit tests are good for lots of things, but acting as documentation is one of the most important.

Unit tests capture the intent of the code, the expected use cases when it was written, and as long as they’re run regularly, they’re practically guaranteed to be up-to-date which is often the downfall of other documentation methods.

Write your unit tests as if you’re explaining to a future colleague how your code works.

Avoid Re-AssignmentThis isn’t a hard and fast rule, but something to think about when writing code.

Consider the following example:public string Example(string input){ input = input.

ToUpper(); input = input.

Substring(0,10); return input;}After the first line of code, “input” no longer properly describes the variable.

Once you have a few more lines of branching and mutations, you can’t look at any given line of code and tell what the variable actually represents.

Without this critical context, you have to understand the entire method instead of being able to scan a few lines of code and know what they are doing.

Instead, try something like:public string Example(string input){ var capitalized = input.

ToUpper(); var truncated = capitalized.

Substring(0,10); return truncated;}Obviously in this simple scenario it’s overkill, but you’ll find that by generally trying to avoid re-assignments, you’ll also end up factoring your code to reduce it’s complexity and improve clarity.

Always Write An InterfaceInterfaces provide a “contract” for the way the world will interact with a class.

Even if there’s only one implementation, writing an interface forces you to define what a class does and what its responsibilities are.

This way, by looking at a class’s definition, you will always be able to tell both what it is and how it’s meant to be used.

Break Out Switch StatementsThis is mostly just a style choice, but switch statements are complex by nature so anything you can do to improve it’s readability can help.

By breaking out switch statements and simply returning a value from each case, it ensures they are concise and avoid common mistakes like forgetting to add a default case.

Consider the following example:public void Example(int value){ var word = ""; switch (value) { case 0: word = "zero"; break; case 1: word = "one"; break; case 2: word = "two"; break; } Console.

WriteLine(word);}Breaking the switch statement out into a separate method reads much more cleanly, and the behavior for a default case becomes more clear:public void Example(int value){ var word = GetWord(value); Console.

WriteLine(word);}private static string GetWord(int value){ switch(value) { case 0: return "zero"; case 1: return "one"; case 2: return "two"; default: return ""; }}Name Parameters When It’s Not ObviousWhen you’re passing a constant value into a method, it can be hard to tell what that value means.

C# lets you optionally name parameters, and doing so can add a lot of clarity.

Consider this example:FetchValue(true); // What's True?versus this:FetchValue(withExtraData: true);In the second example, we can instantly tell what the Boolean parameter does and what it represents in an instant.

You can always go to definition and see what a parameter does, but our goal is to make it easy to scan through code and understand it at a glance.

ConclusionThese tips, like the pirate code, are more guidelines than rules, but I’ve found these practices to be helpful for writing code that’s readable and easy to maintain.

Consider what you can do to make it easy to scan through code and understand it at a glance and the next person working with your code will thank you.

.

. More details

Leave a Reply