More code comments

Posted on by Matthias Noback

Recently I read a comment on Twitter by Nikola Poša:

He was providing us with a useful suggestion, one that I myself have been following ever since reading "Clean Code" by Robert Martin. The paraphrased suggestion in that book, as well as in the tweet, is to consider a comment to be a naming issue in disguise, and to solve that issue, instead of keeping the comment. By the way, the book has some very nice examples of how comments should and should not be used.

The code comment as a naming issue

I think in most cases, indeed, we don't need comments. Common suggestions are, like Nikola suggests as well:

  • Introduce a variable with a meaningful name, which can hold the result of a complicated expression.
  • Introduce a method with a meaningful name, which can hide a piece of complicated logic.

The "hiding" that a method does, provides you with two interesting options:

  1. The method name can summarize a number of statements.
  2. The method name can represent a concept that is of a higher level than the lower-level things that are going on inside the method.

Option 1 is useful, but if you can go for option 2, it'll be the most valuable option.

Consider Nikola's example:

if ($date->hour < 9 || $date->hour > 17) { //Off-hours?
}

Option 1 would entail something like:

if ($this->hourIsBetween9And17($date->hour)) { //Off-hours?
}

Option 2 would be much more interesting and useful:

if ($this->isAnOffHour($date->hour)) {
}

This introduces abstraction, where the client doesn't care about the concrete details of determining whether or not a certain hour is an off-hour, but only wants to know if the given hour is indeed an off-hour.

#NoComments?

I realized I'm always applying the following rule: if I feel like writing a comment, I look for a way in which I can change the code so that I don't have to write a comment anymore. Also, when I encounter a comment in an existing code base, I apply the same rule, and look for ways to remove the comment. Because, as you may know, code can't lie, but comments can, so let's get rid of them before they become a risk.

However, contrary to my own advise, I also realized that I've actually been writing more and more comments over the past few months. So what's going on?

A little soul-searching revealed that I've been adding code comments that can be categorized as follows:

  1. Explanatory comments: ~70%
  2. TODO comments: ~20%
  3. WTF comments: ~10%

Explanatory comments

I've been adding explanatory comments to parts in the code that need an explanation, or a canonical description of the situation. Most often these comments can be found near a couple of statements in the domain model. The comment then explains why a certain business rule should be applied, and how the code beneath the comment actually accomplishes this. Of course, I try to match the words in the comment with the words in the code itself, so they are tied together.

Before adding an explanatory comment, I often try to rephrase the explanation as a test first. This is usually the better option, since it will make sure that the code and its documentation will never diverge. The test is the documentation that describes a piece of the code, and if the code is no longer truthful to that description, the test will fail. An even better option is to apply behavior-driven development, where tests can actually be written as stories with examples, and they will serve as automated tests at the same time.

Still, some things just need a whole paragraph of explaining, and in that case, I happily put the explanation in the code, and take my time (and a long-form commenting style like /* ... */) to explain what's going on.

"Here's a question: why don't you create a separate document, instead of a code comment?"

Good question; in my experience most developers don't care about documentation. They don't read it, don't write it, and don't update it. This means that documentation becomes untrustworthy very, very quickly. And still, nobody cares. All everybody cares about is diving into the code and making that change that needs to be done. So, knowing ourselves, I think it's much better to add a comment, than to write separate documentation.

"Okay, another question: don't you think a commit message would be more suitable for explanatory comments?

I agree, a commit message is great for a bit of explanation from your side. However, commit messages aren't as readily available as code comments are. They aren't searchable. They are not "in your face" - you don't see them automatically when you open the code. In fact, you'd have to dive into the history of that code, to figure out all the reasoning behind a piece of code. And besides, everybody would have to make small commits and write proper commit messages, which definitely doesn't happen in the real world.

By the way, I often stumble upon comments like this:

autoSelect: false, // important !!!! 

I think these are meant to be explanatory, but what they're missing is the "why" part of the explanation. Whenever you add an explanatory comment, make sure you don't forget it!

TODO comments

Besides adding explanatory comments to code, TODO comments are my favorite when doing a major refactoring, Mikado style. I sprinkle lots of these little comments across the area of the code base that I'm working on. You have to remember the one rule that should be applied when using TODO comments: when merging/releasing your work, those TODOs should be gone. This means that, as part of a code review, you should verify that no TODOs were added inside the new branch. Just like comments in general become outdated very quickly, TODO comments expire very soon as well. What happens most of the time is:

  • The TODO comment never was an intention-of-future-work, it actually was an apology in disguise.

    // TODO we should inject this service as a constructor dependency instead
    
  • The work to be done is too much and will never be done.

    // TODO rewrite using Twig
    
  • The TODO comment marks some technical debt that was introduced. The work will also never be done.

    // TODO make it possible to use this with a different tenant
    

From years of experience with TODO comments, my advice is to turn them into DONE comments right away, and move the comment to your commit message.

WTF comments

These comments are very much like TODO comments, because you're basically saying: "this ain't right", but you're also saying: "We're not going to fix this". Either because it works (even if that's a miracle), or because it would take too much time to make it right. You should still add a comment, to explain what's going on, so the next person who reads this code understands what's going on, and doesn't have to spend a lot of time trying to figure it out, just like you did now.

Conclusion

When I write a comment, I do it so that the next person who looks at this piece of code doesn't have to figure it out again. Fun fact: this is the same approach I have to many other things in life. For example, I don't want to spend time and energy over the same thought again and again, in particular if it's a troublesome thought. Same for things I have to do: if I think of it once, I write it down, so I never have to be interrupted by the thought again (until I check my TODO list, that is!).

While thinking about code comments, I became aware of an implicit rule about how I write code: I always aim to de-personify it. I try to write code that doesn't show hints of the author as a person (with emotions, habits, years of experience, etc.). When adding the types of comments discussed earlier, the code starts to have more signs of human authorship. And I actually think that's a good thing: we're working on this code together, but we're also experiencing it. Adding comments increases ownership of the code, and shows empathy towards other programmers, like our current and future team members. And to ourselves, when we dive back into the code after a holiday break. I'd say: happy commenting!

PHP clean code design