Comments have been the target of much negative advice—delete them!
rewrite to eliminate them!—but little positive advice. Let’s take a look at why they get a bad rap,
then examine why the right kind of comments are indispensable.
An Easy Target
// get the minimum X value of our bounds let x = view.bounds.minX
You’ve seen code like this.
You might even cop to having written code like this.
Luckily, the problem is very localized:
You need only look at a couple of lines to see that the author
has duplicated what their code does into their comments.
When the code changes, and the comments don’t—and they need not, since the compiler won’t look at them, anyway—the comment will make the code harder to understand.
What started as background noise
becomes harmful interference over time.
This problem has been with us since the beginning of
Kernighan and Plauger called it out in 1974 with
rule 50 of their Elements of Programming Style:
“Don’t just echo the code with comments—make every comment count.”
Over-commenting in this style can be very helpful when learning a new
programming environment. Everything is unfamiliar,
and the comments help you explain to yourself,
in your own words, what your program is doing. They’re easier for you to read and follow than the still-strange code.
Once you get comfortable in that environment,
the problem of over-commenting often goes away on its own,
since the code is now plain enough for you to read without “interlinear
A New Hope
Once you get past basic API and syntax hurdles,
the confusing parts of your code now become more abstract:
Whole passages that seemed clear as day when you wrote them become clear as mud when you
you return six months later. Over time, you might learn to leave yourself sign-post comments
that minimize this problem.
But the same comment-code skew problem, where the code changes but not
the comments, occurs here as well.
Perhaps we can push what we want to communicate in comments
down into the code itself, so that we are forced keep it up to date?
This leads to the pursuit of intention-revealing code. The hope is that,
through careful selection of variable, class and method names,
we can make our code so lucid that comments become unnecessary.
Intention-revealing code is a worthy aim. Its devotees’ zeal is not misguided.
But you see, it’s not really code per se that needs comments.
We don’t have intention-revealing architecture;
until we do, we must write documentation.
READMEs aren’t just placeholders, they’re your chance to orient the next developer to the overall scheme
of your program, what the major components are, where you got them from
and how they all come together.
Comments should save time over the life of a program
and reduce the amount of legwork the next developer needs to do
in order to understand your program.
Valuable comments provide context
that can be recovered only with significant effort
or that could never be recovered absent the knowledge
and intentions of the original author.
Sometimes our code is a myopic rendering of a higher-level idea.
Which algorithm, from which book, is it implementing?
Why was that algorithm selected,
and which assumptions would lead to discarding it for one
of its alternatives?
The dynamic, runtime context of our objects is often difficult to infer
from the static source code. How does the app use this object, and when?
What’s its typical lifecycle?
What other objects does it collaborate with?
Sometimes, a comment is the only clue a developer will have,
short of having been there from the beginning.
Comments can record historical knowledge:
Why is this class in this particular program?
What about it is most likely to change?
What’s proven a hotspot already?
Comments can also record intentional knowledge:
Is there an easy way to extend the app to accommodate an expected change,
that you’ve provided already, that might be overlooked in future?
JavaDoc Solves a Different Problem
You might notice that the method-level doc comments
popularized by JavaDoc
and available in Obj-C and Swift today
are rarely the sort that provide this kind of value.
Unless you’re authoring a framework,
you’re unlikely to derive much value from method-level comments.
They’re little more than busywork.
With the source code available to you, well-chosen names
and liberal assertions, you’re unlikely to gain much from adding them
to your own code.
Class-level comments, on the other hand, can provide significant value.
They provide a chance to express, up-front, before you even begin
writing the body of a class, what its responsibilities are.
Documenting the other objects it will collaborate with to fulfill those
responsibilities situates it within the context of the application.
Class documentation focused on responsibilities and collaborators
opposes responsibility creep
by helping you keep your classes focused and comprehensible
as your application grows.
But even exhaustive class-level comments
will not begin to address many of the other kinds of context
that we must rely on comments to communicate.
Without such comments,
the developer must resort to archaeology.
In light of software archaeology, don’t forget that this is the ultimate purpose
of all those source control commits you’ve stacked up over the years.
Small, distinct commits say you care,
and good practice
can make history significantly easier to navigate. I’d caution against leaning on version control exclusively for imparting
this sort of information; I’ve been handed too many source-only tarballs over the years.
Expect that your source code will eventually outlive its version history.
Comments form part of a project’s overall documentation.
Unlike some documentation, comments’ intended audience is strictly other developers.
A developer might be on the project for years, or for days;
they might enter the codebase ten days from now, or ten years.
Consequently, comments are about providing two kinds of context:
Situating a local component (method, class, module…)
in a wider non-local context:
You’re new, so here’s how things work here,
and come and meet the neighbors.
Such comments amplify the efforts of someone new to the project
by reducing the amount of the code base they must already be familiar with
in order to be productive.
Situating the current application
in a historical context:
Here is where we started, here is why this is how it is,
and here’s how we anticipated it changing in the future.
These comments provide the knowledge someone needs
to be a productive steward of the project
in light of, and in spite of, its current, imperfect code.
If you comment with the whole picture in mind,
you’ll reap the benefits thereafter. After all, a comment in time saves nine.