Eliminating Comments: the Road to Clarity

April 18th, 2010

I used to think commenting my code was the responsible thing to do. I used to think that I should have a comment for just about every line of code that I wrote. After my first read of Code Complete, my views changed pretty drastically.

I began to value good names over comments. As my experience has increased, I have realized more and more that comments are actually bad. They indicate a failure. In Clean Code Robert Martin says

“The proper use of comments is to compensate for our failure to express yourself in code. Note that I used the word failure. I meant it. Comments are always failures.”

http://i206.photobucket.com/albums/bb19/youdumbcat/EpicFail02.jpg

Those are some pretty strong words. You may be reeling back a bit after reading that. It is a normal reaction, but if you’ll drop your defenses for a second, I’ll help you understand why.

Let’s start with an example

Which is more clear to read? This:

int i = 5;  // Start at 5, since there are 5 widgets in our production system.
//  If the number of widgets is evenly divisible by the time, 
//  and we have exactly 5 sockets we need a new one.
if((i % this.t) == 0  && s.Count() == 5)
{
     i++
}

Or:

int currentWidgetCount = DEFAULT_PRODUCTION_WIDGET_COUNT;
if(ShouldCreateNewWidget(currentWidgetCount))
{
     currentWidgetCount++
}

private bool ShouldCreateNewWidget(int count)
{
     return CountEvenlyDivisibleByTime(count) && SocketCountAtThreshold();
}

Even though the second example is more code, the code is self-documenting. The names of the variables and methods themselves are telling you what the code is doing.  They are also serving to abstract out the concepts so that you don’t have to think about the entire piece of logic at one time.  This simplifies your code.

In the above example, you don’t have to look at the method ShouldCreateNewWidget.  You can deduce that the flow of that logic checks to see if it should create a new widget based on the count, and if it should it does.

If you want to know how it is determined if a new widget should be created, then you drill into the method, and you can see that if the count is evenly divisible by time and the socket count is at the threshold, then the answer is true, otherwise it is false.

Consider again the first example.  What happens if that logic changes, but the comments aren’t updated?  When you read the comments, how do you know that they are even correct unless you read through and understand the logic anyway?

Why are comments so bad?

It is not that comments in and of themselves are bad.  It’s more that having comments in your code indicates that your code itself is not clear enough to express its intent.  Elegant code should be able to express itself simply and completely.  Comments are not code, they are metadata about the code.  If you want to write elegant code, write elegant code, not elegant prose about code.

Here are some of the major reasons why comments are bad:

  • They do not change with the code. If a refactor tool changes the code, it cannot change the semantics of the comments, it can only change the syntax where it can recognize keywords.
  • A wrong comment is worse than horribly complex non-commented code. A wrong comment can lead someone completely in the wrong direction.  For that reason, a good developer always assumes comments are wrong.
  • A comment almost always expresses an absolute thing, where a well named variable or method can express an abstract concept. Comments can actually tightly couple your code.  Take the example above where int i = 5 had a comment stating that 5 was the default.  DEFAULT_PRODUCTION_WIDGET_COUNT communicates the same information, but at a higher level of abstraction.
  • Comments don’t show up in stack traces. I have looked through many stack traces in my career, and I can tell you for a fact, that when you are looking at a stack trace, you would much prefer self-documenting method names, than good comments.
  • Reading comments is optional. Reading code is mandatory.  You cannot count on anyone reading your comments.  You cannot force them to do so, but they must read the code. If you have something important to say, put it in the code.

NDoc and JavaDoc (XML style comments)

I am moving more and more away from even liking comments on public methods using JavaDoc or NDoc.  Most of the time when we create NDoc style documentation, we end up just restating exactly what the parameter name is.  How useful, really, is: cookieCount – the count of cookies? Does that actually help someone using your code?  I would much rather make method names that have intuitive names and parameters than follow an arbitrary convention that adds no real value.

There is even a tool that auto creates NDoc comments for you.  Seriously, I used to think that was cool, but really how stupid is that?  Auto-generating comments?  Before you disagree with me here, really think about if embedding XML into your source code is really adding any value.

I understand creating MSDN style documentation is pretty cool.  I’ve used NDoc and SandCastle myself.  But, wouldn’t the effort be better spent creating more meaningful names and self-explanatory APIs?

Exceptions

Sometimes, you will need to write comments.  But, it should be the exception not the rule.  Comments should only be used when they are expressing something that cannot be expressed in code.  If you are using some mathematical equation, you might reference that equation in a comment, rather than trying to codifying it.

If you want to write elegant code, strive to eliminate comments and instead write self-documenting code.

Update: Just wanted to add this link to my original post on Elegant Code. And the link to my main personal blog at http://simpleprogrammer.com, since some people were getting confused.  Also, you can follow me on twitter here.

  • Renso

    Your code should not contain comments. Your TDD/BDD style unit tests should tell the story. If the unit test name is descriptive it would be easy to understand what the code is doing without even looking inside the unit test itself. if your unit tests are grouped correctly, just reading the method names of the tests should provide an overview of what the code section is doing. best of all, if your code changes, your tests should fail (TDD approach) and you need to fix them, including changing the test’s name, which means your test and description/documentation always stay in sync.

    This of course is in the perfect world of TDD, I do find myself commenting code when I need to fix something quickly and don’t have time to write or update a unit test, not ideal. I started off writing comments in pseudo code style comments as a way to organize my thoughts, you should use your Unit Test Class to do this in TDD style and not in the code. The only reasonable explanation for commenting a piece of code is when it needs work; i.e. better design, and to reflect that in the comment so that another developer knows when they see it that it needs better design, keeping in mind unit tests already exists for it.

  • http://blog.gauffin.com jgauffin

    imho, your blog post takes for granted that everyone writes well structured and self-explainable code. In my experience, people don’t :)

    I rather see documentation as a tool to write better code. And now I’m not talking about writing comments inside methods, but commenting projects, classes/interfaces and properties/methods: XML style comments.

    I try to explain my point of view here:
    http://blog.gauffin.com/2010/06/my-name-is-more-docu-more/

  • florin

    Comments are not bad at all, they are just wrongly used. Because they are consider of lower importance with regards to code.
    The comment should state, at least code comments, why something is done not what it is done.

  • http://www.buyambien.co/ Frank

    If you really need comments then they should be put within the comment blocks that show on the intelisense within your VS IDE.

  • Eric

     Um, no. Comment your code please. I small comment giving me insight to what you were thinking is worth a whole lot.

    I can reverse engineer your code but I can’t reverse engineer your thoughts.

     If you are too lazy to update your comments when you update your code thats one thing. Just don’t encourage others to do it.

  • BDKR

    What about the fact that there is some code that functions exactly as wished but doesn’t really lend itself to self documentation? 

    And in my experience, the vigorous application of this logic begins to feel like the dark side of hungarian notation.