One of the greatest risks with code comments is that they get out of sync with the code. When this happens, they can become actively harmful to the understanding of anyone who reads the code (including the original author!).
In my article on Signal vs. Noise, I drew a chart that showed Signal on the horizontal axis and Noise on the vertical axis. I talked about how excessive comments that don't convey meaning beyond the code itself can distract or even obscure the code.
What I did not show is the negative side of the horizontal access. So, what would be to the left of the vertical axis? Disinformation.
Negative signal is disinformation.
In today's political environment, we often think about disinformation as an active campaign that bad actors carry out to poison our discourse. But when we write code, sometimes we're the bad actors.
This happens despite our best intentions. Here's how this usually plays out.
- Write new function.
- Add awesome comments.
- Weeks go by.
- Requirements change.
- Change code to meet new requirements.
- Forget to change comments.
- Months go by.
- Developers come.
- Years go by.
- Developers go.
- New developer tasked with maintaining software discovers that code does one thing but comments say it should do something else and which one should she believe because both possibilities could be correct and is the code wrong because the previous programmer wrote incorrect code (it's been known to happen) or is the comment simply stale and the requirements changed along the way (it's been known to happen) and boy, oh boy, wouldn't it be nice to have proper version control right now.
Mitigating the problem
Here are three tips for dealing with this issue.
Write self-documenting code
The best way to avoid comments going stale is to avoid writing comments! Here's a contrived example to demonstrate the concept:
'*** Instead of this... 'Check if ReportDate is in the past If ReportDate < VBA.Date Then '*** ...do this Dim ReportDateIsInThePast As Boolean ReportDateIsInThePast = (ReportDate < VBA.Date) If ReportDateIsInThePast Then
Both code snippets above convey the same information. One does it with comments and the other does it by declaring a boolean variable with an overly descriptive name.
The advantage is that when the requirements change some day, you're way more likely to update the name of the boolean variable than you are the code comment.
Keep comments close to the code they document
This mainly applies to so-called "header" comments, those comments that appear above the Sub or Function declaration line. I tend to put comments there that describe the function's purpose along with notes that address ambiguities. For example, if my function returns a collection type and the collection has no items, does the function return
Nothing or a collection object where
.Count = 0?
Since these comments appear above the declaration line, the only way to ensure they stay close to the code they document is to keep the routine itself short. A good rule of thumb is to try to keep your routines short enough that every line of code will fit on-screen without having to scroll your window. For me, I would guess that the median length of my routines is somewhere between 20 and 30 lines of code.
If I'm getting way beyond that size, I will look for a chunk of code that I can accurately describe in a few words and pull that out into a private Sub or Function. I tend to look for opportunities to remove levels of nesting when I do this, which also helps with readability.
Use proper version control
This is by far the most important tip. Perhaps you've heard the phrase, "an ounce of prevention is worth a pound of cure." That may be true, but if I could only spend my money on prevention or cure, I would still buy the cure. And in case you haven't made the connection yet, version control is the cure in this case.
Version control is the closest we've come to building a time machine.
If our comments and our code ever get out of sync, we can go back through the file history to see where the two diverged. If the comment was added in the same revision as the code, then the most likely explanation is that the comment described the requirement correctly and the code is wrong. On the other hand, if the code was changed two years ago, but the comments were originally added four years ago, then chances are the requirements changed and the comment is now stale.
Stale comments are still a problem ("ounce of prevention," and all that), but at least with proper version control we can recover from the confusion.