Edit on August 13, 2017: This post was rewritten while keeping the same structure as before. The first version was total crap.
Edit on August 5, 2016: This post uses an alternative definition of "Code Smell" and is not advocating against comments, but against the early usage of comments when there's a more effective alternative.
If you write code comments as the last option to improve your code, it will force you to improve your self-documenting skills first. That's why it should be considered a smell.
There are many arguments in favor of always using code comments. One of them is that they allow the developer to present in a human-readable form what the code can't. This way the comment can be compared against the source to validate the code correctness.
There are many problems with that.
One of the problems is that the developer overestimates the legibility and self-documenting properties of the comment they write because they already have all the context to understand the code. The developers are biased for being the authors, they don’t have the capability of judging their own work from an outsider perspective and that will lead to comments that other developers will find it hard to read.
A code comment is a piece of human-readable text that is written in the source to explain something about the code.
If you can't write legible code, then it's more likely you won't be able to write legible comments either.
One developer doesn't need to be responsible to build and verify the legibility of their own work. The solution for the developer bias is to rely on another person with the same level of skill (or better) to judge whether the code is really self-documented or not. If the team members do that with each other, everyone will learn and improve their skills on how to make an efficient self-documented software.
In order to avoid the developer bias, you should rely on another person to judge if the code is self-documented or not.
And guess what? There are techniques aimed specifically to facilitate communication between two developers in order to improve the legibility and maintainability of the code they write. Two of them are Code Review and Pair Programming.
One could argue Code Review is much more useful for this purpose than Pair Programming. Pair Programming is only effective when both developers share the same context of what is being done, and because of that there's a risk both can share the same biases.
Code review and Pair Programming enforce collaboration, and that can be orders of magnitude beneficial if each person has "The Growth Mindset" — a way of thinking that is known to exist in high performing teams.
The Growth Mindset is also known in the software industry as The Agile Mindset:
By asking for help with the Growth Mindset, the individuals grow, the team grows and the company grows. It will make possible for the team to produce high-quality code and reduce the chances of having to rework it later.
As an example, if you use a pattern where the source file contains the whole history of changes in the form of comments, then that means you're not using the Version Control System efficiently. You can use the Hidden Documentation to log the detailed information of the changes. There are techniques like Atomic Commits and Atomic Pull Requests which can improve that logging efficiency.
Using the Version Control System effectively can help you to create detailed documentation that is hidden and can be looked up later if necessary.
You should be cautious, though, because Hidden Documentation is not easily accessible when reading the code for the first time without prior context. It’s not wise to hide information that is important for a first-time reader, only the details pertinent to the history of how the code came to be.
Improving the code instead of commenting it is a mindset. If more people care about these things, they can learn as a team on how to do it correctly.
If you want to go fast, go alone. If you want to go far, go together.
— African Proverb
Testing is another way to document the code without having to write Code Comments.
Code Comments will have to be maintained and kept up-to-date primarily for the purpose of documenting the current code. Tests on another hand will have to be maintained primarily for the purpose of ensuring the system works as expected. However, tests can also be used to document the system.
We can’t use the comments to test the system, but we can use the tests to document the system.
If you structure the tests to document how the application behaves — using better specs, for example —you can use the same thing to document the system. This way you won't need to care about comments anymore as a separate concern, it will be a concern that is included automatically when you create and maintain the tests.
Likewise, a pattern for the purpose of documenting the system with tests already exists and is called BDD — Behavior Driven Development.
“Code never lies, comments sometimes do.” — Ron Jeffries
There are cases where it makes sense to create comments that explain some attributes of what the code can’t, like the “why” instead of the “how”.
Code comments can also be useful to document:
- A counter-intuitive hack or performance optimization which can’t document itself.
- Or the fix for a bug that is not easily testable.
In those cases, the best approach might be commenting that code but leave the details to the Hidden Documentation. The comments that are not hidden can serve only as a “head’s up” to the reader.
Explaining the code with comments should only be done as the last option available.
What about JavaDocs or JSDocs?
Those can’t be considered "code comments". They are meant to be the public API documentation that happens to exist as comments in the source code. Just because they are in the code, that doesn’t mean they’re useless comments, it just means they have a different purpose.
Let's call them Public API Comments.
Having Public API Comments in the source code or not is a matter of personal preference. The important thing to take care is to not allow them to lose their purpose and become the mirror of the API internals. If that happens, they will start to document what the code does for the developer, not the API consumer, and that is no different than writing bad code comments.
Public API Comments represents a style, where the definition of the public API is written in the source code using comments.
There are also benefits for code comments when working with legacy code.
Converting legacy code that is not self-documented into something that is self-documented can demand a lot of effort. Comments can be a good strategy to mark what needs to be improved in the future.
However, you can also create a tracking ticket for each legacy code improvement so that the team can have visibility of what needs to be done without polluting the codebase with comments. In the ticket, you make references to the code, like pasting a permanent link to the offending line and explaining what needs to be improved.
In most companies and projects today, having the self-documented code is still a Utopia. Maybe because developers don't care about it or because it's a hard thing to do correctly. The first step is to understand the problem so that it can become a habit, before trying to hide it with comments.
Self-documented code over comprehensive comments.
You can look at one of the main principles of the Agile Manifesto through a different point of view:
Working software over comprehensive code comment
… instead of
Working software over comprehensive documentation
The original intent of that part of the manifesto was not about comments, it was about going against the documentation practices of waterfall models. However, you can still use the same principle when you plan to add documentation to your source code.
Somebody once said:
Programs are meant to be read by humans and only incidentally for computers to execute.
A developer should be responsible for writing understandable code with the intent to make code comments unnecessary. It is a skill that needs to be developed separately, and for every new skill, there is a learning curve.
Communication is a must to prevent the developer bias and increase the ability of the team to build self-documented code.
Code Comments are not the same as Public API Comments, they serve different purposes and tackle different issues, although using similar mechanics.
Comments in the source code can be considered an important Code Smell to watch out for, but depending on their purpose they are legitimately necessary.
Edit March 22, 2017:
I have recently stumbled upon a post from 2014 called How to Write a Git Commit Message. There, the author suggests:
[…] a well-crafted Git commit message is the best way to communicate context about a change to fellow developers (and indeed to their future selves). A diff will tell you what changed, but only the commit message can properly tell you why […]
In some circumstances, Code Comments don't need to tell the "why" and that can be left to the commit message instead.
Edit April 14, 2017:
A real example of existing comments saying the "how" and not being updated when the rule changes: