5. Documentation

The main principle for documentation of source code is that it should appear in the source code files, not in a separate document. If the code and documentation are separated, the process of analysing and understanding the source code becomes harder, since one has to move back and forth between the code and the documentation. It also introduces the risk that the code and the documentation will eventually become out of sync.

For this main principle to be successful, the documentation in the source code files must of course be much more than the occasional comment.

The documentation can be grouped into two parts: usage documentation and implementation documentation. The former is targeted at an audience that needs to understand the functionality of the code and how it to use it from their own code, but have no need of understanding implementation details. The latter contains detailed descriptions of how the functionality of each method is implemented, and is meant for those who maintain, enhance and debug the code.

5.1 Usage documentation

Use javadoc to document the usage of a class, i.e. its functionality and programming interface. This tool is available in most development environments and certainly in the JDK. Javadoc produces a collection of HTML pages that contain the documentation of a class hierarchy. A description of javadoc itself is beyond the scope of this style guide, please refer to the documentation on javadoc.

The following parts of a class should have its usage documented:

  • the class itself, i.e. its purpose and how it is intended to be used
  • public and protected constants, class variables and instance variables
  • all methods (including package private and private methods)

Using javadoc may at first seem to break the main principle we stated above, i.e. that source code and documentation should be kept together. Granted, javadoc generates documentation that is meant to be viewed oustide the source code, but the documentation itself is stored in the source code files and is edited there. This means that the usage documentation is available to anyone looking at the source code. You should therefore try to make the javadoc comments readable in their native format.

Remember that javadoc generates HTML code and that the formatting of the descriptions will not always appear as in the source code file. You can add HTML tags to improve the readability of the documentation, but don't overuse them, since they have a way of making the descriptions less readable in the source code files. Also make sure to escape characters that have a special meaning in HTML, such as <, > and &.

5.1.1 Class descriptions

A class description should contain an explanation of the purpose of the class and how it should be used. Code snippets of common ways of using the class can also be included in the class descriptions.

References to related classes can be included using the javadoc tag "@see". The author(s) of the class should be listed by using the tag "@author". Consider including the mail address(es) of the author(s) as shown in the example below.

/**
 * Utility class for encoding bytes into Base64 and decoding strings
 * encoded in Base64 back to the original bytes.
 *<p>
 * Base64 is an encoding scheme defined by MIME, and it's designed to be robust
 * to all transformations that a message can experience in traversing the
 * Internet. It is not defined in MIME RFCs; they adopted the scheme that was
 * specified in RFC 1421, which refers to the PEM (Privacy Enhanced Mail).
 * See
 * <a href="http://www.ietf.org/rfc/rfc1421.txt">http://www.ietf.org/rfc/rfc1421.txt</a>
 * for a full description of this encoding scheme, below follows a summary.
 *<p>
 * The encoding mechanism is to divide the sequence of 8-bit bytes to encode
 * into groups of three bytes. Each group of three bytes are then encoded as
 * four characters that are printable on virtually any platform. The encoding is
 * done by viewing the 24 bits of the three 8-bit bytes as four 6-bit values,
 * i.e. four values betwen 0 and 63. These values are then used as indices into
 * an array of 64 encoding characters, and the corresponding four characters are
 * used as the encoding of the three bytes. 
 *<p>
 * Special processing is performed if fewer than 24 bits are available in a byte
 * group at the end of a message. When fewer than 24 input bits are available,
 * zero bits are added (on the right) to form an integral number of 6-bit
 * groups.
 *<p>
 * In addition to the 64 encoding characters, the character "=" signifies a
 * special processing function used for padding within the printable encoding
 * procedure. If the sequence of bytes is not a multiple of 3, i.e the number of
 * bits is not a multiple of 24, the output sequence of encoded characters are
 * padded with one or two '=' to make the number of encoded bits a multiple of 24
 * and thus the number of 6-bit groups a multiple of 4.
 *<p>
 * The encoding function's output is delimited into text lines (using local
 * operating system conventions), with each line except the last containing
 * exactly 64 printable characters and the final line containing 64 or fewer
 * printable characters. (This line length is easily printable and is guaranteed
 * to satisfy SMTP's transmitted line length limit of 1000 characters.)
 *<p>
 * The Base64 characters are shown below:
 *<pre>
 * Value    Encoding    Value   Encoding    Value   Encoding    Value   Encoding
 * 0        A           17      R           34      i           51      z
 * 1        B           18      S           35      j           52      0
 * 2        C           19      T           36      k           53      1
 * 3        D           20      U           37      l           54      2
 * 4        E           21      V           38      m           55      3
 * 5        F           22      W           39      n           56      4
 * 6        G           23      X           40      o           57      5
 * 7        H           24      Y           41      p           58      6
 * 8        I           25      Z           42      q           59      7
 * 9        J           26      a           43      r           60      8
 * 10       K           27      b           44      s           61      9
 * 11       L           28      c           45      t           62      +
 * 12       M           29      d           46      u           63      /
 * 13       N           30      e           47      v           (pad)    =
 * 14       O           31      f           48      w
 * 15       P           32      g           49      x
 * 16       Q           33      h           50      y
 *
 * An example:
 *  The bytes
 *      0x40 0xfa 0x55 0x93
 *  are the 24 bits
 *      01000000 11111010 01010101 10010011
 *  which formed as 6-bit values are (with zero padding)
 *      010000 001111 101001 010101 100100 11(0000)
 *  or as integers
 *      16 15 41 21 36 48
 *  which translates to the Base64 characters
 *      Q P p V k w
 *  and gets two padding characters to form a multiple of 4
 *      QPpVkw==
 *</pre>
 * The data to encode should be on the form of a byte array to allow just about
 * any type of data to be encoded. The encoded form is stored in Strings. To
 * encode a sequence of bytes, simply call the <code>encode</code> method:
 *<pre>
 *   byte[] aBinaryBytes;
 *   ...
 *   String aEncodedString = Base64.encode(aBinaryBytes);
 *</pre>
 * and to decode the encoded string the <code>decode</code> method is called:
 *<pre>
 *   byte[] aOriginalBytes = Base64.decode(aEncodedString);
 *</pre>
 *
 * @author <a href="mailto:peter@myire.org">Peter Franzen</a>
 */
