To boldly go where no tech writer has gone before (one can dream, right?)

Importing Code Samples with DITA (or How to Avoid Serious Headaches)

So now we know that good API documentation must include code samples. But if we want our users to base their code on our examples, we must make sure that they are valid and always up-to-date.

In general, the code samples are simply copied from the developers’ source files and pasted into the documentation. If the source code is updated after the documentation is released–for example, if a new mandatory parameter is added to the API–then the documentation must also be updated. Manually checking that all the code samples are still valid may be possible if the documentation is short and simple, but that is rarely the case when documenting APIs. Updating code samples manually can quickly become unmanageable (not to mention be the source of a serious headache, as I unfortunately had the chance to experience recently).

To solve this issue, the code samples in the documentation should be linked to the developers’ source files so that any change to the code will be reflected automatically in the documentation. In DITA, this can be done with the <coderef> element, which is available inside a <codeblock> element.

For example, consider the following source file:
C:\SVN_Checkout\product_x\src\samples\HelloWorld.java


class HelloWorld {
 public static void main(String[] args)
 {
 System.out.println("Hello World!");
 }
}

In the DITA XML file, the reference to this sample would be coded as follows:


<p>The following code shows the infamous "Hello World!" Java class:</p>
<codeblock>
  <coderef href="..\..\SVN_Checkout\product_x\src\samples\HelloWorld.java"/>
</codeblock>

When transforming the DITA file, the output would be similar to the following:

Some guidelines when importing code samples:

  • The imported source files should be short and sweet; importing a Java class that goes over four or five pages in the documentation is not very useful (or readable).
  • The source files should be well commented and include white space for readability.
  • The documentation should be stored with the software, using a control management system, so that the paths to the source files are always valid.

One disadvantage of using <coderef> is that the source code cannot be formatted once it’s imported, so for languages with amazingly long class names (like Java!), it can be downright ugly. Another disadvantage is that <coderef> imports the complete source file, which is not always optimal. Sometimes I only want to include short sections from the source file. Fortunately, this can also be done in DITA, but it’s a bit more complicated.

Including code snippets
To include code snippets in a document, one solution is to create a script that extracts from the source files only the sections that are of interest to the documentation. The script looks for keywords in the comments, indicating the beginning and end of the code samples, along with an ID in a <ph> element uniquely identifying the sample. The output of the script is a DITA file that contains all the code snippets with their IDs.

For example, assuming that the script looks for the DITA_START and DITA_END keywords, a code snippet could be coded in the Java file as follows:


/** DITA_START:<ph id="helloworld_example"> **/
class HelloWorld {
 public static void main(String[] args)
 {
 System.out.println("Hello World!");
 }
}
/** DITA_END:</ph> **/

Running the script generates a valid DITA file (for example, dynamic_code_sample_library.xml with a root id of “dynamic_code_sample_library”) that contains the code snippet:


<codeblock>
 <ph id="helloworld_example">
   class HelloWorld {
     public static void main(String[] args)
     {
     System.out.println("Hello World!");
     }
  }
 </ph>
</codeblock>

The snippets are included in the documentation using conrefs:


 <p>The following code shows the infamous "Hello World!" Java class:</p>
  <codeblock>
    <ph conref="dynamic_code_sample_library.xml#dynamic_code_sample_library/helloworld_example"/>
  </codeblock>

With this solution, I run the script to make sure that the code snippets are up-to-date, I generate my DITA output, and voilà! Well, that’s the plan anyway. I’m currently working on the script, so the headache occurs at the beginning of the project ;-) But I’m having fun and know that it will be worthwhile in the long run!

Additional example

In the example above, I used the <ph> element to set the <conref>. But as Frank Ralf mentioned in a comment below (thanks for your feedback, Frank!), we could also put the <conref> directly on the <codeblock>. In this case, because the <conref> must be set on the same type of element where the id was set, the id must be set on the <codeblock> in the source code. For example, the source code would be as follows:


<codeblock  id="helloworld_example">
   class HelloWorld {
     public static void main(String[] args)
     {
     System.out.println("Hello World!");
     }
  }
</codeblock>

And the code snippet would be included as follows:


 <p>The following code shows the infamous "Hello World!" Java class:</p>
 <codeblock conref="dynamic_code_sample_library.xml#dynamic_code_sample_library/helloworld_example"/>

Using the conref directly in the <codeblock> makes for clearer, more concise code. But if you wanted to include more content in the <codeblock> than the code snippet (for example, if you needed to combine two different snippets in the same <codeblock>), then using the <ph> would be a better option.

For more information on creating good samples

Peter Gruenbaum from SDK Bridge has written some of the most interesting articles I’ve read on how to document APIs: