DEV Community

Cover image for Readable Code
Gergely Orosz
Gergely Orosz

Posted on • Originally published at

Readable Code

Good code needs to meet two key requirements. First, it should be correct: when executing, it should produce the result that is expected. Second, it should be easy to read for other developers.

Coding is a social activity. Your code does not exist in a vacuum, just implementing a lone task. The code you write will be re-read by many other developers, who want to either understand or modify how your code works.

Why readable code matters

Why is readability so important? It's because checking if the is correct is relatively straightforward. Unit tests are excellent ways to do this, but manual tests or monitoring the system also help catch incorrect code.

While incorrect code cannot hide for long, unreadable code can go undetected for a long time. It keeps silent in the codebase until another developer comes along and tries to understand what the code does. They might be trying to fix a bug or adding a new feature. They might want to understand what this unreadable piece of code does and perhaps also need to change it.

When the code is not readable, the engineer changing the code next will burn a lot more time on what should have been straightforward work. They might misunderstand the code and use it in ways it was not meant to be used. They will then spend multiple iterations getting the change right. Or they might change the code, unintentionally breaking functionality elsewhere. If there are automated tests for the breaking functionality, this is only a minor annoyance. If there are no tests, this will lead to more problems and more time spent on making this change correctly.

In some cases, the other developers might spend so much time, failing to understand the code, that they might completely rewrite it: deleting the original code and writing a new implementation. Of course, when rewriting something completely, perhaps not all edge cases will be covered. This will result in more time spent on the rewrite than the time it took to write the original code.

The biggest risk that non-readable code brings is that it starts a pattern of poor readability. The engineer making a change burns a lot of time to figure out how the code should work. Instead of making the code more readable, they make the smallest possible change possible, resulting in even less readable code. And the person coming next will spend even more time understanding the code, unintentionally breaking the system, or just giving up, deleting the code and rewriting the whole thing.

Non-readable code is a large contributor to technical debt. While tech debt can build up for a variety of reasons - a lack of automated testing, lacking processes like CI or CD or poor onboarding and documentation - non-readable code is a major driver of the tech debt that slows teams down.

Readable code, together with well-tested code, are the two most important principles that pragmatic engineers follow. Readable and well-tested code is what makes refactoring, extending, and modifying parts of the system straightforward. Readable and well-tested code is the foundation of a solid codebase, where engineers are confident and quick to make changes.

What is readable code?

Readable code will mean slightly different things to each person. It varies between teams, companies, and programming languages. There are two groups of important people who are judges of how readable the code is: yourself and everyone else who will later read the code.

Readable code starts with code that you find easy to read. When you finish coding, take a break to clear your mind. Then try to re-read the code, putting yourself in the mindset that you know nothing about the changes and why you made them.

Can you follow along with your code? Do the variables and method names help understand what they do? Are there comments at places where just the code is not enough? Is the style of the code consistent across the changes?

Think about how you could make the code more readable. Perhaps you see some functions that do too many things and are too long. Perhaps you find that renaming a variable would make its purpose clearer. Make changes until you feel like the code is as expressive, concise, and pretty as it can be.

The real test of readable code is others reading it. So get feedback from others, via code reviews. Ask people to share feedback on how clear the code is. Encourage people to ask questions if something does not make sense. Code reviews - especially thorough code reviews - are the best way to get feedback on how good and readable your code is.

Readable code will attract little to no clarifying questions, and reviewers won't misunderstand it. So pay careful attention to the cases when you realize someone misunderstood the intent of what you wrote or asked a clarifying question. Every question or misunderstanding hints to opportunities to make the code more readable.

A good way to get more feedback on the clarity of your code is to ask for feedback from someone, who is not an expert on the codebase you are working on. Ask specifically for feedback on how easy to read your code is. Because this developer is not an expert on the codebase, they'll focus on how much they can follow your code. Most of the comments they make will be about your code's readability.

If both you and other developers are happy with how readable the code is, you're on the right track. Many principles can help the code become even more readable and more clear. But before you go too deep on these, focus on what matters. Focus on the code being easy to read for you, and for the people you work with.