public class Base64
{
...

In the above example the purpose of the class is the first thing that appears. Then follows a description of the main functionality of the class, in this case a summary of the Base64 encoding scheme. Note that a reference to the official source of this summary is given as well. Furthermore, nothing concerning the implementation is discussed in the class description; that belongs to the implementation documentation.

The example above also contains some interesting javadoc techniques. Each paragraph is separated with a <p> tag to create the same paragraphs in the HTML generated by javadoc. We use the <pre> tag to format the table of the Base64 characters. We could of course have used a <table> instead, but that would have made the documentation harder to read in the source code file with all <tr> and <td> tags cluttering things up. The mail address of the author is given as a convenient mailto: link.

Not all classes require as much usage documentation as the one above. Below follows another example, where you also can see the use of the javadoc tag "@see" to refer to related classes.

 * A ConnectionHandler handles all interaction with a client that has
 * connected to a Listener. A Listener creates a new ConnectionHandler
 * implementation through a ConnectionHandlerFactory for each connection
 * that is accepted, and lets the ConnectionHandler do all the communication
 * with the connected client, including closing down the connection once
 * the interaction is finished.
 * <p≫
 * The ConnectionHandler runs in a separate thread provided by the Listener.
 *
 * @see Listener
 * @see ConnectionHandlerFactory
 *
 * @author <a href="mailto:peter@myire.org">Peter Franzen</a>
 */
public interface ConnectionHandler extends Runnable
{
...

For more good examples of class usage documentation, have a look at the java.util Collection classes.

5.1.2 Variable descriptions

The public and protected variables of a class should have descriptions in javadoc format. These descriptions document what the variable is used for, and are normally quite short. Although this style guide doesn't discuss principles for object oriented design, we note that public and protected instance variables are considered evil by many. Constants, i.e. final class variables, on the other hand often have public or protected access and are documented with javadoc comments.

An example:

/**
 * Constant to pass to setQueryType() for boolean queries.
 */	
static public final int kQueryTypeBoolean = 1;

Variables with package private or private access are implementation details that are not given descriptions. They should instead be commented to explain their role in the implementation, see below.

5.1.3 Method descriptions

A method description explains what the method does, which parameters it expects and any requirements on their format or legal values. If the method returns a value, that should also be described together with any special cases where certain values may be returned.

Any exceptions that may be thrown should be explained and under what circumstances they will be thrown. Document checked exceptions and also unchecked exceptions that are explicitly thrown. For example, if an IllegalArgumentException is thrown if the method is passed a bad parameter value, that should be documented.

If there are any special considerations for using the method, e.g. preconditions or side effects, those should also be documented in the method description.

Always document the unit for numeric parameters, e.g. the unit for length or time. If a parameter or the return value is an index to an array, list or collection of some kind, it should be documented which base the index uses (normally 0 or 1).

Below follows an example of a method description:

/**
 * Get the first n characters from the document, beginning with the headline
 * and then continuing with subheadline, intro and body until the specified
 * number of characters have been retrieved.
 *<p>
 * Note that the document must have been loaded from its storage with a call to
 * <code>{@link #load}</code> before this method can be called.
 *
 * @param pNumCharacters   The number of characters to get.
 *
 * @return  A String containing the first pNumCharacters characters of
 *          the document. Should the entire document contain less than
 *          this number of characters, only as many characters as are
 *          available are returned.
 *
 * @throws  StorageException          if the document wasn't loaded.
 * @throws  IllegalArgumentException  if pNumCharacters is negative.
 */
public String getFirstCharacters(int pNumCharacters) throws StorageException
{
...

The reason that all methods, not only public and protected, should be documented with javadoc comments is that the information provided in the method description is needed for the documentation of the implementation as well. There is no reason to use another format for the implementation documentation just because it concerns the internal structure of the class. In javadoc it is possible to specify that only public and protected methods should be included when generating the HTML documentation, which makes it possible to generate documentation both for the user and the implementer of the class.

5.2 Implementation documentation

The mechanism used for implementation documentation is source code comments. All important implementation details should be commented; what variables are used for, the purpose of a group of statements in a method body, how the algorithm used is implemented, etc.

A comment should be put on its own line or lines and be placed immediately above the first line of code it explains. Comments are indented at the same level as the block of code they belong to. Avoid putting a comment at the end of the line of code it belongs to, such comments clutter the code and are easy to overlook.

Use // for comments. Do not use pairs of /* and */, they have been proven to be a notorious source of problems where code can accidentally be commented out. Do not put comments into "boxes" of asterisks, it only draws the attention from the comment and the code, which is exactly what it shouldn't do.

When deciding whether to comment something or not, ask yourself: will the meaning of this variable or statement be obvious to me, the implementer, three months from now? If the answer is no, document with a comment.

Commenting extensively will also give the programmer an opportunity to think the code through when it is written. If the programmer explains his or hers thoughts about the algorithms and what the code does when it is written, any incomplete chains of thought or ambiguities in the semantics can often be discovered. If a particular block code of code is hard to describe, it could be a sign of an unclear part of the algorithm.

To comment extensively does not mean to comment every single line of code, but every non-trivial "group" of statements that belong together in some way should be commented. The definition of non-trivial is of course subjective. Code that appears trivial to the person who writes it may not be trivial to a future reader, and it can be dangerous to assume that a piece of code can be understood by just about anyone. Also, remember that what may be obvious to you when you write the code may not be as obvious in a few months.

Below follows an example of how a piece of code can be commented:

...
    // Class variable holding the files that have been written to at least once.
    static private Set cWrittenFiles = new HashSet();
...
    public void writeToFile(String pFileName, String pData)
    {
        // Open the file for writing, possibly creating it.
        File aFile = new RandomAccessFile(new File(fDirectory, pFileName), "rw");
        FileChannel aFileChannel = aFile.getChannel();

        // Check if this file has been written to earlier. Each file that has
        // been written to at least once will be in the cWrittenFiles set.
        boolean aFirstTime;
        synchronized (cWrittenFiles)
        {
            // Try to add the file to the set of written files. If that
            // succeeds, we know the file hasn't been written to earlier.
            aFirstTime = cWrittenFiles.add(aFileName);
        }

        if (aFirstTime && !fAppend)
        {
            // This is the first time we're writing to the file and we're
            // not in append mode. Remove any old content from the file and
            // write the header to it.
            aFileChannel.truncate(0);
            aFileChannel.position(0);
            writeToFile(aFileChannel, fFileHeader);
        }
...

There are other code style guides that take a contrary position when it comes to comments and argue that if the code needs extensive commenting it is a sign of that the code is badly written and should be redesigned.

We believe that even the most crystal clear code (if there is such a beast) will benefit from comments. With a few thoroughly picked comments, the reader's thoughts can directly be focused on the important parts of the code and guided through the algorithm. Even if an average programmer could understand a piece of code after a minute or two, isn't it better if he or she understands it already after a few seconds with a little help from some comments? The author of this style guide has wasted too much time on trying to understand poorly documented code, code that wasn't all that complex but lacked both consistency, comments and style.

It can also be noted that if you have a hard time finding a good comment for a block of code, perhaps you should think about what it really does and if it has a natural part in the algorithm.

The more ingenious and complex the code is, the more detailed should the comments be. You should also concentrate on the semantics of the code, i.e. explain why the code does what it does. There is little point in using words to merely repeat what the code already states. With this is mind, trivial comments can be converted to non-trivial comments that actually helps the reader understand the code better.

In the following example, the comments only repeats the code and doesn't add anything of value:

// Set the result to null.
aResult = null;

However, if the comment instead explains why we do the assignment, it does provide some information that may not be easily extracted from simply reading the code:

// If something goes wrong in the calculations,
// null will be returned.
aResult = null;

Finally, it takes some time to write good comments, but the time is usually well spent and will be rewarded when the code is maintained, debugged or enhanced. Do not postpone the writing of comments until later, you will probably never get around to it if you don't integrate it with the coding itself.


Previous Contents Next