Code Documentation Guide

Alexey Akimov
3 min readJun 16, 2017

--

This is my summary regarding the code documentation ideas. Of course, the topic has been discussed many times by many developers. But this is something based on my vision of the topic, especially as our codes at the Quantum-Dynamics-Hub are concerned. Also, this is meant to be resource for the developers (students, postdocs, collaborators) I work with, so that if you are reading this, you may already be one of them :) I hope, I’ll update this document and the vision evolves.

1. The documentation should be meaningful and non-trivial. This means it should contain some information that is not obvious from the names of functions/variables.

Bad:

class matrix{public:
int n_rows; ///< n_rows
...
};

Better:

class matrix{public:
int n_rows; ///< The number of rows
...
};

2. It must provide the information on the purpose of functions and variables. For function — what does it do? For variables — what does it represent? Provide a rationale/justification for some design decisions made, especially it that took long time and has a long history/background behind it. This will help other developers not to repeat those trials that you might have made. Also, if possible, provide some ideas on other design decisions related to the presently documented item (this is not always needed).

Bad:

class matrix{/** A matrix class */
};

Better:

class base_matrix{
/** The class representing an arbitrary-sized arbitrary-type valued matrices
It implements ONLY the methods and operators overloads that do not return anything of the same base class. Those operators/functions will be implemented in the derived classes, to avoid confusions with the data types.
This has been a hard decision, but other approaches seem to be even less suitable: 1) template specialization — would require re-implementing same methods for different data types 2) inheriting methods that return the templated data class (e.g. base_matrix<double>) would lead to a confusion with the derived classes (e.g., MATRIX::base_matrix<double>). One way to make everything consistent is to use converters, but that would incur extra consts for copy-constructors etc. That is why, we are going to ensure that MATRIX class is not just a typedef base_matrix<double> We stil do not want to re-implement common methods, so we’ll create free templated functions here acting on even more basic datatypes and then, will re-use them in the derived class, yet keeping in mind the above considerations*/ public:...};

3. Documentation of the function arguments should contain the information on:

a) the type of the variables (int, double, vector<int>, list of ints, etc.). This is trivial for C++, but is strongly recommended for Python;

b) the meaning of the variables (see p. 2);

c) the purpose of the variables: input, output or both;

Bad:

def hop_py(initstate, g, ksi):
# Implements hopping

Better:

def hop_py(initstate, g, ksi):    
## This function implements a simple surface hopping procedure
# \param[in] initstate [ integer ] The state index before hop # \param[in] g [ MATRIX ] The surface hopping matrix, the element g(i,j) contains the probability of the i->j transition
# \param[in] ksi [ float ] A random number uniformly distributed in the range of (0.0, 1.0)
# The function returns:
# finstate [ integer ] The index of the final state after hop

4. Documentation of the functions should contain the information on the returned result: how it is returned (explicitly or via some of the arguments), its type and meaning.

Example: see above

5. Be style-consistent. One of the examples — so far, we adapt the documentation of the functions to start right after the function name line, not before.

No:

##  Documentation goes here
def hop_py(initstate, g, ksi):

Yes (Python):

def hop_py(initstate, g, ksi):    
## Documentation goes here

Yes (C++):

void excite(int I, int J){
/** Documentation goes here
*/

Same for classes (C++):

class Hamiltonian{
/** This is our functor class: it manages customized Hamiltonian calculations customization is realized via inheritance common interface is realized via virtual functions ...
*/
...

--

--