You've probably had this experience: you open code you wrote six months ago, and it feels like someone else wrote it. The logic seems convoluted, the variable names don't quite explain enough, and you find yourself asking, why did I do it this way? The code runs fine, but understanding it requires archaeology.
This frustration reveals something important about programming. Code tells the computer what to do, but it rarely explains why you chose that approach. Comments bridge this gap—they're messages you send forward in time to help your future self (and teammates) understand decisions that seemed obvious in the moment but will become mysteries later.
Intent Documentation: Explaining the Why Behind Your Decisions
The most common commenting mistake is restating what code already says. Writing // increment counter by 1 above counter++ wastes everyone's time. The code itself communicates the what perfectly well. What code cannot express is the reasoning behind your choices—the alternatives you considered, the constraints you navigated, the goals you pursued.
Effective comments capture intent: // Using linear search here because the list is always under 20 items, and the simplicity outweighs the performance gain from binary search. This explains your decision-making process. Six months later, when someone wonders if they should optimize this, they'll understand you already considered it and made a deliberate choice.
Think of intent documentation as leaving breadcrumbs through your thought process. You're not describing the trail—that's visible. You're explaining why you chose this particular path through the forest when multiple routes existed. Future readers can then evaluate whether your reasoning still applies or whether circumstances have changed enough to warrant a different approach.
TakeawayBefore writing a comment, ask yourself: does this explain something the code cannot express on its own? If you're just restating the code in English, delete the comment and focus on making the code itself clearer through better naming.
Assumption Recording: Capturing Knowledge You'll Forget
When you write code, your head is full of context. You know the data will always arrive sorted. You know the user ID will never be negative. You know the function gets called at most once per session. These assumptions shape your implementation, but they're invisible in the code itself.
Here's the problem: you will forget these assumptions completely. In three months, they'll evaporate from your memory, leaving behind code that depends on conditions you no longer remember establishing. Worse, someone else might modify the system in ways that violate these invisible rules, introducing bugs that seem inexplicable.
Recording assumptions transforms tribal knowledge into documented knowledge. // Assumes input array is pre-sorted by timestamp—if this changes, switch to the sorting version in utils. This comment doesn't just state the assumption; it provides a recovery path. You're telling future developers both what the code expects and what to do if that expectation no longer holds true.
TakeawayWhenever you write code that depends on something being true—data format, timing, external state, input constraints—write a comment capturing that assumption. Your future self will thank you when debugging at midnight.
Warning Signs: Marking Dangerous Territory
Some code sections are landmines waiting for unsuspecting developers. Maybe there's a subtle race condition that only appears under heavy load. Perhaps the function modifies global state in non-obvious ways. The algorithm might look inefficient but exists because the 'obvious' optimization actually breaks edge cases.
These dangerous areas desperately need warning signs. // WARNING: Do not cache this result—the underlying data changes between calls and stale values cause silent corruption. This isn't documentation for understanding; it's documentation for survival. You're protecting future developers from mistakes that seem reasonable but lead to disaster.
Pay special attention to code that behaves differently than it appears. Functions with side effects, operations that aren't idempotent, algorithms where order matters unexpectedly—these deserve prominent warnings. The goal isn't to explain how the code works but to prevent specific mistakes you can already anticipate someone making.
TakeawayWhen you encounter or create code where the obvious modification would break things, add a warning comment immediately. The five seconds spent writing it will save hours of debugging when someone inevitably tries that obvious change.
Good comments are investments that pay dividends over time. They transform solo knowledge into shared understanding, turn implicit assumptions into explicit documentation, and prevent future developers from repeating mistakes you've already made. The best programmers write comments as if they're helping a stranger—because in six months, that stranger is you.
Start small: for your next coding session, add one comment explaining why you chose an approach, one capturing an assumption you're making, and one warning about potential pitfalls. These three habits will dramatically improve your code's long-term maintainability.