Writing code, as in many other forms of communication, comes with a challenge of clearly expressing thoughts and ideas into a limited set of words. Quite often we envision the end-goal but the process of translating that vision into words does not always lend itself nicely. Moreover, it gets more complicated when consideration is given to not only what was communicated but how it was conveyed as well. In this essay, we explore ways object oriented languages have addressed this challenge and how developers can leverage these building blocks to increase readability of their code.
Before we get started, note that we specifically referred to programming as a communication form. Take a minute to let this sink in, because it’s going to be very important moving forward. Back…? Good. Now, this communication takes place among three parties; there are the original programmer, the machine, and the future programmer. As you can probably figure already, most complications will arise from the “future programmer aspect of this communication triangle and more often this is ignored completely. Just in case you are not totally onboard with this third party, suffice to note that even the “future you can be regarded as a third party!
Now that we have the basics covered, it is time to briefly look at what constitutes an effective communicator. This is a broad subject itself so we only offer a small glimpse but you are welcome to read more on your own. To quote the master of rhetoric, Aristotle, to be an effective communicator you have to “Tell them what you are going to tell them, tell them and tell them what you just told them”.
If you are starting to wonder how this all relates to programming, ask yourself this; what do we or should we be communicating in programming? We’ve already established that it’s a communication form. As ridiculous or simple it may sound, it is imperative to understand this if we are going to be effective at it. As an example, suppose you encounter the following definition of function foo:
Public int foo(int a, int b)
What have I communicated to you? Ok, you may say, function foo takes two integers and returns an integer. If that were all that was given to you, would you consider it effective? To a machine this is sufficient but what about the future programmer? Hint; recall that we are in an object-oriented language here, therefore, there is a thing called "state". So the short answer is no. The above snippet fails to clearly communicate its intent. More important than the details of how a specific task is accomplished, the intent is the thing we should strive to communicate at all levels.
So then, where and how should intent be communicated? The obvious location is in the comment section, as most of you would agree. But what should we put there? Contrary to popular practice, for those who comment their code, I argue that less is more. What do I mean? It is often advised to put as much information as you can think of in the comment section with the idea that over-communicating is better than under-communicating. While this is sometimes true, it also highlights a deficiency. We don't know what to say so we say everything and you sort it out as you see fit. The trick here is to go for less. If more is needed, perhaps the functionality is too broad or we are getting into the how. Recall the quote from Aristotle, so basically state what a particular piece of code is intended to do, any pre-conditions expected and what effects such functionality has on the object’s state – i.e post-condition.
///Intent: ///Pre-condition: ///Post-condition: public int foo(int a, int b);
The idea of communicating intent is that one should be able to follow your code, without ever stepping into definitions. This applies at the module, class and function level.
The second location for communicating intent is in naming. This is without a bought one of the hardest problems in programming and in Computer Science in general. Therefore all we can say is try your best to keep it meaningful! This serves to highlight the importance of a comment section as described above. Naming itself is not reliable enough to communicate our intent no matter how clever the name seems.
The last and most unappreciated location to place our intent is in unit tests. Sure, a unit test is meant to confirm that a piece of code accomplishes what it was set out to do, you may say. This is an important reassurance to communicate to your “future programmer and it serves to keep the integrity of the original intent. Additionally, what makes it absolutely indispensable is that it is executable. Therefore we are able to change how a particular functionality is achieved and be confident that the intent is still intact. Surprisingly, it is also the case that unit testing strengths naming and commenting.
So what constitutes a readable code? We discussed the importance of looking at programming as a communication form among three parties where "intent" is the most important piece of information to be communicated. There are three places where this intent can be stated; namely in the comment section, naming, and unit testing. When it comes to commenting, we also urged the programmer to strive for less as opposed to over-communicating. A readable code communicates its intent over approach. In the case of object-oriented languages, this is achieved with the proper use of classes.