In this artile, we will look at how to structure a 1-page readme file that you must provide for each and every software project you embark on from now on. Be it a short library or a complex code base, you owe it to your users (and yourself) to provide a minimum set of instructions that allow users to see, in a few minutes, what your code does, how to get it to work (compilation and/or installation), and finally how to use it.
By the end of this article, you will have internalised the proven structure of a 1-page readme file that should be used for each project, You can adapt it to your project needs, but the presented sections are the bare minimum that you need to document code. We will also look at the most popular markup language used to write technical documentation which is called Markdown. You will see that with a minimum set of instructions, you are able to write rich and beautiful technical documentation.
After looking at the basics of Markdown editing, we apply that knowledge to write the missing 1-page readme files for our previously developed linear algebra solver and mesh reader libraries.
Download Resources
All developed code and resources in this article are available for download. If you are encountering issues running any of the scripts, please refer to the instructions for running scripts downloaded from this website.
- Download: linearAlgebraSolverLib.zip
- Download: meshReaderLib.zip
In this series
- Part 1: Documenting code; why bother and how to do it right
- Part 2: How to write a 1-page readme file to document your code
- Part 3: How to write a user guide to document your CFD code
- Part 4: How to annotate C++ code for automatic code documentation
In this article
Introduction to documentation markup
In our last article, we looked at different types of documentation and mentioned that we have essentially three types to choose from; the 1-page readme file, the user guide, and the annotated code documentation. We will concentrate on the 1-page readme file in this article.
If you want to sit down and type out your documentation, we are not just writing text, but for anything longer than a paragraph or so, we want to structure the text with section titles and sub-headings. If we want to show specific code snippets and comment on them, then we require some support to render the code.
For our purposes, we are interested in writing CFD solvers and related libraries, so we may also want to show some equations. Later, we want to show some references and link back to them, and perhaps show some sample output and structure that into a nice table.
Thinking about all of these use cases (and you may come up with more), the question then arises of how we should write our documentation. We could open up a text editor and start writing away, inventing our own creative syntax ASCII-art-like to separate sections and display tables, but certain things like equations and displaying images will not be possible.
Luckily, we don’t have to reinvent the wheel and we can make use of solutions others have come up with before us. There exists a plethora of so-called markup languages, that allow you to style your text using a specific syntax. The most popular markup languages in use, when it comes to code documentation, are markdown and restructured text. There exist other popular languages such as wikitext which, as the name suggests, is used on Wikipedia and related websites to markup text for articles, and you can find an overview of other, less known, markup languages here.
All of these markup languages have one thing in common; they take the annotated text and transfer it into some form of HTML document. A dedicated reader is then required to display your marked-up text. But once again, we don’t have to worry about this. If we are using markdown or restructured text, we stand a good chance that our code editor or online repository, where we want to show our documentation, has a dedicated reader already available for us.
Let us remind ourselves about the structure that we want to follow in our 1-page readme file. This is taken from our last article in a slightly adapted form, where we discussed different types of documentation approaches:
- Introduction: This section describes what problem this library or code is solving. The first sentence should be a description that summarises the entire code in a single sentence. Any following sentences may provide additional background and motivations for this library/code.
- Installation: This section shows how to install the library code. For interpreted languages such as Python, this may be as simple as downloading the code from a remote repository such as GitHub, but for compiled languages like C++, it is useful to include instructions on how to build the code, potentially with different instructions for different operating systems.
- Usage/Examples: Anything you want your users to be able to do straight away after installing your library/code should be covered by an example with some additional explanations as required. This section should contain all of these examples/tutorials. These may be grouped into sub-sections if you have a few examples to go through.
- References: Anything you want to reference should go here. This can be reference papers or other libraries that are used.
In this article, we will look at how we can use markdown to write documentation of this form. First, we will go through the syntax to learn markdown and you will see that it is pretty straightforward to use markdown for documentation purposes. We also look at badges and how we can use them to convey quickly key aspects of our code. Finally, we will apply this and write two documentations; one for our linear algebra solver library, and one for our mesh reading library based on the CGNS file format.
Markdown: The tool of choice for documentation
In 2004, John Gruber created Markdown as a simple but effective way to format text. At the time, formatting was predominantly performed in HTML, but this mixes formatting and text, which is not ideal when writing documentation. The idea behind markdown, and any other markup language, is to provide intuitive markup clues that can be interpreted by the markup interpreter and translated into valid HTML.
The popularity of markup is explained by its extremely easy-to-use syntax. I bet that if you go through the rest of this document and you have never used markdown before, then you will be able to write markdown text, without looking up the syntax over and over again. Most of that is so simple, that you will be able to remember it straight away.
Markdown is very limited in the things it can display (or markup). This is by design and on purpose. However, Markdown has become the most popular markup language for writing code documentation, and as you might suspect, the more users you have, the more features will be requested. But this goes against the design of markdown.
To complicate things further, Markdown does not have an official specification that describes what a valid Markdown document should look like. Gruber himself was against the idea of standardising Markdown, and so over time, others have taken it upon themselves to define a standard for themselves. As a result, we now have different implementations for Markdown, of which popular implementations are CommonMark, GitHub-flavoured Markdown, Markdown Extra, and MultiMarkdown.
If you want to write Markdown for a specific platform, you should ensure that you are writing it with the correct specification in mind. While all of them support what was proposed by Gruber originally, the main difference in these specifications is the additional features that add. Since this goes against the founding idea of Markdown, you can see why it has never caught support from the inventor himself, and as a result, Markdown itself can be a bit messy at times if you mix up specifications.
To make things clear, we will be using the GitHub-flavoured Markdown extension, so if you are using a different platform to view your Markdown files, you may see differences. While we will look at the most common use cases, there are quite a few more things you can do, but perhaps you won’t need them as often. You can always check out the full Markdown documentation and what is supported in the official GitHub documentation.
In the following sub-section, we will look at common Markdown syntax that we want to use when writing documentation, which we can then use to write our 1-page documentation for our existing libraries. For the examples that follow, the Markdown syntax will be displayed on the left and the generated HTML on the right. It will not look exactly as it does on GitHub, nor, perhaps, as in your Markdown viewer, if you are using one, keep this in mind when inspecting the results.
Headings
The basic building blocks are headings and the paragraphs they contain. Section headings are achieved by using the #
symbol in front of the title, and the number of #
symbols determine the level of the heading. This is shown below.
# Main title
Your document should only contain one main title
## Section heading
You can have as many section headings as you want
### Sub-section heading
You can further sub-divide your sections into sub-headings and use as many as you want
###### This is the smallest heading
You can have at most 6-levels of headings. In most documents, you probably won't need as much fine grained control.
Paragraphs
Paragraphs form the core of our text, and Markdown provides us with basic editing options here. The example below shows different markup options that we have available with the GitHub-flavoured Markdown.
We can highlight text in **bold** or *italics*, and even ~~strike through~~ text. We can also use superscripts such as H<sub>2</sub>O and superscripts such as E=mc<sup>2</sup>.
A new paragraph is created by simply adding an empty line between two paragraphs. You can also add a separating horizontal line if you want using three dashes:
---
You may want to quote some text in your documentation. Use the right arrow symbol on a new line to achieve that. We can use that together with footnotes[^1] to link back to the original source.
> Import quote to highlight.
[^1]: Quote of an important person.
Code blocks and inline code
To show code in our documentation, we can either display it within the written text (inline) or as a separate block which allows us to show several lines of code at the same time. We can optionally specify the programming language that we used, which will then use syntax highlighting as required.
To display code on the same line, you can use `dashes` to highlight code differently from the written text. If you want to show entire code sections, use three dashes on a new line and close the block with another set of three dashes. You can optionally specify the programming language used in the code block to provide syntax highlighting.
Example of code block without syntax highlighting:
```
#include <iostream>
int main() {
std::court << "no syntax highlighting applied" << std::endl;
return 0;
}
```
Same code example, but now we use C++ syntax highlighting:
```cpp
#include <iostream>
int main() {
std::cout << "c++ syntax highlighting applied" << std::endl;
return 0;
}
```
Equations
The GitHub-flavoured Markdown extension does come with full support to write equations using LaTeX’s equation syntax. This is a particularly useful extension if we want to display equations in our documentation.
Equations in Markdown are rendered by placing a valid LaTeX math expression between two dollar (`$`) signs. For example, the divergence-free constraint of an incompressible flow can be stated as $\nabla\cdot\mathrm{\mathbf{u}}=0$. We can also display longer equations in their own block using two leading and trailing dollar signs:
$$\frac{\partial \mathrm{\mathbf{u}}}{\partial t} + (\mathrm{\mathbf{u}}\cdot\nabla)\mathrm{\mathbf{u}} = -\frac{1}{\rho}\nabla p + \nu \nabla^2\mathrm{\mathbf{u}}$$
Lists
We may want to display a list at some point and Markdown has us covered here as well. Lists are rather straightforward to create. Either choose an enumerated or itemised list and start listing your entries in the list as shown below. We can have to-do lists as well, but this is specific to GitHub-flavoured Markdown.
We have two options, either we can add an enumerated or an itemised list. Examples of both are given below:
An itemised list may be given as:
* First list item
* Second list item
* We can have nested items as well
An enumerated list may be given as:
1. First list item
2. Second list item
* We can have nested items as well, but not with numbers.
- We can also use a dash instead of an asterisk
GitHub-flavoured markdown allows for todo list items as well:
- [x] Task 1
- [ ] Task 2
- [ ] Task 3
Tables
Tables can be added as well to Markdown and while they have some limitations in their layout, adding a simple table is not too difficult. We separate columns using the pipe symbol (|
), and we separate the header from the data entry with at least three dashes (---
). Adding a leading, trailing, or both leading and trailing colon (:
) signifies if the text on the respective column should be aligned to the left, right, or centre.
| Column 1 | Column 2 | Column 3 |
| :--- | :---: | ---: |
| entry 1 | entry 2 | entry 3 |
| entry 1 | entry 2 | entry 3 |
| entry 1 | entry 2 | entry 3 |
Links and images
Links and images can be added in a very similar manner. The syntax for both is almost identical, where images require an additional preceding exclamation mark. See the example below.
Links can be added using the providing a description for a website or URL in square brackets, i.e. [], while the link itself is followed in round brackets, i.e. ().
Example: [cfd.unversity](https://cfd.university)
Images can be added in just the same way, but we need to provide a leading exclamation mark, followed by the alternative description of the image in square brackets, and the URL to the image. It can either use absolute paths, i.e. a website's URL + path, or relative paths, where images are given relative to the Markdown file itself. Here is an example:
![Alt description: Will be used by screen-readers](http://cfd.university/wp-content/uploads/resources/documentation/logo.png)
Adding badges to polish your documentation
Badges allow you to showcase what your code can do at a glance. These are commonly added at the top of your readme file and can contain things like the software license, current version, whether the latest unit tests have passed, how many downloads your software got, and much more.
There are dedicated online services for each aspect of your code development, and pretty much all of them provide their own badge that you can use to show how your code is performing. A common example is that of software testing; every time we push a new code change onto our remote repository, where we store our code, it gets built and our unit tests will be automatically run by an external service. THis service will then set the status of your tests, which can be used to dynamically show whether your tests are passing or failing.
The website which brings all of these together is shields.io. A list of all possible badges is provided on their documentation page. For example, if we wanted to show that the current version of our software is 1.2.5, and we are using the permissive MIT license, we can add the following two badges to our readme file:
![Version number](https://img.shields.io/badge/Version-1.2.5-red.svg)
![License type](https://img.shields.io/badge/License-MIT-blue)
In both cases, we are using static badges here. This means that we can type any 3-word combination after the URL part https://img.shields.io/badge/
and it will be transformed into a badge. We use the same syntax we saw above for images and links to display the badges in our Markdown readme file.
This is a very basic usage; I would encourage you to look through the myriad of badges that are available. See which ones interest you and what syntax you need to use to add them to your readme file. Most of them will require some form of third-party involvement and when we will look at them in future series, we will get back to these shields and look at how to add them to our documentation file.
Another good option is to check popular libraries and see which badges they are using. For example, have a look at the C++ JSON parsing library, and you will see a number of badges in action. Make it a habit of checking which badges are used by others and how you can incorporate them into your own projects if you feel they would improve your documentation.
Adding 1-page readme files to our existing libraries
At this point, we have looked at how to write Markdown files. We have also established what structure we want to follow. So let’s put this to the test and start writing some basic 1-page readme files that we can add to our linear algebra solver library and mesh reading library that we based on the CGNS-file format.
Instead of looking at the comparison between Markdown and the generated output, I’ll show the generated output here only. If you want to look at the Markdown files, you can download the updated mesh reading and linear algebra solver library at the beginning of the article, which contains the new readme files.
Linear algebra solver library
The generated HTML output for the linear algebra solver library is shown below.
CGNS-based mesh reading library
The generated HTML output for the mesh reading library is shown below.
Summary
Writing a concise, yet effective 1 page documentation is not difficult and all it takes is a proven structure with the right markup language to guide the reader through your software project.
Markdown is by far the most popular markup language and is used universally by projects, but it does come with some disadvantages, such as no unified standard. This means a Markdown document will only be rendered correctly if the Markdown renderer is following the same standard as the author of the file, and there are many different standards available instead of one provided by the inventor of Markdown.
At a bare minimum, for every software project that you embark on, be it a simple library or a large code base, you should, at a minimum, provide a 1-page readme file visible to everyone in the root directory of your project. This will be rendered automatically by online version control repositories such as GitHub or GitLab.
If you put up the effort to show users what the purpose (and features) are of your code, how to install it and then how to use it, you will see a much better usage of your code by others. And even if you do not plan to make your code available to others (for now), documenting your code will go a long way for your future self, when you try to remember how to compile your code or which functions you need to call in order to achieve the desired outcome.
Tom-Robin Teschner is a senior lecturer in computational fluid dynamics and course director for the MSc in computational fluid dynamics and the MSc in aerospace computational engineering at Cranfield University.