Summary:
How and why to document your code using the free tool Doxygen, make your documentation available online, and how to automate the process with free tools.
“Comments often are used as a deodorant.”
— Martin Fowler and Kent Beck, Refactoring, page 87
Forward
The agile software manifesto states:
Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan
That it values items to the left more (emphasis mine) than items to the right. Of the four universal statements, I believe the second one is the most misunderstood. Without working software, comprehensive documentation is null and void. The operative word here is comprehensive. It takes time and effort to create comprehensive documentation. But it should never be an excuse not to create code documentation.
What use is code documentation?
I believe documenting the code is different from just commenting on it. If you are trying to reduce the “odor” of code by commenting on it you better refactor the code to make it more understandable. I believe code documentation should:
Provide information that cannot be expressed by the code
So, what kind of information does code documentation provide that cannot be expressed by code?
- Requirement traceability: A unit of code – be it a function, class, module, or component – should be traceable to one or more requirements. Requirement traceability is required to answer two fundamental questions: are we building the right product? Are we building the product correctly? Code documentation can embed requirement identifiers that enable forward and backward tracing to code.
- Design by contract: This method of software development has its roots in the formal verification of software. A contract is a unit of code. We have the following three questions that need to be answered by this contract:
- What does the contract expect?
- What does the contract guarantee?
- What does the contract maintain?
Such strict rules ensure software correctness and can be written by code comments – especially in languages that have no native support for contracts.
- 4+1 architectural view model: In the 4+1 architectural view model, the development view is concerned with code. This is the implementation view. There is no reason why code documentation cannot allude to other views – especially the dynamic view and the deployment view.
- As a heads-up to the maintainers: I cannot describe it any better than the image I found on the internet:
- Regulatory requirement: In some domains like medical devices, code documentation is mandatory as it is a requirement to pass Food and Drugs Authority (FDA) regulations. In such situations, the metric of code to comment ratio will be enforced.
- API documentation: Systems which expose services through APIs (REST-based) need to provide API documentation. This documentation is exposed to the clients as API documentation. It helps clients to understand the functionality of exposed APIs and consume them as per specification. Also, as APIs change over time (with new functionalities getting added, and older ones getting depreciated) API documentation should state the versioning information.
Doxygen – Documentation Made Easy
In the previous section, I believe I have driven home the point that code documentation is important. Although code and code documentation both go into the source code file, it would be unwise to read the file for documentation. Separation of concerns is what we need:
Doxygen is a well-known tool to generate documentation from annotated sources for different programming languages like:
- C and C++
- Objective C
- C#
- PHP
- Java
- Python
- Fortran
- ..etc
Doxygen can generate both Online (HTML hosted on a server viewable through a browser, e.g. D-Bus documentation https://dbus.freedesktop.org/doc/api/html/index.html) and offline documentation (in RTF, PDF, PostScript, or LaTeX formats).
Doxygen is a mature open-source project and has been around for more than 20 years. It is well maintained because it solves a vital problem of generating code documentation from annotated files thereby delivering value.
Doxygen Example
For this demonstration, I am creating a blogging system in C++ to show off some code. Here is one header:
BlogEntry.h:
#pragma once
/*! \file BlogEntry.h
* \brief The BlogEntry class is defined in this file
*/
#include <chrono>
#include <string>
/*! \namespace BlogChrono
* \brief Currently based on std::chrono, but can be changed
* later to other non-standard library if the need arises. \n Code based on this
* namespace should not change.
*/
namespace BlogChrono = std::chrono;
/*! \class BlogEntry
* \brief The BlogEntry class
* BlogEntry is a domain object under the bounded context
* of our blogging system's domain driven design. Every BlogEntry has the
* following characterstics:
* Title: The title of the blog \n
* Author: The author of the blog \n
* Published date: Date of publication of blog \n
* Keywords: SEO keywords in the blog \n
* See also : Blog.h \n
*/
class BlogEntry
{
private:
std::wstring m_Title;
std::wstring m_Author;
const BlogChrono::time_point<BlogChrono::system_clock> m_PublishedDate;
public:
//! Blog published date in a nice format so as to embed in a page
std::wstring GetPublishedDateInHumenReadableForm();
///...showoff our expertise in domain driven design...///
// ...
};
BlogEntry.cpp:
#include "BlogEntry.h"
/**Create a wide char string that is human readable to embed into a
* blog post.
@return: Empty string if conversion fails, else a valid string.
*/
std::wstring BlogEntry::GetPublishedDateInHumenReadableForm()
{
return std::wstring();
}
As you can see, I have documented my code using Doxygen markups. To create HTML-based documentation that I can host online there are several possibilities:
- Option 1: Download and Install Doxygen myself (including the graphviz tool for creating graphs within Doxygen), configure everything myself, run it myself and upload the documentation to the cloud to a hosting service myself.
- Option 2: Use CodeDocs which takes care of all that and automatically does it (however, it’s only for public repositories on GitHub and it does not create any graphs in your documentation nor does it maintain version control of your documentation).
- Option 3: Use a GitHub action that generates the documentation automatically and uploads it to your GitHub pages (however, this does not maintain any version control of your documentation). There are several GitHub actions available in the GitHub marketplace.
Here is the experience with Option 1:
- Download and install Doxygen. Once installation is done, you should be able to print the version of Doxygen from the command line using doxygen -v
- Create a configuration file in the same directory of your sources by the command doxygen -g <configfilename>
- The created democonfig file needs some edits. Here is what you need to do:
Won’t it be nice if this can be automated?
Edited
- Now run the command: doxygen democonfig
You will see Doxygen preprocessing and parsing the headers and sources of your project. Once done, you can check the generated documentation using a web browser by navigating to .\html\index.html page.
Let us give a project number and see what changes.
PROJECT_NUMBER = 3.14
And regenerate the documentation.
Version made explicit:
- Here is how the documentation for the class would look like:
Here is how the documentation for the header would look like:
Adding versioning to the documentation is very important – as important as versioning the source code itself. Keeping documentation and code versions in sync manually is a pain. That is why it is highly recommended to automate this process and have it done in sync with your version control on Git.
How to set up an automation for syncing your Doxygen documentation with your code?
The use of automation should have two main purposes:
- Maintain version control of your documentation that is in sync with your code version control
- Automate the process to save you time
How to do it?
You can implement this in numerous ways using an automation server such as Jenkins or using GitHub Actions etc. But that kind of implementation requires a bit more technical skills and a longer learning curve. If you are not proficient with automation servers and would still like to automate this without having to learn too much, then the SIMPLEST and most straightforward way to implement this is by using a pre-commit hook. This is ideal if you are a really small team or just working yourself on a project.
When using a pre-commit hook you can write a script that automatically creates the documentation for you and stores it in your repository (with your code) before your code changes have been committed. This way your code and documentation are always in sync. If you are using GitHub Pages you can even set up GitHub pages to show the most recent version of your documentation at all times and this way you get your documentation online. If, however, you need to see a previous version of the documentation, it won’t be visible on GitHub pages, but you can always checkout the relevant commit to your PC and open it locally. Also, GitHub Pages will show your documentation to the public even if your repository is private. You can control the visibility of your GitHub Pages only if you upgrade to GitHub Enterprise (which is quite costly).
The disadvantage of using a pre-commit hook is that your script relies on the installation and configuration of Doxygen on your local machine. If another team member wants to use the same script on their machine, they must set up things exactly the same way, otherwise, you might get discrepancies in the outcome of your documentation. If you were to use an automation server, then everything is set up on that server, and then you get consistent results for all users of the script. That is why I recommend using a pre-commit hook only if you are a small team or a solo developer.
Summary
Comments definitely should not be used as deodorants. Code should never smell. If the project has design or code smells, use that as a guiding principle to refactor your code. Maintain code documentation. It has a direct impact on the internal quality of your system. You must maintain your code as well as your documentation making sure that they are in sync. As a follow up I recommend checking out our other post on how Doxygen documentation can help you write better code in C and C++.