Automate the process of documenting your code

Introduction

Every developer is relying on a development platform, the two major ones being .NET and J2EE. The development platform provides the basic plumbing like file IO, threading, XML processing and much more so we developer don't have to worry about the low level plumbing itself. You use the classes and methods provided by the development platform. Both platforms have a rather large class library and you rely on a comprehensive documentation to understand it and to be able to use it. The same holds true for your own projects and products. Every product needs to constantly innovate and be expanded to survive in the market place. This means your own class library is growing and you get quickly to the point where your team also relies on good documentation to be able to understand, use and improve it. This holds very true when you bring in new team members.

We all understand the need to comprehensively document our class libraries and to keep it up to date with the code base. And still, documentation is an ongoing pain for all of us. We want better documentation about the development platform we use and your team requires better documentation about each others code. Many people experienced the pain trying to keep external documentation up to date with an ever changing code base and also finding the right documentation when looking at some piece of code. The Visual Studio .NET IDE takes a first big step in easing that pain. It allows to document your code in a way that the compiler can create an XML document describing your classes, methods, properties, etc. This article explains how to use this feature and then create a basic help file out of it.

How to create XML documentation tags in VS.NET

How this works is that you document your code using XML tags and when you compile your project the compiler looks for those tags and uses them to create a XML file describing your classes, methods, properties, etc. This is available in C# since Visual Studio .NET 2003 and in VB.NET since Visual Studio .NET 2005. In an empty line above your class, method or property declaration type three slashes in C# or three apostrophes in VB.NET. The IDE now creates a XML structure in front of your class, method or property which reflects exactly its signature (see example below). You then type in the documentation of the class, method or property.

/// /// the form which allows to choose the XML and XSLT document and
/// then perform the transformation to create the help page
/// partial class CodeDocumenter : Form {
/// /// user can choose the XML source file to use
/// /// event sender
/// event arguments
private void SourceFilePicker_Click(object sender, EventArgs e)
{ }
/// }

Methods have also a XML property tag for each argument. This allows you to describe each argument in detail. It also creates a XML tag for the return value itself so you can describe the expected return value. Any change to the method signature requires also keeping the XML tags in sync. It is also important to keep the order of the XML tags describing each argument in sync with the order of your arguments in the method signature. So if you add a new argument at the beginning of your method signature then you also need to add the XML tag describing this argument before all the other ones. First add a new line at the appropriate position, which already adds the three slashes or apostrophes for you. Then type the left angle bracket (<) which opens up an intellisense menu and shows you already the "param name = 'argument name'". Select it and add the right angle bracket (>) and the IDE creates the complete XML tag for you and you add the description.

The intellisense menu shows also additional XML tags available. You can for example add a permission tag describing the permissions callers need to have to be able to call and execute the method successfully. You can use the example tag to show an example how to use the method, etc. This makes it very easy to document your classes, methods and properties comprehensively.

How to create the XML documentation file

You need to tell the compiler to create a XML documentation file using all the XML documentation tags you added in your code. You can do this through your project properties. The steps are different for VB.NET and C#. In C# select the "Build" tab and under the "Output" group select the option "XML Documentation File". Beside the option is a textbox with the path and name of the XML file. This gets set by default to the same path where your binary gets created plus the project name as the file name, for example "bin\Debug\CodeDocumenter.XML". In VB.NET select the "Compile tab" and at bottom check the option "Generate XML documentation file". This creates at the same location where your binary is created, which is by default the BIN folder under your project folder, an XML documentation file (same name as your project file). Next compile your code and look for the XML documentation file. Here is a sample XML documentation file for the code snippet shown above.

CodeDocumenter the form which allows to choose the XML and XSLT document and then perform the transformation to create the help page user can choose the XML source file to use event sender event arguments

Any missing XML tag or mismatch between the XML tags and class, method or property signature will be show as a warning. It is important to resolve this to assure that documentation and code stay in sync. As soon as your team gets negligent on that you will see the documentation gets less and less valuable till you reach the point that it is out-of-sync and no longer used. This is a discipline you need to instill in your development team.

How the Visual Studio .NET IDE uses the XML documentation file

The Visual Studio .NET IDE is also taking advantage of the XML documentation file. The intellisense feature of the IDE will look for the XML documentation file at the same location as the referenced binary file. If present it will use the XML documentation file when showing the intellisense and show right in your IDE your descriptions of the classes, methods, method arguments, return values, properties, etc. This can be extremely useful for other teams and team members. You get helpful information shown right when you have a need to use the class, method or property. So when distributing your binaries to other teams or team members make sure to pass along the XML documentation file. They will appreciate that little bit of convenience.

How to create a help file for your code

