The comments you write can be revealing about the quality of your code. Countless times I've removed comments in my code to replace them with better, clearer code. For this I follow a couple of anti-commenting rules:
- If your comment merely explains a line of code, you should either let that line of code speak for itself or split it up into simpler components.
- If your comment explains a block of code within a function, you should probably be explaining a new function instead.
Those are really the same rule repeated for two different contexts.
The other, more normal rules I follow are:
- When using a dynamically-typed language, document the expectations that important functions make about their arguments, as well as the expectations callers can make about the return values. Important functions are those that will ever have non-local callers.
- When your logic is dictated by the behavior of another component, it's good to document what your understanding and expectations of that component are.