Code Clarity, Commenting, and Documentation for a Specific Purpose
Posted by Dan Vanderboom on February 2, 2008
I am currently transitioning from one job to another. As such, I find myself looking through three and a half years of source code, and analyzing it from a perspective of needing to make sure that it’s maintainable for those who follow me. One trend that I observe is the gradual decline of comments I’ve written over the years. Not because I feel they are less important now than in the past, and certainly not because of laziness (I am very consistent and meticulous about my code). As I will explain, the slimming down of comments isn’t necessarily a bad thing, and the number of comments isn’t directly related to the clarity of code.
It has to do with the mind set and skill level of the developer. When I started my current job, I had been doing VB.NET development for a few years (after a succession of other languages), and C#—other than what I’d experimented with in MSDN magazines, and despite my experience with C and C++—was basically new to me. I found myself commenting anything that was different from past language experiences, such as delegates and events (different syntactical style in VB.NET versus C#), or new design patterns or idioms that I learned or created.
Over time, familiarity with the language, the patterns being used, and the framework caused many of those comments to seem superfluous and redundant. Things that once seemed odd—delegates, reflection, use of nested dictionaries, exception-handling patterns—have become so second-nature that comments describing them decreased in perceived value dramatically. Add to that the fact that comments themselves are assets that need to be updated along with the code they reference, and the creation of unessential comments becomes something of a small burden to add to a rapidly-growing pile.
Up until now, when deciding whether to add a comment to a section of code, I’ve asked myself this question: if I were going to look at this code several months or years from now, what about it would be confusing at first glance? This has led me to write clearer code, breaking operations that could appear on one line into several, and naming variables in the clearest way possible to indicate their role in whatever algorithm they appear. This, I find, precludes the need for some of the comments I may have otherwise felt the need to write. If we can write code in a way that is self-describing—making the best use of identifiers to do their job and identify purpose—then comments will often seem redundant. (The purpose of a good comment is to clarify code, not to instruct a beginner on “how to program 101”.)
Coming up with good, accurate identifiers is an art in itself, and comes only through a great deal of experience, learning to describe the entity’s purpose instead of the implementation details whenever possible, being very specific instead of defining ambiguous methods like Process or DoWork. Naming things consistently according to a unifying metaphor (or set of metaphors) also helps to clarify how all of the pieces fit into a coherent whole. Above all, one must be willing to refactor and rename whenever it will enhance code clarity.
Not all comments can be obviated in this way, however. Sometimes, algorithms are just plain hard, or the entities you’re working with are so abstract (such as manifests full of collections of cached reflection metadata) that comments are critical. The need for comments in situations like this may be an indication that there is still an opportunity to refactor and make the purpose more clear, but since unoptimal solutions will always exist, and our opportunities to refactor are often limited by time, resources, and therefore other priorities, comments in these situations do serve a very useful purpose.
So without being irresponsible and leaving those who follow us with an undecipherable mess, while at the same time minimizing redundancy and unnecessary work, how can we come up with a code documentation strategy that makes sense?
First, I would consider the level at which code is commented. There are comments we place above or to the right of a single statement, comments that describe a following block of code, and comments that appear on larger entities (such as methods and classes). Method comments, whether XML or not, are a good place for defining the purpose and describing the strategy used. If you feel that comments for every few lines of code creates unnecessary clutter, this may be a good place to provide some guidance. With a little bit of contextual information, it is much easier to figure out how each line participates in the method’s strategy, and class-level comments can describe how that class fits within a larger design pattern.
Second, if you find yourself continuously copying and pasting comments because you keep reusing the same pattern or idiom that would, perhaps, be unobvious to outsiders, then you have an opportunity to consolidate those comments into your software solution’s design documentation. I have discovered and identified fourty- or fifty-some patterns that I’ve used consistently throughout my current software system; and this list, along with descriptions, should serve as good prerequisite reading and background information for future developers, along with several diagrams of complicated interactions and dependencies. If we as object-oriented developers value code reuse, then we should embrace comment reuse as well, and consolidate this knowledge in a place outside of our code base. Having and updating this list can also serve as a reminder of the strategic level of your coding patterns, and give your software a more tangible form of stylistic identity.
Third, identify the purpose of comments and your target audience. If you’re developing a system in-house, working on a commercial software system, or building a development library that you deliver with source code (or XML comments supplied for Intellisense), you will have different sets of eyes and different perspectives to consider. Is the project huge and convoluted, or small and simple? Sometimes the simple question of “could I understand it later?” is too short-sighted. Coming up with a set of principles to follow will make all of your individual documentation decisions much easier. Just as comments are used to indicate the purpose of your code, identifying the purpose of your comments is the surest way to a sensible documentation strategy.