The need for comments
There seems to be at least some friction in writing code comments. And recently I’ve come more often across the claim:
“If code is written clearly enough, there is no need for comments.”
In my opinion, code is a projection of your mental model of what you are working on at a specific point in time. The clearer your thoughts, the more precise the mental model and code. This means that a fair amount of big-picture thinking is a prerequisite, in order to produce a clear and concise code contribution. If you consider that a repository ends up being a patch-work of mental models over time, it’s really hard to maintain this clarity without any additional explanation. A new person reading into a code base is only able to understand another author’s intentions by following the hints that were left behind.
A simple example:
cron.schedule(schedule.EVERY_HOUR, async () => {
await analytics();
});
The only take-aways from this excerpt is that seemingly a cron-job is running every hour and that some sort of analytics will be performed. Without opening the file that this function is exported from, the code itself is not capable of painting a clear picture of its purpose for the reader. Now imagine that this is one of many cron jobs.. This encourages a depth-first approach 1 in exploring the repository!
Let’s try a better function name:
cron.schedule(schedule.EVERY_HOUR, async () => {
await fetchJobsAndExecuteAnalyticUpdates();
});
Nice, there are more hints on what happens. But still, the code excerpt only ever focuses on the how, never on the why. Often times I’ve noticed that even when additional comments are added, that it’s simply a regurgitation of the function name. Instead, let’s try focusing on the why:
/**
* In order to reduce response times, database writes for analytics
* are separated from read operations. This cron job works down the
* queued analytics events gathered from requests.
*/
cron.schedule(schedule.EVERY_HOUR, async () => {
await fetchJobsAndExecuteAnalyticUpdates();
});
While this explanation might still not be perfect, suddenly, the reader may understand the intention at this level and move on, if it is not applicable to their current interests. At the same time, the reader learned something about the architecture and may recall it at another code location. A breadth-first approach1.
You’ll find that the same principle applies when looking at a repository without any readme file. Unless some strong motivation like a referral or exhaustion of all other options exists, the friction of trying to build the project or trouble-shooting errors is too high. The repository will be avoided and forgotten.
Who you are writing for#
This seems like a lot of effort for other readers - who might not materialise. But it is important to emphasize the insight above, that by writing the right comments and documentation, the author is automatically encouraged to engage in more big picture thinking. This will help solidify the mental model surrounding the project and improve how closely the code base resembles that mental model - an investment into yourself, as well as future-you.
In a company setting, code is usually reviewed as part of a pull request. Ideally such pull requests can be reviewed:
- by any developer on the team (without deep knowledge of the project)
- in a short amount of time (to reduce the lifespan of branches)
My experience is that if the pull request does not match the intended change that I expected, it is necessary to read into the code base itself, to figure out where this discrepancy stems from. Is my mental model wrong or are we not working towards the right goal here? At this point, it is not only an investment of time, but also mental power capacity. It heavily depends on the quality of comments and documentation. If not enough hints are left behind, it is likely that the review gets postponed and confidence in the project decreases. The ability to mentor across teams suffers.
Once the discussion inevitably moves away from its asynchronous nature, the quality of that exchange depends on the original author’s availablity and memory capacity. It is way easier to hand off pointers to specific code areas if documentation exists. Writing the right comments facilitates the path from pull request to merge for yourself, as well as improves the impression that colleagues will be left with.
Conclusion#
My advice:
For any reasonably serious code base, an effort should be excerted to maintain a structure which is inviting for another developer to dive into.
This includes the habit of writing self-explanatory file/class/function names and documentation at various levels, be that a singular function or the readme file for the whole repository. Without any comments, the code-base can only ever represent what is already there. Documentation is an opportunity for colleagues to evaluate your mental model without your presence. It is a win-win in terms of quality of code and onboarding processes.
In many ways, a lot of parallels can be drawn to the habit of writing unit tests, though some other caveats apply. But that’s a topic for another time.
-
Depth-first search is tree-traversal algorithm that first explores as far as possible along a path, before back-tracking. In contrast to breadth-first search, which iteratively explores all children nodes at a given depth. ↩︎ ↩︎