Code Comments: When, Why, and How (Not)
Good code is self-documenting, but that doesn't mean all comments are bad. Learn the difference between valuable comments and harmful noise that hurts maintainability.
There’s a popular mantra in clean code circles: “Good code comments on itself.” While this is a noble goal, it’s often misinterpreted to mean “never write comments.” The truth is more nuanced. The best developers don’t avoid comments; they use them sparingly and effectively.
The key is to distinguish between comments that add value and comments that are just noise. A bad comment can be more misleading and harmful than no comment at all.
The Golden Rule: Comments are a Last Resort
Before you type // or #, ask yourself: “Can I make the code clearer?” Most of the time, the need for a comment indicates a failure to write clean code. A confusing piece of logic doesn’t need a paragraph of explanation; it needs to be refactored.
Bad: A Comment Explaining a Bad Name
// Checks if the user is eligible for the promotion (must be over 18)
function check(user: User): boolean {
return user.age >= 18;
}
This comment is a “code smell.” It exists only because the function name check is terrible.
Good: Refactor the Code, Remove the Comment
function isEligibleForPromotion(user: User): boolean {
return user.age >= 18;
}
The new function name makes the comment completely redundant. The code now speaks for itself.
Good Comments: The Ones Worth Writing
Some comments are not only acceptable but necessary. They provide context that the code itself cannot.
1. Comments Explaining “Why,” Not “What”
Your code should always explain what it is doing. A comment is for explaining why it’s doing it, especially if the reason is non-obvious business logic or a workaround for a strange bug.
# Bad: Explains the "what"
# Increment the counter by one
counter += 1
# Good: Explains the "why"
def process_payment(amount: Decimal, user: User):
# We must apply the discount before the tax calculation
# due to the requirements of the third-party tax API (TAX-1138).
discounted_amount = apply_loyalty_discount(amount, user)
final_amount = calculate_tax(discounted_amount)
return final_amount
2. Legal Comments and Copyright Notices
These are often required by company policy or open-source licenses. They don’t explain the code but serve a legal purpose.
// Copyright (c) 2025 FuryBee Industries. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
3. TODO Comments
TODO comments are a practical way to mark areas that need future work. They act as reminders and can often be tracked by IDEs and other tools. The key is to make them actionable and not let them rot.
# TODO: Convert this to a batch processing job.
# The current implementation is too slow for more than 100 records.
# See ticket JIRA-456 for more details.
def sync_user_profiles():
# ... temporary sync logic ...
A good TODO explains what needs to be done and why. A bad TODO is just // Fix this later.
4. Public API Documentation (Docstrings, JSDoc)
When you are writing a library or a public API for other developers to consume, detailed documentation is essential. This is where formats like JSDoc (for TypeScript/JavaScript) and docstrings (for Python) shine. They explain the contract of your function: its parameters, what it returns, and any exceptions it might throw.
/**
* Calculates the final price of an item after applying discounts and taxes.
* @param {Item} item The item to price.
* @param {User} user The user purchasing the item, used to determine discounts.
* @returns {Promise<number>} The final calculated price.
* @throws {Error} If the item is not found in the database.
*/
async function calculateFinalPrice(item: Item, user: User): Promise<number> {
// ... implementation ...
}
def calculate_final_price(item: Item, user: User) -> Decimal:
"""Calculates the final price of an item.
This function applies user-specific discounts before calculating
regional sales tax.
Args:
item: The item to be priced.
user: The user, used to determine available discounts.
Returns:
The final price as a Decimal.
Raises:
ItemNotFoundError: If the item does not exist.
"""
# ... implementation ...
Bad Comments: The Ones to Avoid and Delete
These comments add clutter and often become outdated, leading to confusion and bugs.
1. Redundant Comments
If a comment says the exact same thing as the code, it’s useless. Delete it.
// Bad: This is just noise
// Create a new user object
const user = new User();
2. Misleading Comments (The Worst Kind)
A comment that is out of date or just plain wrong is a lie. It will cause developers to waste time and introduce bugs. No comment is infinitely better than a wrong comment.
# This comment is a lie! The function was changed to return None on failure.
# Returns the user object or raises an exception if not found.
def find_user(user_id: int) -> User | None:
try:
return db.query(user_id)
except DbError:
return None # The comment above is now incorrect.
3. Commented-Out Code
Don’t do this. We have version control systems like Git for a reason. If you need to see old code, you can look through the commit history. Commented-out code is dead code. It clutters the file, confuses readers, and will almost certainly never be uncommented. Just delete it.
// Bad: Dead code belongs in source control history, not here.
// function oldLoginLogic(user) {
// // ... a bunch of old, confusing code ...
// }
4. Journal Comments
Some developers leave a running log of every change they’ve made at the top of a file. This is another anti-pattern that is made obsolete by version control. git log is your journal.
# Bad: This is what `git log` is for.
# 2025-10-15 - FB - Added support for PNGs
# 2025-10-18 - FB - Refactored image processing
# 2025-10-20 - FB - Fixed bug in resizing
A Simple Checklist for Writing Comments
Before writing a comment, ask:
- Can I improve the code’s name or structure to make this comment unnecessary? (Do this first!)
- Does this comment explain why something is being done, not what?
- Is this a required legal comment?
- Is this an actionable TODO with context?
- Is this public API documentation that will help other developers?
If you can’t answer “yes” to one of the last four questions, you probably shouldn’t write the comment. Clean, expressive code is always the primary goal.