Eliminating Comments: the Road to Clarity
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.”

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.






Love this article – I have long promoted this. I even went so far as to say -Comments are bad- in a session only to have to get into a huge debate on it.
Method names also need to be descriptive – it’s all about the name.
Comments do have their place – but most comments can be left inside Source control systems and spec documents. That said, I like what Shazbot said:
If you really need comments then they should be put within the comment blocks that show on the intelisense within your VS IDE.
That’s why I added a rule into my refactoring tool to say any code where the comments are 1/3 the size of the code, needs to be refactored immediately.
The non-trivial software product will have many levels of abstraction. At the lowest level there are the actual code statements, over that there are methods, then classes/interfaces, components/packages/assemblies/DLLs, layers, clients/servers/tiers etc… and these are just “physical” levels – there may be many domain-specific “logical” paradigms with no direct analog in the programming language/technology.
While I agree that commenting at the level of statements is usually superfluous (i.e. the code can usually express itself AT THAT PARTICULAR LEVEL OF ABSTRACTION), properly documenting all the other levels has great value for long-term maintainability of the product, which is where some forms of comments have their rightful place.
The rules of thumb for good comments are:
1. The comment should be AT HIGHER LEVEL OF ABSTRACTION than can be expressed directly in code.
2. The comment is usually written BEFORE code.
Here are some examples:
– Commenting the API is absolute must – the client will usually not have the access to the source code and not all of the pre/post-requisites for making a particular API call can be expressed through the language / communication technology chosen to implement the API. Typically, the best the API implementation code can do is throw an exception / error code, but by that time the high-level context for understanding the root cause of the problem may be lost.
– Everything is “API”, even if used by the same person/team. The software I usually work on is usually too complex to keep ALL the nitty-gritty details in my head. There is a great value in being able to FORGET the code that I’m not currently working on. Having high-level comments all over the place serves as a “shortcut” for understanding the code I now no longer need to read.
– Commenting intention – as code evolves, having a proper documentation on what is ESSENTIAL, versus what is INCIDENTAL lets me stick with essentials and break less clients as code evolves. In fact, well written comment will change LESS OFTEN than the implementation code.
– Commenting higher-level structures. Often, my data structure is a complex graph or tree of nodes, and needs to have a specific “shape” or certain things need to happen in certain sequence to have a proper behaviour. While assertions/contracts help, higher-level documentation is usually a must.
– Commenting dependencies – a product can depend on many pieces of code or even entire applications not written by me or my team. We are often forced to do certain things in a certain way simply by not existing in a vacuum. With proper documentation, it is easier to understand what changes need to be made in our code when the “environmental forces” change.
– Commenting on a choice of algorithm or data structure – there is often a situation when there are multiple choices of algorithms and/or data structures that can be used to solve a particular problem. Neither choice is “incorrect” – they all produce correct end result – by there are time/space/scalability tradeoffs to consider and the “correct” solution is the one that fits with the expected USAGE PATTERN best. Commenting what is the expected usage pattern and what are the performance tradeoffs chosen as a consequence can help tremendously in understanding performance bottlenecks when usage pattern changes.
– Comments can simply be LONGER than programming language names. Just the other day, I was tempted to make a method: “RemoveHandlesOfNotImplicitlyUnloadedModelsFromSession()”; at the end I settled for simple (but imprecise) “CleanupSession()” with appropriate comment.
Let me disagree with some of the specific points you make:
– “They do not change with the code.” – Nor the other way around. I often find myself editing the comment simply to “debug” my thinking and change the code only AFTER the comment looks right. If you code first and comment later, then I can see your point.
– “A wrong comment is worse than horribly complex non-commented code.” – True, but a comment rarely exists in vacuum. If the rest of you product is documented properly, the bad comment will be obviously inconsistent with the rest of the documentation and easy to spot. Actually, achieving “comment consistency” is useful technique for “paradigm debugging” in your head.
– “A comment almost always expresses an absolute thing, where a well named variable or method can express an abstract concept.” – Actually, my experience is the opposite. Good comments are always at the higher level of abstraction than the code.
– “Comments don’t show up in stack traces.” – No, they are one click away.
– “Reading comments is optional.” – Well, the basic OOP principle of encapsulation tells us that reading implementation code is optional as well. Without comments, what you are left with is reading names/signatures of classes/methods/parameters and that alone is often simply not expressive enough.
@Branko, you said:
“Everything is “API”, even if used by the same person/team. The software I usually work on is usually too complex to keep ALL the nitty-gritty details in my head. There is a great value in being able to FORGET the code that I’m not currently working on. Having high-level comments all over the place serves as a “shortcut” for understanding the code I now no longer need to read.”
Its ok not knowing and/or remembering the details of complex software. But if you open any given code file in such software, and you can’t easily/quickly understand what it is, it almost surely isn’t good code. You say having the high-level comments all over the place serves as a ’shortcut’, but its usually there for the inability to use a better design. ps. I know sometimes we just have to deal with such code, but that doesn’t mean the situation wasn’t created by a different problem, ignoring that perpetuates the issue.
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.
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/
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.