Write comments explaining WHAT and WHY, never temporal context or history
Comments documenting change history or implementation improvements become stale and confusing. "// Refactored from legacy system" tells nothing about current purpose.
Core principle: Comments explain WHAT code does or WHY it exists, never how it's better than before.
Violating the letter of this rule is violating the spirit of documentation.
Use for:
Use ESPECIALLY when:
Comments describe present state, not past or transitions.
// Improved error handling - used to just throw function processRequest() { }
// Recently moved from utils/ to core/ export function helper() { }
</Bad>
<Good>
```typescript
// Validates configuration against schema
class Validator {
validate(data: unknown) { }
}
// Returns error details to caller for proper handling
function processRequest() { }
// Shared utility for data transformation
export function helper() { }
Comments document code, not instruct developers.
// TODO: migrate all code to use this function improvedAPI() { }
</Bad>
<Good>
```typescript
// Handles async operations with automatic retry
class RetryableOperation { }
// Validates input before processing
function processInput() { }
Code quality shows in behavior, not comments claiming superiority.
Every file starts with 2-line header explaining purpose.
export class Validator { // ... }
</Good>
**Why ABOUTME:** Greppable pattern for finding file purposes.
```bash
grep -r "ABOUTME:" . --include="*.ts"
| Bad Comment | Why Bad | Good Comment |
|---|---|---|
// Refactored from legacy |
Temporal context | // Handles user authentication |
// New error handling |
References change | // Returns errors to caller |
// Improved performance |
Claims improvement | // Caches results for 5min |
// Use this instead of X |
Instructional | // Validates async |
// Wrapper around API |
Implementation | // Fetches user data |
// Recently moved here |
Temporal context | // Shared validation logic |
Rule: Remove old comments describing old behavior. Don't add new comments about the change.
Critical: Never remove comments unless proven false.
// DO remove if provably wrong
// OLD COMMENT: Returns null on error
function process() {
throw new Error(); // ← Comment was false, remove it
}
// PRESERVE if still accurate
// Retries up to 3 times before failing
function fetch() {
// Even if you refactor, keep comment if behavior same
}
If you catch yourself writing:
STOP. Write comment describing current behavior and purpose.
| Excuse | Reality |
|---|---|
| "Developers need to know what changed" | Git history records changes. Comments describe current state. |
| "This explains why refactoring was done" | Explain WHY current code exists, not what it replaced. |
| "Future devs should use this pattern" | Code quality speaks for itself. Don't instruct. |
| "The old comment has useful context" | If false, delete. If true, rewrite in present tense. |
| "Need to mark this as 'new' temporarily" | If it's running, it's not temporary. Describe what it IS. |
Every file starts with 2-line header:
// ABOUTME: First line - what this file does
// ABOUTME: Second line - key details or context
// Rest of file...
Guidelines:
ABOUTME: Before committing comments:
// ABOUTME: New validation system
// ABOUTME: Refactored from old regex approach
// This replaces the old validator - use this instead
// Better error handling than before
class Validator {
// Enhanced validation logic (improved from v1)
validate(data: unknown) { }
}
// ABOUTME: Validates configuration against schemas
// ABOUTME: Returns all errors in single pass
// Validates data structure and types
// Returns structured errors with field paths
class Validator {
// Checks each field against schema rules
validate(data: unknown) { }
}
See skills/naming-by-domain for domain-focused naming (no temporal context in names either).