Comments Are Not Just Notes: How to Write Code That Explains Itself
Every beginner is told to "write good comments." Almost nobody is told what that means.
Good comments are not summaries of what the code does. They're not labels stuck next to every line. They're not proof that you documented your work.
A good comment does one specific job: it explains something the code itself cannot explain. Everything else is noise.
What Most Beginners Get Wrong
Here's a comment that adds nothing:
# Add 1 to the score
score = score + 1
You already knew what that line does. Reading it in plain English tells you nothing new. This is a comment that restates the code — and that's the most common mistake beginners make.
The problem isn't just that it's useless. It's that it adds maintenance work. Now you have two things to update every time that line changes. And the comment will lag behind. Six months later, someone will read "add 1 to the score" next to a line that multiplies the score by 2.
Comments that restate the code become lies over time.
When a Comment Is Actually Worth Writing
Comments earn their place when they answer a question the code can't answer on its own.
Why, not what
If you wrote something in a non-obvious way, explain why. Not "sort in reverse order" — that's what the code says. Instead: "sort in reverse order because the leaderboard shows highest score first."
Hidden constraints
# Max 20 items — the API silently drops anything beyond this
items = items[:20]
The code slice is obvious. The reason for 20 isn't. That comment is worth keeping.
Workarounds and oddities
If you had to do something weird to make something else work, say why. Future-you will thank present-you when the workaround needs to change.
Decision points
If you made a deliberate choice between two approaches and picked the less obvious one, note why you didn't go the other way. Especially useful in code that will be read by others — or yourself after a break.
When to Stay Silent
- When the code says exactly what's happening:
# loop through scoresabovefor score in scores— delete it. - When you're explaining a language feature:
# list comprehension— delete it. - When you're labelling a variable:
# this is the user's nameaboveusername = ...— delete it. - When you wrote it to reassure yourself:
# should be fine here— especially delete this one.
Comments Rot
This is the thing nobody tells you upfront: comments don't update themselves.
Code changes. Functions get renamed. Logic gets inverted. If you don't update every comment that references that code — which nobody ever does reliably — you end up with comments that are wrong.
A wrong comment is worse than no comment. It actively misleads the next person reading the code.
The cure is to write fewer comments, not more. Comments you write because you feel like you should are comments that will rot. Comments you write because the code genuinely cannot explain itself are comments worth keeping.
The One Rule Worth Taking Away
Comment the why. Let the code speak for the what.
When a variable is called harvest_buffer instead of items, the name explains the what. When a function is called find_best_crop(), the name explains the what. Readable code with good names needs almost no comments at all.
Save the comments for moments where someone reading the code six months from now would genuinely wonder: "why did they do it this way?" That question deserves an answer. Everything else doesn't.
This post expands on the Comments OCCOB Short — one concept, 60 seconds, no jargon.