Why Most Comments Are Code Smells
Here's a controversial statement: most comments are failures.
Not failures of documentation. Failures of code.
When you write a comment explaining what code does, you're admitting the code doesn't explain itself. Instead of fixing the code, you've papered over the problem.
Comments as Compensation
Consider this:
// Check if user is eligible for discount
if (user.orders > 10 && user.memberSince < Date.now() - 31536000000 && !user.hadRefund) {
applyDiscount(order);
}
The comment explains what the code does. But why is the code so hard to read that it needs explanation?
Better:
const hasEnoughOrders = user.orders > DISCOUNT_ORDER_THRESHOLD;
const hasBeenMemberLongEnough = user.memberSince < yearsAgo(1);
const hasCleanHistory = !user.hadRefund;
const isEligibleForDiscount = hasEnoughOrders && hasBeenMemberLongEnough && hasCleanHistory;
if (isEligibleForDiscount) {
applyDiscount(order);
}
No comment needed. The code documents itself through clear names.
The Maintenance Burden
Here's the problem with comments: code changes, comments don't.
You fix a bug. You refactor a function. You change the algorithm. The comment stays exactly as it was.
// Increment the counter by 1
counter += 2;
This comment was probably accurate once. Then someone changed the code and didn't update the comment. Now the comment is a lie.
Outdated comments are worse than no comments:
- They mislead readers
- They make readers distrust all comments
- They create cognitive dissonance when the code contradicts the comment
The Comment Test
When you're about to write a comment, ask: "Can I change the code so this comment is unnecessary?"
| Comment | Better Code |
|---|---|
// Loop through users | The loop already shows this |
// Calculate the total | Name the function calculateTotal |
// Check if expired | Use isExpired or hasExpired |
// Convert to uppercase | The .toUpperCase() call is already clear |
// Initialize variables | Obvious from context |
Bad Comment Categories
Redundant Comments
// Set the user's name to the provided name
user.name = name;
The code says this already. The comment adds nothing.
Noise Comments
// Default constructor
constructor() { }
// Getter for id
getId() { return this.id; }
These comments take up space without providing information.
Commented-Out Code
// function oldImplementation() {
// // ...200 lines of dead code...
// }
Delete it. That's what version control is for.
Journal Comments
// Modified by John, 2019-03-15: Added null check
// Modified by Sarah, 2019-04-20: Changed comparison
// Modified by Mike, 2019-05-10: Refactored loop
This is what git blame is for. Delete these.
Position Markers
//////////////////////////////////
// HELPER FUNCTIONS
//////////////////////////////////
If you need markers to navigate your code, your code is probably too long.
Attribution Comments
// Written by John Smith
Version control tracks this. Delete it.
The "Don't Comment Bad Code" Principle
Robert C. Martin puts it simply: "Don't comment bad code—rewrite it."
When you feel the urge to write a comment, it's often a signal that the code is too complex. Instead of explaining the complexity, remove it.
// BAD: Comment compensates for unclear code
// Calculate price with discount if customer is preferred and order is above minimum
const price = cust.type === 'P' ?
ord.total > min ? ord.total * 0.9 : ord.total :
ord.total;
// GOOD: Code speaks for itself
function calculatePrice(customer, order) {
if (customer.isPreferred && order.exceedsMinimum) {
return order.total * PREFERRED_DISCOUNT_RATE;
}
return order.total;
}
When Comments Are Appropriate
Comments aren't always bad. Good comments exist (we'll cover them in the next lesson). But the bar should be high.
A good comment explains something that the code cannot explain:
- Why the code exists
- What trade-off was made
- What constraint forced this approach
- What historical context matters
Bad comments explain what the code does. Good code already does that.
Practical Exercise
Go to your codebase. Find 10 comments that explain what the code does (not why). For each one:
- Can you rename a variable to eliminate the need?
- Can you extract a function with a good name?
- Can you simplify the logic?
- Can you use a constant with a meaningful name?
You'll find that most of these comments can be eliminated by improving the code.
Key insight: Comments that explain what code does are admissions that the code isn't clear enough. Instead of commenting, improve the code. Names, structure, and simplicity are better documentation than any comment.