Romain Delamare

September 12, 2023

Writing Good Code Comments

I discuss why, when, and how you should write comments in your code.

During my career I have received conflicting advices about code comments. I recall a tech lead telling me I should comment everything and another telling me I should never comment because that is a code smell. Of course both were wrong, and since I’m right, I will now explain how to properly comment your code.

Documentation comments and code comments

I make a distinction between documentation comments, written for an external tool (such as Javadoc or rustdoc), and code comments, written for developers reading the code.

Documentation comments target users of the code and describe how to use it. They are great. You should write them whenever they are desirable (such as when writing a library). This article will not cover this type of comments. They are highly dependent on the language, and most tools have great recommendations on how to write documentation. You should follow these guidelines.

Code comments serve another purpose: they target developers to help them understand the code. Making the code understandable by humans is one of the most important goals of a software engineer, and code comments is one way to achieve it. Let’s see why, when, and how to write them.

When should you write code comments?

Depending on who you ask, the answer is “always” or “never”. Since you ask me, I think you should write code comments whenever the code is not self-explanatory and you have no other means of improving it.

The debate about code comments and code smell comes from a confusion on cause and correlation. There is a correlation between complex code and comments, because complex code requires more explanations. Since simplicity is a desirable trait, that makes code comments undesirable. This is a fallacy because you could have a complex code without comments, which is probably the worst situation.

More importantly, some complexity is unavoidable: sometimes you must optimize the code, sometimes there is a bug you cannot fix (e.g., a bug in a dependency), sometimes you must ship and cannot write a time-consuming refactoring. All these reasons, whatever their merit, could prevent you from writing simple and self-documenting code.

You should try to find other ways to convey meaning and remove complexity, but if that is not achievable, do write code comments.

Why not use comments more liberally? Because comments make maintenance harder. When the code is updated, it is very easy to forget updating the corresponding comments. A code with a lot of comments will become more difficult to maintain, and when too many comments are obsolete the code will be more difficult to understand

Adding meaning with good names

A good way to avoid using comments is to properly name functions and variables. No need to be creative, do not try to be funny. Write boring names. Be explicit. Write very long names if required.

Do not write
// computes the horizontal offset
fn hoff(x: i32) -> i32 {
    // add header column width
    x + 32
}
Do write
const HEADER_COLUMN_WIDTH: i32 = 32;

fn compute_horizontal_offset(x: i32) -> i32 {
    x + HEADER_COLUMN_WIDTH
}

Adding meaning by extracting functions

A function is not only useful to reuse a piece of code, but also for naming what it does. Function names are usually better maintained than code comments.

Do not write
fn rename_user(id: Uuid, new_name: String) {
    // load user
    …

    user.name = new_name;

    // save user
    …
}
Do write
fn rename_user(id: Uuid, new_name: String) {
    let user = load_user(id);
    user.name = new_name;
    save_user(user)
}

fn load_user(id: Uuid) -> User { … }
fn save_user(user: User) { … }

Dos and don’ts

Here are some guidelines for writing good code comments.

Dos

Don’ts


I used to avoid comments at all cost. Now I write more comments, but still feel like I should first try to make comments unnecessary.