The basic rule I follow is, if it takes me longer than ten seconds to figure out what a section of code is doing, it needs a comment. Maintaining code is hard enough without having to waste time reading every line of code just to understand what you're maintaining. I find the best way of "commenting" code is to write code that documents itself. This means using long_descriptive_ variable/function names and using good programming style. I tend to comment as I go while the code is still fresh in my mind but I also reread the code later and if I look at something and go "what the hell did I do there?" then in goes a comment.
All my programs start with a lengthy comment that describes the file, it's function, version, last revision, author(s) and anything else that other coders need to know. All functions are commented with a purpose, pre and post conditions. It's also handy to include the date and person who made a certain revision to a line of code (that's if you're not using CVS or some other similar software). So you know who to blame ;).
