Categories
Allgemein

History Comments

Comments are a useful tool to give contextual information directly in the source code. They are most typically used as a clarification comments and documentation comments (top Google result for code comments). However, there is a third use which I found comments to be useful for, documenting history!

History Comments

What is a history comment? A history comment is a comment that describes the changes done to the code in the past.

It may be a drop-in replacement of removed code:

int main(int argc, char *argv[]){
    // Removed calculation of twoPow(-1) here
    // because the function did not handle negative integers.
    std::cout << twoPow(7);
}

It may be a description of a changed line:

int main(int argc, char *argv[]){
    // Previously printed "Hello World" here
    // but now there are real calculations.
    std::cout << twoPow(7);
}

Or it may be a description of why something was added:

int main(int argc, char *argv[]){
    // added this calculation, because I was interested in
    // the amount of possible values in uint8
    std::cout << twoPow(8);
}

It may be a description of a failed change attempt:

int main(int argc, char *argv[]){
    std::cout << twoPow(8);
    // tried to use the calculated value
    // as a return value but that sets
    // it as the exit code in main
    // (exit code not 0 is a bad idea)
}

They are intended to give more information about the history (the past changes) of code. In that way it is comparable to the git history, except that commit messages are out-of-code historic documentation of the code and history comments are in-code historic documentation.

How can it help?

Adding history comments to the code may help development in multiple ways.

First off, it is just additional information that future developers may work with. Not knowing why a change was done might lead to attempting a non-working solution twice. Not knowing why a change was done might lead to introducing the same bug twice. Not knowing something about the code is always worse than knowing something about the code. Obviously, this rule somehow breaks when the code gets completely cluttered with comments and it is hard to find an actual line of code in there. I did not once run into this situation yet. Developers tend to under-document their code, not over-document it.

The second advantage is that it makes (git) diffs better.

--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,14 +1,17 @@
 #include <iostream>
+#include <cmath>

 #include "main.hpp"


 template<typename ValueType>
 auto twoPow(ValueType value){
-    return 2 << (value - 1);
+    // was previously calculated as 2 << (value - 1)
+    // that did not work for floats
+    return std::pow(2, value);
 }


 int main(int argc, char *argv[]){
-    std::cout << twoPow(7);
+    std::cout << twoPow(7.f);
 }

This especially comes in handy for code reviews where lines are otherwise removed, no reason given. The reviewer then has to deduce from the context, why that line might have been bad (or superfluous). If it is instead replaced by a history comment (i.e. //previously the value was cast to an int here, but this did not work for classes that behave like an int arithmetically, but are not castable), it becomes quite clear why a change was done. Admittedly, code review tools could do a better job here by inlining the commit message with the full-text code review, but that might again not work when doing a command-line (git) diff.

History comments are highly contextual. They are embedded directly in the source code, change with the source code and get removed or changed when work is done on the source code. This is the main advantage over out-of-code documentation like git or Markdown files.

Alternative: Function Changelog

An alternative to adding comments directly to where a change was made is keeping a per-function changelog in the header documentation of a function.

template<typename ValueType>
auto twoPow(ValueType value){
    /**
     *  Changelog:
     *  - changed calculation to make use of the cmath function std::pow
     *  - calculated twoPow by bit-shifting
     */
    return std::pow(2, value);
}

This is a tradeoff between the direct contextualization of changes with history comments and less comment-cluttered code. There will be only a single point in each function where information about its history may be expected. This, ultimately, comes down to taste and is more of a stylistic choice. Some documentation tools support this. Doxygen, for example, allows providing \version tags to document changes in the Doxygen documentation header.

By Tilmann Matthaei

I'm an aspiring software professional looking to share what I learn about reliable software along the way.

I hold a Bachelor's Degree in Applied Computer Science - Digital Media and Games Development and am working in software development since 2018.
I have experience in embedded development (mostly in C++) as well as Continuous Integration and IT Security.

Feel free to contact me via tilmann@matthaei.dev.