Why write code comments?

Share on:

We've all seen it, code comments that are so obvious they add nothing but noise to the codebase. Redundant comments restating exactly what operation the code is performing.

For example, this function's purpose is obvious from its name - adding a comment as well doesn't add any value:

1// Verifies if the auth token is valid
2fun isAuthTokenValid(tokenFromRequest: String) =
3    authConfig.publishToken == tokenFromRequest

Or the comment on this block of code, which again doesn't clarify anything beyond what is already understandable from the code:

1// Only execute cleanup if dry-run flag is disabled
2if (!cleanupConfig.dryRun) {
3    attachmentService.deleteAttachments(publicId)
4} else {
5    logger.info("Not deleting attachments from test run $publicId since dry run is enabled")
6}

Unnecessary comment downsides

These types of comments aren't just harmless - here are a couple potential drawbacks to unnecessary comments:

  • Code and comments can get out of sync, causing confusion in future readers/maintainers of the code. Which of the two is correct - the code or the comments?
  • Unnecessary comments take up space in the code, making it more verbose and slower to read and understand by future maintainers.

Comments detailing "why"

However, there are situations where code comments can be very helpful. Rather than these "what" comments that are best represented in the code implementation itself, comments explaining why the author wrote included specific code is much more helpful.

For example - this piece of code always sets this partialLines field to an empty list, which at first glance looks it might be an issue. But there is an important reason why the field is always an empty list, with an inline comment to explain why.

1// Clover partial lines from Jest coverage reports are not accurate
2// so don't show anything rather than inaccurate data.
3partialLines = listOf(),

This code removes any leading forward slash from another field, which might seem odd to a future reader (or myself six months from now) so again I included a comment as to why:

1// A leading forward slash messes up the URL when deep-linking to the page in the UI
2val packageStartIndex = if (cleanedClassNameWithPackage.startsWith("/")) 1 else 0
3val packageName = cleanedClassNameWithPackage.substring(packageStartIndex)

These comments give future readers and maintainers of the code a glimpse into the mind of the author and help illustrate the importance of the code implementation. And it's not just other people that will benefit from these comments in the future. You could easily be the beneficiary - coming back to the work on the code six months later and trying to remember why you implemented specific functionality that way.

Pull request answers into code comments

One often-overlooked source of great "why" comments is from interactions amongst folks in pull requests. When a pull request reviewer isn't sure why the author implemented specific block of code a certain way, they'll often ask in a pull request comment. Then the author will answer the question in a followup pull request comment.

If a reviewer wasn't sure about the code and asked about it in the pull request review, chances are a future maintainer of the code may have the same question. Add the answer from the pull request into the code as a comment so it helps these future maintainers as well.

Include tests

While these comments explain why the specific code exists, the comments themselves are documentation and don't protect against the code accidentally getting changed or removed. So I also include tests to explicitly check for these scenarios to fail if they change in the future. Having tests as well adds another layer of protection against accidental modification to these key pieces of code.

Conclusion

When used judiciously, code comments can be a great way to convey the reasoning behind why the original author wrote specific parts of the codebase. But take care to not over-comment the "what" and "how" of a codebase. Unnecessary comments have drawbacks, and that information is better embedded into the code itself.