Don’t comment your code. Refactor it.

Are comments an apology for writing bad code?

In the book Refactoring, Martin Fowler talks about splitting up long functions:

How do you identify the clumps of code to extract? A good technique is to look for comments. They often signal this kind of semantic distance. A block of code with a comment that tells you what it is doing can be replaced by a method whose name is based on the comment. Even a single line is worth extracting if it needs explanation.

Martin Fowler, Refactoring

To find an example, I opened up the Github repo for Ghost (the first major open source project that came to mind). Within 15 seconds I found this chunk within a ~100 line anonymous callback function:

// don't allow indexing of preview URLs!
if (_.includes(context, 'preview')) {
    head.push(writeMetaTag('robots', 'noindex,nofollow', 'name'));

The book quote says to replace the block with “a method whose name is based on the comment.” So we could create excludePreviewFromIndexing() and remove the comment.

What would that get us? A few things:

We’d have no risk of the comment becoming outdated. The classic book Clean Code by Uncle Bob talks about this:

The problem with comments is that they have no compile-time check and tend to be forgotten. It’s very easy to change your code but forget about the comments.

Uncle Bob, Clean Code

We’d also get self documenting code. You wouldn’t need to read a comment to grok it at a glance.

Plus, we’d have a shorter parent method, and it would get much shorter if we did that in a few more places.

But how can this be?! I always learned that comments are good, and that uncommented code is bad code. I always felt guilty if I submitted a pull request without some solid code comments. I’ve asked other people to add comments countless times in code review. Have I had it backwards for all these years?

And what about “code tells you how, comments tell you why”?

I went looking for other opinions and found another, spicier quote from Uncle Bob:

A comment is an apology for not choosing a more clear name, or a more reasonable set of parameters, or for the failure to use explanatory variables and explanatory functions. Apologies for making the code unmaintainable, apologies for not using well-known algorithms, apologies for writing ‘clever’ code, apologies for not having a good version control system, apologies for not having finished the job of writing the code, or for leaving vulnerabilities or flaws in the code.

[…] Is there any use of comments that are not apologies? I don’t think so. I can’t think of one. Is there any good reason to write a comment? Only if you’ve done something “wrong”.

Uncle Bob

Vicious, right? There’s never a good reason to write a comment, ever? Comments always mean you’ve done something wrong?

Jeff Atwood doesn’t go quite as far, but he’s close:

You should always write your code as if comments didn’t exist. This forces you to write your code in the simplest, plainest, most self-documenting way you can humanly come up with.

[…] If your feel your code is too complex to understand without comments, your code is probably just bad. Rewrite it until it doesn’t need comments anymore. If, at the end of that effort, you still feel comments are necessary, then by all means, add comments. Carefully.

Jeff Atwood

Jeff also referenced this blog post. It ends with a tiny list of legitimate reasons to add comments:

There are only four situations I can think of at the moment where I need to comment code:

1. In the styles of Javadoc, RubyDoc, et cetera for documenting APIs others will use.
2. In the off chance it really is that complex: For example, on a bioinformatics DNA search function that took 5 weeks to formulate and write out. That’s how rare it is to have something complex enough to warrant comments.
3. TODOs, which should be the exception, not the rule
4. Explaining why the most obvious code wasn’t written. (Design decisions)

Sam Larbi

I guess I’ve had it backwards. Comments are not a sign of craftsmanship. Comments do not imply good code. It’s the opposite – comments imply bad code. If the code was good then the comments wouldn’t need to exist.

Comments should be an absolute last resort. And even then, I should feel a little guilty about them.

What do you think? Tweet me and let me know.