When I first started programming I was horrible with comments. I honestly didn't write them because I didn't see the point. The reason I did not do it was because I was never forced to maintain any of my code. In school we often wrote little programs that were a couple hundred lines long that was discarded after each assignment. Despite my teacher's best efforts it never struck me as to why comments are necessary. I would comment my code when forced to by my teacher. This lead to inane commenting like the following:
//Assign 5 to foo
int foo = 5;
If anything my commenting here has hurt the readability of the code because it clutters it with needless information. If you know the language, you know what an assignment statement looks like, making the comment unnecessary. It was only once I started working on an J2EE application with approximately 200,000 lines of code that I understood why you comment. After much thinking about it I've come to the conclusion that you comment to justify the code. What I mean is if someone reading your code was to ask "Why does this code exist?" the comment should provide the answer. My comments tend to be long winded compared to most other developers I've encountered, because of this approach. I often make statements about the origin or the history of a piece of code to give context. I also believe in making the comment conversational or tell a story. This makes it both easier to read, more fun to read, and simplifies the communication. I'll write something like the following:
//The item has to be added to the collection before the call to the next function
//because the control throws an exception if the item is not in the collection
//yet. It'd be better if we could do it later on but we are limited by the existing
//structure. If we refactor the control to use WPF we should revisit this.
This of course is completely contrived and doesn't relate to any real code. I am trying to demonstrate what I believe is a good commenting style. I am doing the following things:
- I justify the positioning of the code and why it exists there.
- This lets a future developer (or which might be me) know why the code is set-up as it is and that the order has a logic to it and what that is
- It also prevents a developer who is refactoring the code from unwittingly creating an error. I hate when I move something that appears to have no effect on the logic but then a strange edge case appears that causes an error. Even worse is when you talk to the original developer and they knew about the error potential but did not document it
- I also acknowledge any short comings.
- This is partly me protecting myself from future developers being to angry at me. I cannot count the number of times I've read someone's code and just questioned their sanity for coding something in a certain manner. There might have been logical justification for doing it that way and if I understood that I probably would accept it. I still may dislike the code but at least I now have context
- This also provides information to someone who want to improve the code in the future. At some point in the future someone will be changing that code. There may be a way to perform the operation in a better manner. If that person may be less experienced with the code base or less experienced in general they may just assume that this is a good piece of code.
- It raises a do not copy and paste this flag for people. Nothing is worse than seeing a poor piece of code copy and pasted. Inexperienced developers make this mistake often. They know a piece of code works but they don't understand it. They therefore copy, paste it, and never examine it closely. A comment that acknowledges short comings encourages a deeper level of thinking.
- Provide an upgrade path
- If there is some point in the future that the code be changed to remove the short comings and I know what that point is I mention it. I don't necessarily think that those short comings will be removed right away when that upgrade point change occurs but it provides a reference point to make the change.
It is impossible to link every piece of code to meaningful external references, but sometimes providing that link is vital. The easiest link to provide is to requirements management systems and defect tracking systems that give unique identifiers that can be easily referenced. If a change for a requirement or a defect is fairly esoteric and isolated to a small code section I will often include the ID of the requirement or the ID in the comments for the code. Sure, a tool like subversion can be used to gain the same information, but that requires an additional step that most people will not undertake. It also gives me traceability back to the defect tracking system, which occasionally comes in handy on its own. Defects and requirements are not the only links that can be put in comments. If you keep meeting minutes or a record of conversations you can provide a link by putting in the date of the conversation that was the basis for the change. Architecture and design documents can be referenced in similar manners. Instead of trying to reexplain in detail why something works the way it does, reference the existing documentation. If a change significantly changes behavior starting at a certain version number, it doesn't hurt to mention that with that version number the functionality has changed.
You can go overboard with this to the point that it becomes annoying. Just like the first example of commenting an assignment statement, you don't want to make it so the comments lose meaning. For example I don't link to a defect number if the defect occurs because of a null reference that is avoided by a simple null check. Generally, I add the link and level of detail if
- The change required significant archeology on my part
- If a fix for a defect was non-intuitive
- It seems likely that similar changes will need to be made in the future
- The way something was functioned was specifically prescribed by a meeting or a document