Talking Code: Best Practices around In-Code Comments
I always strive to make my code maintainable by making its path logic obvious. I achieve this largely by assigning identifiers meaningful names and by limiting functions to a single action. Given my meticulousness, I always thought of in-code comments as unnecessary. If my code is readable, comprehensible, and obvious, wouldn’t comments just be redundant? This is not to be confused with public interface documentation, which usually takes the form of large comment blocks preceding the definition of the unit to be documented.
In my earliest college programming courses, my professors would commonly tell me my program needed documentation even though I had already provided it in the form of API documentation. What they were really after was for my code to include a few comments within its logical implementation. But often, I ended up with needless text such as:
// Initialize the matrix.
int matrix = new int[rows][columns];
From my perspective, in-code comments should only be used when the code is not obvious. But then again, if the code isn’t obvious one should go back and revisit the implementation. The following code resembles something I recently encountered that would have baffled me:
if (Compare(currentSubject, updatedSubject) != 0)
//update modified to prevent deletion
Were it not for the above comment I would probably had moved the
repository.Update call inside the if. But as it turns out, the program relies on the repository’s individual subject touch information to make a decision whether or not to mark a subject as inactive. Nevertheless, the “need” to include such a comment indicates the code is probably not the most obvious. Further, the underlying framework may require some serious refactoring.
On the other hand, a good company-wide culture of the use of small incremental changes towards source control (in git lingo: commits) with precise descriptions could also serve as a replacement for in-code comments. In the scenario above, I could have looked at the code and realized that such an odd statement ordering might have a reason for being and that reason could be found in the file’s change history.
Still, sometimes we rely on a third party whose source is not available for us to modify and whose behavior is not what we would typically expect. In this scenario, it’s true a comment might be required to alert others about the unconventional nature of the function. But it’s also reasonable—and recommended—to wrap it around a function of our own which documents the odd behavior of the external function.
For instance, let us imagine we are consuming a C# third-party Complex Number definition which contains a
TryParse method. This method’s signature, however, is different from the .NET framework
bool in that, instead of
result being an
out parameter, it is a
ref parameter. We would then perhaps wrap it as:
Although I don’t want to make a case for what is “obvious” code, I would also discourage the use of comments to explain syntax or language features no matter how obscure or complicated these are. For instance:
/* "identifier" is a constant pointer (cannot point to a different location)
* to a constant int (its value cannot be modified).
int const * const identifier = ...;
Perhaps, not commenting something like this will encourage both the author and the maintainer to ‘agilize’ their minds until more sophisticated syntax comes as naturally as
int identifier = ....
I hope you have found this in-code commenting lesson helpful. Full disclosure: at Propelics, confusion avoidance is a major priority. So our practice is to always provide ample explanatory material along with additional documentation and small incremental commits. Got a question about this approach (or any other mobile strategy question)? Then give us a call! We’d love to hear from you.