You can use the same XML documentation file to create help files describing your code. This is useful if you are selling components within the developer community. But it is also useful to create help files describing your code each time you create a release. It can be used by your support teams, integration partners or by your sustained maintenance team (the team which does the bug fixing after a release). The biggest advantage of this approach is that code and documentation are kept in sync. Even if you have separate technical writers creating your code documentation, they can still use the help files generated out of the XML documentation files as a starting point. This cuts down the time they need to gather information.

The simplest way to create a help file is to apply a XSL transformation to the XML documentation file which creates a HTML file. The enclosed tool allows you to select a XML documentation file, a XSL stylesheet, perform the transformation and save it as a HTML help file. Here is how the XSL stylesheet provided by the tool works. First the template for the matching root node gets called. This one selects all assembly nodes and calls its associated template.

The assembly template includes the CSS stylesheet provided by the tool. The tool creates a copy of that CSS stylesheet at the same location it saves the generated HTML help file. All HTML code generated references styles defined in the CSS stylesheet, so it becomes easy to change the formatting of the generated help file later on. Next it creates a HTML table to describe the assembly. It then displays the assembly name in the first row of this table. Next it selects all member nodes which have a name attribute containing the "T:" characters. The XML documentation file adds all types as member nodes with a name attribute always starting with "T:". So effectively we select all types and call its appropriate template.

Assembly

The member template first creates three variables. The first variable stores the name of the member. This is done by cutting off the "T:" prefix and also removing the assembly name. Looking at the XML documentation file you see that each type is added using the syntax "T:assembly-name:type-name". The second member variable stores the type prefix and the assembly name. The last variable stores a filter which we use when selecting all members of this type, which is effectively "assembly-name.member-name". Then we add for each processed type a row to the assembly table created in the assembly template. We add an empty column at the beginning and at the end for positioning purpose. The middle column contains the information about the type itself. It creates another HTML table to display all the type information. In the first row it shows the type name and if present its description. Then it calls the ProcessTypeMembers template and passes along a collection of nodes, which are all members for the processed type as well as the name of the processed type.

Type -

The template ProcessTypeMembers does the work of adding now to the type table all members (please download the code attached to this article). It loops through the passed along member nodes. For each member node it first gets the member name by cutting off the member identifier (can be "M:" for method, "F:" for field and "P:" for property, etc.) and the assembly and type name. The format used in the XML documentation file is "member-identifier:assembly-name.type-name.member-name". It then performs the following logic:

  • Constructors - If it finds the string "#ctor" in the name attribute of the member node it knows it is a constructor. It adds a new row to the type table, the first column showing that this is a constructor and in the second column showing the description in the summary tag.

  • Property - If it finds the member identifier "P:" in the name attribute it knows that the member is a property. It adds a new row to the type table, the first column showing that this is a property and in the second column showing the name of the property with its description in the summary tag.

  • Field - If it finds the member identifier "F:" in the name attribute it knows that the member is a field. It adds a new row to the type table, the first column showing that this is a field and in the second column showing the name of the field with its description in the summary tag.

  • Type - If it finds the identifier "T:" it knows that the node represents the type itself and ignores it. The type node itself gets also selected and passed along to the ProcessTypeMembers template but no additional processing is needed.

  • Method - If it finds the member identifier "M:" in the name attribute it knows that the member is a method. It adds a new row to the type table, the first column showing that this is a method and in the second column showing the name of the method with its description in the summary tag. It then adds another table for all method arguments. It selects all param nodes for the processed member node and outputs the argument name and its description. It then also checks if there is a return node, in case the method has a return value. In that case it adds another row to the argument table with the name return value and the description of the return value.

  • Unknown - All other nodes are considered as unknown. It adds a new row to the type table, the first column showing that this is an unknown member and in the second column showing the name of the member with its description in the summary tag.
Again, please refer to the attached code for the complete XSL stylesheet. If you want your help file to be structured use the attached XSL stylesheet as template and modify as needed. You can also create multiple XSL stylesheets and select the one to use when performing the transformation. The attachment also includes the CSS stylesheet referenced by the generated help file (called HelpStyleSheet.css). Modify it to change the font-family, font-size, font-color and more.

Summary

The value of the documentation capabilities build into the Visual Studio .NET IDE are often overlooked. They are easy to use and can improve the productivity of your development team quite noticeably. As this article shows there are ways how to further maximize the value of these documentation capabilities. It can reduce quite a bit the costs associated with documenting your code. This holds very much true when you need to provide such documentation to members out-side of the team, whether these are internal teams involved in supporting the product post release or external customers. There are professional tools available on the market and there are freeware tools available which are build using the XML documentation file.

The following article shows how you can utilize the VS.NET 2003 Power Toys to generate a help file out of the XML documentation file and incorporate that help file into the VS.NET IDE so it is available right within your IDE. The attached example shows how easy it is to build such infrastructure.

Next Recommended Readings