There was a time when undocumented code was sin. Javadoc annotations were everywhere, often duplicating information contained within the file itself.

Since then, the meme of self-documenting code has arisen. Why?

In code, there are wishes and then there is reality. The following represent the reality of how code will run:

  1. The code itself and,
  2. Sometimes the tests

The following are merely wishes for how the code should run:

  1. Design documents
  2. Ad-hoc or formal discussions
  3. Whiteboard drawings
  4. READMEs or other documentation

This post is only concerned with comments, because they can be particularly insidious. Because they co-habitate with the code itself, you may be tricked into thinking that the comments are good representations of the code.

Comments getting out of sync with the code to which they are adjacent doesn’t have a good name. Let’s call it Comment Drift.

Why Do Comments Drift?

Comments drift for the same reasons we sometimes write bad code: We are human.

When writing code, we are subject to many different pressures: we need to ship ASAP or we don’t quite understand the code we’re moving into this new module or…

Having committed many sins myself: I get it. I’ve probably updated code this month and neglected to change its associated comment. Changing a comment will many times require a deeper understanding of the code than the task at hand.

With any given task of writing code, we are bound to commit some sins. Some will be graver than others.

Should We Comment at All?

The absolutists of self-documenting code maintain that any comment is a smell.

I’m not quite there, personally. Many comments would be better served by baking the explanation into the code. If comments mirror too much of the How but do not capture the intent, they are duplicated cruft. Worse, they are duplicated cruft that has the tendency to be incorrect once the code gets changed.

Let’s spell out exactly the distinction between the How and the Why of comments. First, let’s look at a comment that focuses too much on the How:

# This methods adds 2 numbers together
# @param x [Number] The first number that you would
#                   like to add
# @param y [Number] The number you would
#                   like to add to the first number
# @return [Number] The result of adding `x` and `y` together
def add(x, y)
  x + y

My pedantry knows no bounds sometimes. The above code is awfully silly. Our fancy Yardoc comments and descriptions don’t hide the fact that this comment solely focuses on the How of this method. It is far too focused on the implementation details.

Instead of focusing on the How, focus on the Why. Write a future note to yourself. One of my favorite comments of all time began with, “Hello, fellow developer. You have reached the hardest dungeon.” It then went on to describe exactly why the method performed its responsibilities, which happened to be due to some obscure tax laws in Pennsylvania.

We can’t add that level of flourish to every comment we write, but we can focus in on that Why.

Back to our pedantic addition example:

# Adding 2 numbers together is a pretty important action
# for the system. We’ve chosen the traditional interpretation
# of what it means to "add."
# We were under some time pressure at the time, so we
# realize that this is not the most optimized implementation.
# If you need to ask someone about how or why this works
# the way it does, go talk to Kelly or someone else
# originally on Project X.
def add(x, y)
  x + y

I’ve exhausted my pedantic example allotment for today, but I think you get the point.

Even with this comment, there’s some information that may not belong here. The authorship note might be better fulfilled by version control.

What Makes a Good Comment?

If you must write a comment, the key to a good comment is to capture the Why of the code, not the How. Good comments capture intent.

When I find myself writing comments that are explaning too much of what the code is doing rather than the intent, I look for ways of baking that language into the code itself. Domain-Driven Design encourages this with its concept of Ubiquitous Language.

I also like to think of comments as feedback mechanisms. There are some things that need comments, but many things do not. Whenever I find myself reaching to write a comment, I take that as feedback that perhaps my design needs improving.

As with many topics related to software engineering, Jeff Atwood has already written about this topic in detail: Coding Without Comments. It’s essentially the software engineering equivalent of Simpsons Did It.

Special thanks to William Van Hecke and Justin Duke for providing feedback on early drafts of this post.