Principles of readable code

There are numerous principles on what readable code is. For me, readable code means following these principles.

  • Single responsibility. All building blocks - classes, methods, variables - follow the single responsibility principle: every building block does exactly one thing. This makes it easy for the person reading the code to understand what this responsibility is. It also makes it clear what part of the code needs to change.
  • Well-structured. The codebase is easy to navigate around, as functions, classes, modules follow a logical structure. Formatting is consistent across classes and the codebase.
  • Thoughtful naming. Class, function, and variable names all help understand what is happening, and making reading more seamless. Code that has good names often had developers spend multiple iterations coming to these clear names.
  • Simple and concise. The code tries to be as humble and simple as possible. Developers don't use fancy tricks and also avoid over-complicating things. Functions are mostly short, making them easy to read. Classes are also not overly large.
  • Comments explain the "why," not the "how." Most of the code can be understood by itself. Comments fill in the remaining gaps.
  • Continuously refactored to keep being readable. Codebases grow. As a simple class gets more responsibility, it grows in size and complexity. Readable codebases stay readable due to continuous refactoring. The new, complex class might be broken into multiple parts or changed other ways to stay easy to read.
  • Well-tested. Well-tested code can be modified quickly and without fear of breaking things. Having the code tested via automated tests is important for the code to stay readable. Without tests, refactoring the code becomes risky, and developers eventually stop doing it. With tests, there is no excuse on why not to make even large and risky refactors, that keep the code easy to read.

There are many great books and other resources that go into far more depth on what readable code is and ways to make code more clear. I especially recommend the books The Art of Readable Code and Clean Code.

What does readable code mean to you?

This article was originally posted on The Pragmatic Engineer Blog

About me: I'm an engineer turned engineering manager, working at the intersection of Silicon Valley & European startups and tech companies. Follow me here and on Twitter. I am writing a book on growing as a software engineer - read more about it and sign up for updates on it here.

Top comments (7)

tomazfernandes profile image
Tomaz Lemos

Great article! I agree with all the principles you describe, and I would add that for me readable code is also code that makes it easy to figure out what the business rules are, as the code itself is merely a representation of them.

Usually understanding the code language is not hard, the greater difficulty is understanding the purpose of a particular piece of code and what part of the domain it represents, so I can figure out easily what to change.

Perhaps another good measure of non readable code would be when you need to think like a compiler just to figure out what a piece code does, and after a while cracking it you realize it has nothing to do with what you needed in the first place.

vlasales profile image
Vlastimil Pospichal

What is "Thoughtful naming"? Short and simple or long and complex? My base of naming is one word, sometime two words. No longer.

ghost profile image

To me "Short and simple or long and complex" is like asking how long should a program be, depends, the main purpose of a name is clearly indicate what it is/does, second is how long; the name should be as short as possible without losing it's main goal. Restrict oneself with artificial rules seems useless to me, the amount of chars or words are not the purpose of a name.

I usually make a stupid long name and then ask myself, and start iterating, can I shorten it while keeping understandable? when the answer is no, that's what I keep. If the end result is inconvenient (too long and used too often) maybe there is a deeper problem in my code.

gergelyorosz profile image
Gergely Orosz

Good question. In my opinion, the easier to understand the purpose, the better. For the most part, this would mean simple & short.

But it depends on the codebase and domain. E.g. in a large codebase following agreed on architecture principles on using e.g. viewcontrollers and the concept of interactors, the name RootViewControllerInteractor could count as a good name. Or in an accounting domain, EndOfYearCalculationController could also be a thoughtful name.

My point is to put thought to come up with clear names that make sense to you and other devs who will work on the same codebase.

vlasales profile image
Vlastimil Pospichal • Edited

I use namespaces for split words, Interactor\Controller\View\Root, Calculator\Controller\EndOfYear etc. Nouns for things, verbs for methods, adjectives for interfaces.

Two words in a method name shows violation SRP.

vlasales profile image
Vlastimil Pospichal

Of course, broader the scope, the longer my names become. But... Demeter's law tell me, talk with friends. Creating a thin scope is my way.