DEV Community

Alex Bunardzic
Alex Bunardzic

Posted on

Code comments are a sign that something's off

Often when we write a block of code, we feel the need to supply an accompanying comment. Some teams value code comments, and insist on leaving as many detailed comments as possible.

Some other teams may perceive code comments as a sign that the code is actually not finished yet. The code is left in a half-baked state, and the accompanying comment is a reminder to go back and finish ‘baking’ the code.

Value of code comments depends on the software development philosophy

You may have guessed that those teams who consider comments as a reminder that the code is not finished typically subscribe to the Extreme Programming (XP) software development philosophy.

The opposite of XP philosophy are teams who value zero-tolerance-for-rework. Such approach is focused on the process of building; there is an envisioned ‘end state’ and there is a perceived gap between ‘here’ and that desired ‘end state’. Software development efforts are therefore focused on bridging the gap from ‘here’ to the ‘end state’ as soon as possible. Stopping on that trajectory in order to change the code that is already written is therefore perceived as a waste of time.

In contrast, teams practicing XP are focused on the process of changing the code. Instead of practicing gap thinking, they practice present thinking. Such approach may be confusing to the ‘end state’ software development philosophy. How can we keep developing software if there is no clearly defined ‘end state’?

So a team doing software development without setting their sights firmly on the planned ‘end state’ is prone to doing a lot of rework. As they write micro tests, XP teams let those micro tests evolve the shipping code. During the process of evolution, guided by micro tests, the code that’s already written gets revisited (often more than once). Revisiting the already written code is part and parcel of the discipline we call refactoring.

Doing development by following such philosophy typically means that any open-ended block of code could drag with it some kind of a code comment. And as we’ve already mentioned, the comment does not necessarily serve to explain to the human reader what the meaning of the code might be; rather, it serves the purpose of enticing developers to finish up the code, to refactor it properly.

Teamness and oral tradition

High performing teams tend to exhibit strong oral tradition. This strong oral tradition is the cohesive force that keeps team members together, establishes firm trust among colleagues, and cements loyalty to the team. It’s of no surprise that such teams tend to outperform majority of average teams.

When working under the safety umbrella of strong oral tradition, team members feel less prone to spend precious time on writing detailed documentation. If any time is spent on writing comments, it is only to ensure that no incomplete block of code falls through the cracks and does not get revisited.

The property of highly cohesive teams is that there are few permanent artifacts outside of the code. On the other hand, teams with low cohesion (i.e. those ‘revolving door teams’ with high staff turnover) depend on copious artifacts that are persisted outside of the code. Oral tradition in such teams is weak/non-existent, and the only way for newcomers to pick up the pieces is by pouring over the documentation/code comments.

Make transition from communication to collaboration

How can we turn low cohesive, drowning in documentation/comments teams into highly cohesive teams with strong oral tradition? One very effective way is to favour collaboration over communication.

Teams communicate via emails, sharing documents/diagrams, opening Jira/AzDo tickets, attending meetings and observing rituals and ceremonies.

None of those activities are necessary for teams that focus on collaboration. The difference is that while communication is mostly asynchronous or scheduled ahead of time, collaboration is always synchronous, in real time, and ad hoc. If a team spends most of the productive time collaborating on solving the problem at hand, when the problem is solved, there seems to be very little need on spending extra time documenting what transpired during the collaboration session. The problem is solved, and the team moves on to solving the next high priority problem.

Such approach to working is the least wasteful one. Naturally, as teams collaborate and share insights and knowledge in real time, face-to-face, there seems to also be very little need for rolling up their sleeves and writing code comments. The shipping code is implemented, it is expressive, everyone on the team has full grasp and full understanding of what the code does and how it does it. Oral tradition gets strengthened with every collaborative session. There isn’t any need for further communication at that point.

What if collaboration is difficult to achieve?

Due to various constraints (organization policies, temporary instability such as pandemic, etc.) sometimes it is not possible to achieve such high performing levels by implementing full blown collaboration. Teams need to fall back on the asynchronous and scheduled modes of communication. In such cases, code comments seem inevitable, no?

There still may be a better way. But first, let’s take a closer look at why are code comments, as a vehicle of communication, undesirable:

As the saying goes, code comments are actually lies waiting to
happen. At the time when we write the comment describing what our block of code does, the comment is truthful and accurate. However, as the time progresses, various pressures may cause the block of code to be modified. And at that point there are no guarantees that, with altering the code, the team will also make sure to alter the comment to reflect new, unplanned changes. So now we may introduce the risk of relying on incorrect code comments. More harm than good, when it comes to the accuracy of communication (in the absence of oral tradition).

The better way in the absence of oral tradition? Practice TDD. With TDD, we evolve the shipping code by writing one micro test at a time. That micro test drives only one change to the shipping code. After that change passes the test, we write another micro test, and so on.

In the end, or at any point in time during that process, if we examine the tests, we can understand the intention and the meaning of the shipping code. The upside is that we know that the story, as told by tests, is 100% accurate, because tests are executable and represent a healthy state of the shipping app.

Why are zero-tolerance-for-rework teams bothering with code comments?

One mystery remains unsolved: if zero-tolerance-for-rework teams consider reworking the shipping code an utter waste of time, what's the point in bothering to waste any time writing code comments?

In other words, since such teams are practising gap thinking and are only focused on bridging the gap from 'here' to the 'end state', isn't the real value they are bringing to the table the discipline of 'doing it once and only once'?

The gap thinking teams' value proposition is that the only focus that makes sense is to define the 'end state' clearly, then rally all forces and sprint in straight line toward achieving that desired 'end state'. Once we are very clear on how the 'end state' should look like, we analyze it, decompose it, plan and estimate it, and once that gets signed off, we jump in and just build it. The emphasis is on the process of building.

And since at that point they know exactly what they're building, and they intensely frown upon doing any rework (such a waste of precious time), code comments seem completely redundant.

Still, we see that gap thinking teams who emphasize the process of building are consistently practising articulate and detailed commenting of the code. What could be the reasoning behind that stringent practice?

The fact is, while gap reasoning teams are practising zero-tolerance-for-rework, they remain fully open to retries. They are fully tolerant to retrying.

Which is odd, considering their conviction that they only start building once they obtain clear understanding of the 'end state'. If that's the case, what is the need for retries?

Experience teaches that almost any time the gap thinking teams deliver the desired 'end state', it turns out to be buggy and needs fixing. That's where the culture and the discipline of retries comes in. And that's where detailed code comments are often life savers.

Top comments (2)

mcsee profile image
Maxi Contieri

Wow !

I wanted to read an article like that for such a long time !!

It remainds me on Naur's paper on Theory Building

alexbunardzic profile image
Alex Bunardzic

Thank you Maxi. The tragedy of the current state of software engineering lies in the stubborn refusal to admit the staggering level of uncertainty any software project is faced with. We still insist that software engineering is basically no different than traditional forms of engineering -- electrical, civic, etc. In the traditional engineering, we are faced with much lower levels of uncertainty, which enables us to successfully implement quality products by following the Big Plan Upfront.

Such approach always fails miserably in software, and yet we see, today in the year 2020, that majority of teams still fall for this trap of gap thinking.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.