1. Favor commenting why over how. It may be clear how your function works, but it's rarely self-evident why you chose to use a particular technique -- another will probably seem (perhaps correctly) like a better choice to someone else. Subtleties of design choices and lessons learned from mistakes are much harder to just infer while looking at code than surface details about how it works.
2. If you're about to write a comment, see if better names make it unnecessary, or if breaking a section of a function into a named subfunction clarifies things. (The corollary being that there's nothing keeping you from naming all your stuff "dude" and "heyHeyHey" besides bitter experience and the eternal scorn of your peers.)
3. Consider using asserts, tests, or the type system in place of some comments - they're like comments, but they're actually checked.
4. Consider datestamping any comments more than a few words. (Do it automatically, with an action in your editor.) It only takes a few characters, and sometimes it will be unexpectedly helpful. (A good VC system can help you track down when a given comment was added, of course.)
I'm with you on 1-3, but #4 seems wrong. What purpose is there to knowing when the comment was added if you don't know when the code was written[1]. This just looks like a trick you've developed to try to figure out when a comment is lying to you. But if you have so many comments that you doubt their veracity, you have too many comments. Read the code for truth.
[1] Without, as you mention, using your SCM system. But I'd argue strongly that if you can't do the equivalent of "cvs annotate" from memory, you're using the wrong system or you don't understand it well enough.
In my experience, it has been helpful in untangling contradictory changes based on changing customer specifications over time. Mostly, I think it's worth doing because the cost of doing so is really, really low (e.g. a hook to your add-block-comment function, a few characters), but there are edge cases where it's very helpful. Take it with a grain of salt, of course. (I edited #4 a bit.)
I agree with you about the annotate part, but (for example) I'm not clear if there's a cheap and/or fast way to find at what point a comment appeared in Perforce, when it may have been added six release-branch merges back. (I recently started using Mercurial for my personal projects. Night and day.)
There's a somewhat parallel debate about the pros and cons of signing comments.
Even among experienced developers, assuming for a moment that it is possible to write perfect code that doesn’t require comments...
Why is the author talking under the assumption that "perfect" code wouldn't require comments? I would imagine perfect code to have consistent style, an intelligent and intuitive separation of concepts, etc. I don't see a good reason it should strive to be human readable. Quite the opposite, actually - I find good code will often use mathematical abstractions that simplify the problem greatly, but are nearly impossible to understand, and need extensive comments to explain.
Yes, absolutely. Although in the extreme of complexity, comments actually stop helping. A straightforward implementation of, say, RSA or an FFT can actually be done in small, simple, well-organized code whose structure is "obvious" to someone who understands the problem. But no amount of comments is going to help the reader understand the algorithm to begin with. In those circumstances it's much better just to document what you're doing and let the reader go to their textbooks.
This issue has always been about time. It doesn't matter how clean the code is, it can still get complex. If it takes someone less time to read your comment than to read code and finally know what the function does, this is a situation where a comment is valuable. Just do it and stop the philosophical debate when productivity is the issue.
1. Favor commenting why over how. It may be clear how your function works, but it's rarely self-evident why you chose to use a particular technique -- another will probably seem (perhaps correctly) like a better choice to someone else. Subtleties of design choices and lessons learned from mistakes are much harder to just infer while looking at code than surface details about how it works.
2. If you're about to write a comment, see if better names make it unnecessary, or if breaking a section of a function into a named subfunction clarifies things. (The corollary being that there's nothing keeping you from naming all your stuff "dude" and "heyHeyHey" besides bitter experience and the eternal scorn of your peers.)
3. Consider using asserts, tests, or the type system in place of some comments - they're like comments, but they're actually checked.
4. Consider datestamping any comments more than a few words. (Do it automatically, with an action in your editor.) It only takes a few characters, and sometimes it will be unexpectedly helpful. (A good VC system can help you track down when a given comment was added, of course.)