Comments That Add Value
Not all comments are bad. Some are essential.
The key distinction: bad comments explain what, good comments explain why.
Code can show what it does. Code cannot show why it does it that way, what alternatives were considered, or what constraints led to this design.
Explain "Why" Not "What"
Bad: Explaining What
// Loop through users and filter active ones
const activeUsers = users.filter(u => u.isActive);
The code already says this. The comment adds nothing.
Good: Explaining Why
// We filter inactive users here rather than in the query because the
// user service doesn't support filtering and we're deprecating it next quarter
const activeUsers = users.filter(u => u.isActive);
This explains a decision that isn't obvious from the code.
More Examples of "Why" Comments
// Retry because the API is eventually consistent—first read
// after write may return stale data
await retry(fetchOrder, { times: 3, delay: 100 });
// Use 1000 as default, not 0, because 0 causes division errors
// in the legacy reporting system
const defaultQuantity = 1000;
// Sort by created date descending because users expect most recent first,
// but the API returns oldest first
results.reverse();
Each comment explains something the code cannot express.
Warning Comments
Some comments exist to prevent future mistakes:
// WARNING: This function modifies global state. Do not call
// during parallel processing.
function updateGlobalConfig(settings) { }
// CAUTION: O(n²) algorithm. Acceptable for n < 100, but
// refactor before using with larger datasets.
function findDuplicates(items) { }
// NOTE: This format is required by the legacy import system.
// Do not change without coordinating with the data team.
const dateFormat = 'YYYYMMDD';
// SECURITY: Input must be sanitized before this point.
// Raw user input here creates XSS vulnerability.
function renderUserContent(content) { }
These comments prevent bugs and security issues.
Legal and License Comments
Some comments are required:
/**
* Copyright 2024 Your Company
* SPDX-License-Identifier: MIT
*/
Keep these minimal but compliant with your legal requirements.
TODO/FIXME Comments (Done Right)
TODO comments are useful when they're actionable. Useless when they're vague.
Bad: Vague TODO
// TODO: fix this later
// TODO: improve performance
// FIXME: doesn't work sometimes
These will never be fixed because they don't explain what to fix or why.
Good: Actionable TODO
// TODO(JIRA-1234): Replace this with the new PaymentService
// when it launches in Q2. Current implementation doesn't support refunds.
const payment = legacyPaymentProcess(order);
// FIXME(alice@company.com): Race condition when two users
// update simultaneously. Need optimistic locking.
async function updateSharedResource(id, data) { }
// HACK: Workaround for React 18 hydration bug (#12345).
// Remove when upgrading to React 19.
if (typeof window !== 'undefined') { }
Each includes:
- What needs to change
- Why it needs to change
- Who owns it or what tracks it
- When it should happen
Clarification Comments
Sometimes code is unavoidably complex:
// Bitwise operations for performance: checking if number is power of 2
function isPowerOfTwo(n) {
return n > 0 && (n & (n - 1)) === 0;
}
// RegEx breakdown:
// ^[a-zA-Z0-9._%+-]+ - local part before @
// @[a-zA-Z0-9.-]+ - domain
// \.[a-zA-Z]{2,}$ - TLD
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
When the code must be complex, explain it.
Intent Comments
Sometimes you need to document the intent behind a design:
// We chose this data structure because inserts are more common
// than lookups in this module. A hash map would be faster for lookups
// but slower for our use case.
const items = [];
// Deliberately not using async/await here because we want these
// requests to fire in parallel, not sequentially
const promises = urls.map(url => fetch(url));
const results = await Promise.all(promises);
External Reference Comments
Links to external resources can be valuable:
// Implementation follows RFC 7519 (JSON Web Tokens)
// https://tools.ietf.org/html/rfc7519
function createJWT(payload) { }
// Algorithm explained at:
// https://en.wikipedia.org/wiki/Levenshtein_distance
function levenshteinDistance(s1, s2) { }
// Fix for Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=12345
element.style.transform = 'translateZ(0)';
Comments for Tests
Tests can benefit from comments explaining:
describe('OrderProcessor', () => {
// Edge case: order total exactly at free shipping threshold
// should get free shipping (inclusive boundary)
test('applies free shipping at exact threshold', () => { });
// Regression test for bug #456: discount wasn't applying
// when coupon code had trailing whitespace
test('handles coupon codes with whitespace', () => { });
});
The Quality Bar
Before writing a comment, ask:
- Can the code be improved instead? If yes, improve it.
- Does this explain "why" not "what"? If it explains "what," delete it.
- Will this stay accurate? If it'll go stale, reconsider.
- Is this actionable? If it's a TODO, include context.
A comment should earn its place. Most don't.
Key insight: Good comments explain things code cannot: why decisions were made, what warnings apply, what constraints exist, what resources to reference. Bad comments explain what code does—let the code do that itself.