A delicate matter, requiring taste and judgement. I tend to err on the side of eliminating comments, for several reasons. First, if the code is clear, and uses good type names and variable names, it should explain itself. Second, comments aren't checked by the compiler, so there is no guarantee they're right, especially after the code is modified. A misleading comment can be very confusing. Third, the issue of typography: comments clutter code.
— Rob Pike, Notes on Programming in C
I used to be staunchly against comments, but I came to appreciate them. Like many things, it isn't black and white.
It is true in most cases, code with good names, types, and abstractions should explain itself. However, explaining the what of the code is only one of the useful modes a comment has. And it's easily the least common/useful mode.
Let's explore the questions that comments can help us answer.
Why does this code exist?
It is not self-evident why all code exists. One of the best use cases for a comment is to answer "why?", not "what?".
/*
* Distribute memory according to CPU & memory use on each node,
* with 3/4 hysteresis to avoid unnecessary memory migrations:
*
* faults_cpu(dst) 3 faults_cpu(src)
* --------------- * - > ---------------
* faults_mem(dst) 4 faults_mem(src)
*/
return group_faults_cpu(ng, dst_nid) * group_faults(p, src_nid) * 3 >
group_faults_cpu(ng, src_nid) * group_faults(p, dst_nid) * 4;
This is an example of a good comment from the Linux kernel, which concisely captures both the "what?" and the "why?" of a non-trivial expression.
What are we doing?
Distributing memory, according to the formula shown above.
Why do it like this?
We're adding a 3/4 hysteresis to avoid the churn and burn of twitchy, sensitive-to-change migration formulas.