Comments are, to put it mildly, a controversial topic.
There are two very strong opinions in software development, both extremely popular and widespread. The first one states that comments are evil, and you should not use them under any circumstance. The main argument is that instead of using comments, you should try to make the code as readable as possible. If the code is written in an expressive way using best practices, comments are not needed.
The second group thinks that comments are a necessity. The code can't hold all the information needed to properly maintain a solution, and comments are an effective way of communication for fellow developers. If all we needed was the code, we could grab the binaries and work from them.
I think both groups have something valuable to teach. It's true that comments can be dangerous, some of the reasons why you might be wary of them are:
- Comments easily become outdated, and it's unreasonable to expect everyone to update every comment when code changes. It would be an ideal thing, but it rarely happens in reality.
- Code is the sole source of truth that is guaranteed to be true at any given point through the lifecycle of software.
- A bad comment is worse than no comments at all, as it misleads you into wrong assumptions.
- When overused, comments clutter our code and make it harder to find the things we are looking for.
Comments are essentially there because we weren't able to perfectly express our ideas in code. Every single time you write a comment, think if it's possible to refactor your code in a way that makes it obvious to the reader. With effort and experience, you can remove most of the unnecessary comments from your projects.
Despite their downsides, comments can be used to effectively communicate with fellow developers. The trick is not to repeat your code, but to clarify its intent and provide valuable extra information that you can't represent in code. If you can keep your comments at a higher level of abstraction, you will have a powerful tool for making your code more maintainable.
Let's take a look at 5 scenarios where using comments can help improve the readability of our code:
Explaining the intent and answering why
Explaining why things are done in a specific way in the code is one of the most accepted uses for comments.
The reason is simple: code itself only tells you what is there, not why it is there. The motivations behind seemingly arbitrary choices in design and development are usually found in the documentation, but if you need to keep this information in the source code, comments are the best way of doing it.
Feel free to add comments if you feel that something looks too arbitrary, or to let other developers know why you are doing things the way you are doing them. Don't write a huge essay supporting the choice, a quick one-liner is enough to convey information. Other developers will appreciate this valuable information.
Clarifying details
Sometimes you need to write small clarifications for input arguments or data returned from a function, in this case, a comment might make things easier to understand.
It's also useful for summarizing a series of complicated operations: writing a small comment that explains the intent of the following lines is useful to understand how they work together.
Another common usage is specifying the units of a variable: is this meant to be a distance in meters or feet?
This might be the weakest use case of the list because comments of this type are rendered useless by giving variables and functions good names. If you want some guidelines for naming variables, you can read the previous article on the topic.
Warning the user of a method about side effects
There are methods with 'dangerous' side effects. Some of them will perform actions that are hard or impossible to revert or will remove records from an important record.
You could have in place some special naming conventions to make this clear. The Ruby community, for example, has a convention for appending a '!' character at the end of methods that perform this type of action. If there is a need for a more detailed explanation, feel free to add a comment explaining the possible dangers of calling a specific method.
# Warning!: This method will stop the pipeline and all unprocessed data will be lost,
# ensure the queue is empty before calling it, otherwise, you might lose data.
def perform_teardown():
# Implementation of this method
return
TODO comments
You can add little reminders for things you need to improve or refactor later. There are lots of changes that don't merit a new ticket in the issue tracking system, and those little reminders can be useful for not forgetting about these little improvements.
Most modern text editors and IDEs have tools for finding those TODOs, and I have the feature enabled in every single one I use (actually, it's one of the first things I do when setting up a new system). Use them with confidence, TODO comments are ok.
# TODO: Find out if there's an efficient alternative for linear algebra and make this method a wrapper around it
def transpose_matrix(matrix)
# code for transposing a matrix
end
Public API documentation
Documenting the public interface of your classes is a very important part of software development. You want other users (and well, you too) to know how to use your classes and code. There are many tools that let you convert comments into documentation (PDF, HTML, and other formats), as long as you write your comments with a specific format. The tool will scan your code and extract all the required information for the documents.
Some popular examples are Javadoc for Java and YARD for Ruby, the comments on top of methods look like this:
Javadoc:
/**
* <p>Translates text from English to alienspeak
* </p>
* @param textInEnglish the text in English I want to translate
* @return the text after being translated into alienspeak
*/
public String translateToAlienspeak(String textInEnglish) {
// contents of the function
}
YARD:
# Translates a text from English to alienspeak
#
# @param text_in_english [String] the text in English I want to translate
# @return [String] the text after being translated into alienspeak
def translate_to_alienspeak(text_in_english)
# content of the function
end
Not all comments are cool comments, but some are
These are just a couple of cases where comments are helpful, but there are many other scenarios where using a comment is the right thing.
The trick for writing good comments is asking yourself why you are writing them in the first place. Is it to fix a deficiency in the clarity of your code? if that's the case, stop and refactor your code to make it more readable. As we said before, most comments can be omitted in favor of a better-written piece of code.
On the other hand, if you are providing information that your colleagues will find helpful, and there is no way to embed that info in the code, then go for a comment. Good comments can be extremely helpful. Just make sure they are good comments, not lazy patches for code that can still improve.
In the next article, we will see scenarios where comments are definitely a bad choice.
What to do next:
- Share this article with friends and colleagues. Thank you for helping me reach people who might find this information useful.
- You can find more information about creating good function arguments in chapter 4 of Clean Code, and in chapter 32 of Code Complete. This and other very helpful books can be found in the recommended reading list.
- Send me an email with questions, comments or suggestions (it's in the About Me page). Come on, don't be shy!