When you start a career in IT (or even before, as you approach coding interviews), you are told that writing “readable” code is the most desirable technical skill you will ever have.

But no one can tell you what a readable code really looks like. Some authors have list of rules, and if your code matches their specific set of rules, it’s deemed “readable”.

In everyday practice, it comes down to a mix of company code style guidelines, usually designed by senior developers according with their experience, and the aesthetic taste of the person reviewing your code.

In general, this works well enough. A set of simple and clear rules sprinkled with a bit of personal taste acquired from experience can go a long way. But still, it’s sort of unclear where the rules come from and why.

In the course of my career I have encountered conflicting code readability practices in different companies. For example, keeping the size of a line within 80 characters in one, and within 120 in another; or (sensibly) abbreviating names in order to fit expressions in one line versus having verbose, sentence-long names; or again, writing helper functions to reduce the size of large code blocks versus having the relevant code all in one place.

So, in some cases, code considered “excellent” for a set of developers would look “unreadable” to others.

Can there be a metric to determine the readability of code beyond consolidated practices and personal taste?

I think I found it, and in this series of articles, I am going to share it with you: I call it the principle of minimal incompleteness.

Minimal incompleteness means that the things you need to keep track of before you can make sense of something must be as few as possible.

In other words, the less incomplete pieces of information you need to know before having a complete picture, the better.

This is a general principle about how our brain works. The readable in “readable code” actually means understandable. To understand a complex concept, and code certainly is, we must process multiple information. A concept is simpler if it requires to keep track of less information before it all comes together to finally make sense.

Now, for an exercise, let’s get a good “code readability checklist”, and let’s see how it’s related with the principle of minimal incompleteness.

This checklist comes from codegrip.tech, and it’s a fairly basic yet solid one.

  • Indent code depending on its nest level: by indenting the code, we give a visual hint on how the code is meant to be processed. Without it, we should keep track of the latest branch, loop and function in the code that we encountered; we would need to remember more incomplete information before the code we’re looking at can make sense.
  • Add comments: comments remove the need for the reader to do extra guesswork and figure out what a certain piece of code is doing and/or why. Such guesswork may require many pieces of incomplete information, and the comment obviates the need to search for them and then retain them all before the code can be understood.
  • Code Grouping: grouping similar operations together will remove the need to guess each time what each operation is about. Without it, we’d need to keep track of each different operation before understanding it, but if all similar operations are grouped, we can assume they all have similar behaviour and results to the first one. So, we have more complete information right from the start.
  • Use the Do Not Repeat Yourself (DRY) principle: each time a piece of code is repeated, a reader needs to look out for differences, and when found, understand their significance. So, each repetition increases the amount of incomplete information the reader needs to deal with.
  • Using “good names”: according to CodeGrip, good names are self-explanatory, including verbs that explain what a function/method is meant to be doing, avoiding ambiguous abbreviations, and separating different words with camelCase. Each of this choices could be separately analysed, but in general, it’s easy to see that each of them reduces the amount of incomplete information the reader needs to deal with when encountering new entities in the code.
  • Avoid deep nesting: As a nesting scope is opened we need to have some idea of what preceded it, and as it is closed, we need to go back and recover the information that was still incomplete. The more a piece of code is nested, the more information we need to keep track of.
  • Horizontal formatting: if lines are too long to fit on a screen, there will be some part of the code not immediately visible as we scroll around. It could be the indentation level, or a crucial piece of code that just slid off. At any rate, that may increase the amount of incomplete information that needs to be remembered while not looking at it.

So, we can see that every recommendation in this list is born out of the need to remove incomplete information each step of the way.

How can the principle of minimal incompleteness help us in our everyday work?

Each time you are writing or refactoring a piece of code, just ask yourself, “how much context must be kept in mind to understand what this piece of code is doing?”

If you can remove one hidden information, one untold assumption, one additional statement after a sequence that is already long, this reduces the local incompleteness of the code, and makes it more understandable.

This principle also comes handy when designing or adopting company-wide code style guidelines.


Since a computer program is an expression written in a formal language, and given that we have a solid theory linking formal languages and information content, I think that it would be possible, in principle, to quantify the average local incompleteness of any program.

In other words, I think it’s possible to write a static analyser to score the readability of any code.

But that’s material for another story. In this one, I have introduced the concept of minimal incompleteness as the base for writing good code. In the next articles, we’ll discuss how this concept is applied to various elements of modern software development in general, and in C++ development in particular.