It is our firm belief that software can only be successful if it is properly documented. Too many academic software projects die prematurely once their creators leave the university or the workgroup in which the software was developed, since with their creators also knowledge of internal structures, interfaces, and the valuable bag of tricks leaves, a gap that can not be closed by reading sources, trial-and-error, and guessing.
The deal.II project has therefore from its infancy adopted a policy that every aspect of the interface needs to be well-documented before its inclusion into the source tree. Since we have found that it is impossible to keep documentation up-to-date if it is not written directly into the program code, we write the documentation directly at the place of declaration of a function or class and use automatic tools to extract this information from the files and process it into HTML for our web-pages, or LaTeX for printing.
In addition to the API documentation, we maintain a series of well-documented example programs, which also follow a certain ``literate programming'' style in that the explanations of what is happening are integrated into the program source by means of comments, and are extracted by small scripts.
This document first explains the basics of documenting the API and then of writing example programs.
In order to extract documentation from the header files of the project, we use doxygen. It requires that documentation is written in a form which closely follows the JavaDoc standard.
Basically, every declaration, whether class or member function/variable declaration, global function or namespace, may be preceded by a comment of the following form:
/** * This is an example documentation. */ class TestClass { public: /** * Constructor */ TestClass (); /** * Example function */ virtual void test () const = 0; /** * Member variable */ const unsigned int abc; };
doxygen will then generate a page for the class
TestClass
and document each of the member functions
and variables.
In order to allow better structured output for long comments, doxygen supports a great number of tags for enumerations, sectioning, markup, and other fields. We encourage you to take a look at the doxygen webpage to get an overview. However, here is a brief summary of the most often used features:
/** * <ul> * <li> foo * <li> bar * </ul> */you can get itemized lists both in the online and printed documentation:
In other words, one can use standard HTML tags for this
task. Likewise, you can get numbered lists by using the
respective HTML tags <ol>
.
If you write comments like this,
/** * @verbatim * void foobar () * { * i = 0; * } * @endverbatim */you will get the lines between the verbatim environment with the same formatting and in typewriter font:
void foobar () { i = 0; }This is useful if you want to include small sample code snippets into your documentation. In particular, it is important that the formatting is preserved, which is not the case for all other text.
In order to use typewriter font for instance for function
arguments or variables, use the <code>
HTML
tag. For a single word, you can also use the form @p
one_word_without_spaces
. The <tt>
is obsolete in HTML5
If you refer to member variables and member functions doxygen has better options than this: use function_name() to reference member functions and #variable_name for member variables to create links automatically. Refer to the documentation of doxygen to get even more options for global variables.
To generate output in italics, use the @em
one_word_without_spaces
tag or the <em>
HTML tag. To generate boldface, use <b>
For simple and short formulæ use the <i> HTML tag. Note that you can use <sub> and <sup> to get subscripts an superscripts, respectively. Only for longer formulæ use $formula$ to generate a LaTeX formula which will then be included as a graphical image.
Sections in class and function documentations can be generated using the <hN> HTML headline tags. Headlines inside class documentation should start at level 3 (<h3>) to stay consistent with the structure of the doxygen output.
Sections cannot be referenced, unless you add a <A NAME="..."> name anchor to them. If you really have to do this, please make sure the name does not interfere with doxygen generated anchors.
doxygen sometimes has problems with inlined functions of template classes. For these cases (and other cases of parts of the code to be excluded from documentation), we define a preprocessor symbol DOXYGEN when running doxygen. Therefore, the following template can be used to avoid documentation:
/* documented code here */ #ifndef DOXYGEN /* code here is compiled, but ignored by doxygen */ #endif // DOXYGEN
Tutorial programs consist of an introduction, a well documented
code, and a section that shows the output and numerical results
of running the program. These three parts are written in separate
files: for the step-xx
program, for example, they
would be in the
files examples/doc/step-xx/doc/intro.dox
,
examples/doc/step-xx/step-xx.cc
and
examples/doc/step-xx/doc/results.dox
. There are a
number of scripts that then process and concatenate these three
different files and send them through doxygen for generation of
HTML output. In general, if you want to see how certain markup
features can be used, it is worthwhile looking at the existing
tutorial program pages and the files they are generated from.
The introduction, as well as the results section, will be processed as if they were doxygen comments. In other words, all the usual doxygen markup will work in these sections, including latex formulas, though the format for the formula environment is a bit awkward. Since it takes much longer to run doxygen for all of deal.II than to run latex, most of the lengthier introductions are just written in latex (with a minimal amount of markup) and later converted into doxygen format. One thing to be aware of is that you can reference formulas in doxygen, so you have to work around that using text rather than formula numbers.
More important is what goes into the introduction. Typically, this would first be a statement of the problem that we want to solve. Take a look, for example, at the step-22 or step-31 tutorial programs. Then come a few sections in which we would discuss in mathematical terms the algorithms that we want to use; this could, for example, include the time stepping, discretization, or solver approaches. step-22 and step-31 are again good, if lengthy, examples for this.
On the other hand, if a program is an extension of a previous program, these things need not be repeated: you would just reference the previous program. For example, step-16 does not talk about adaptive meshes any more — it extends step-6 and simply refers there for details. Likewise, step-32 simply refers to step-31 for the problem statement and basic algorithm and simply focuses on those parts that are new compared to step-31.
The purpose of the introduction is to explain what the program is doing. It should set the mindset so that when you read through the code you already know why we are doing something. You may not yet know how this done, but this is what the documentation within the code is doing. At least you don't have to wonder any more why we are building up this complicated preconditioner — we've already discussed this in the introduction.
If it helps the understanding, the introduction can refer to particular pieces of code (but doesn't have to). For example, the introduction to step-20 has pretty lengthy code snippets that explain how to implement a general interface of operators that may or may not be matrices. This would be awkward to do within the code since in the code the view is somewhat smaller (you have to have complete parameter lists, follow the syntax of the programming language, etc, all of which obscures the things one wants to discuss when giving a broad overview related to particular C++ constructs). On the other hand, showing code snippets in the introduction risks duplicating code in two places, which will eventually get out of synch. Consequently, this instrument should only be used sparingly.
At present, the tools that extract information from the actual example
programs code are rather dumb. They are, to be precise, three Perl
scripts located in the directory of the
deal.II/doc/doxygen/tutorial
tree, where
the .cc
files of the tutorial programs are converted
into doxygen input files. In essence, what these scripts do is to
create doxygen input that contains the comments of the program as
text, and the actual code of the programs as code snippets. You
can see this when you look at the pages for each of the tutorials
where the code is indented relative to the text.
The whole thing being interpreted by doxygen means that you can put anything doxygen understands into comments. This includes, for example references to classes or members in the library (in fact, you just need to write their name out and doxygen will automatically link them), formulas, lists, etc. It all will come out as if you had written comments for doxygen in the first place.
The bigger question is how to write the comments that explain what's going on in individual code blocks. Many years back we wrote them so that every line or every two lines had their own comment. You can still see this in some of the older tutorial programs, though many of them have in the meantime been converted to a newer style: it turns out that if you have comments so frequently, it becomes hard to follow the flow of an algorithm. In essence, you know exactly what each line does, but you can't get an overview of what the function as a whole does. But that's exactly the point of the tutorial programs, of course!
So the way we now believe tutorial programs should be written is
to have comments for each logical block. For example,
the solve()
function in many of the programs is
relatively straightforward and has at most a dozen lines of
code. So put a comment in front of the function that explains
all the things that are going on in the function, and then show
the function without comments in it — this way, a reader
will read through the half or full page of documentation
understanding the big picture, and can then see the whole
function all at once on a single screen without having to scroll
up and down. In the old way, the code would be spread out over a
couple pages, with comments between almost any two lines, making
it hard to see how it all fits together.
It is somewhat subjective how much code you should leave in each block that you document separately. It might be a single line if something really important and difficult happens there, but most of the time it's probably more along the lines of 6 to 12 lines — a small enough part of the code so that it's easy enough to grasp by looking at it all at once, but large enough that it contributes a significant part or all of an algorithm.
The results section should show (some of) the output of a program, such as the console output and/or a visualization of graphical output. It should also contain a brief discussion of this output. It is intended to demonstrate what the program does, so that a reader can see what happens if the program were executed without actually running it. It helps to show a few nice graphics there.
This section needs not be overly comprehensive. If the program is the implementation of a method that's discussed in an accompanying paper, it's entirely ok to say "for further numerical results, see ...".
Like the introduction, the results section file is copied verbatim into input for doxygen, so all doxygen markup is possible there.