Chapter 15
Documentation of Object-oriented Programs

Kurt Nørmark ©
Department of Computer Science, Aalborg University, Denmark


Abstract
Previous lecture Next lecture
Index References Contents
This lecture is about documentation of object-oriented programs.


Documentation of Object-oriented Programs

Program Documentation
Slide Annotated slide Contents Index
References Textbook 

Documentation may serve several different purposes

  • User and usage documentation

    • Describes how the program is used

    • Oriented towards the end-user of the program

  • Documentation of types - for external purposes

    • Describes external properties of each type

    • Oriented towards programmers of client types

  • Documentation of programs or types - for internal purposes

    • Describes internal properties of a program or type

    • Oriented towards current and future developers of the current program or type

Program Documentation - When and Where?
Slide Annotated slide Contents Index
References Textbook 

  • Temporal: When is the documentation written?

    • The documentation is written before the program

    • The documentation is written together with the program

    • The documentation is written after the program is completed

  • Spatial: How is the documentation organized relative to the program structure

    • The documentation is written in documents separate from the program

    • The documentation and program are written and organized together

      • The documentation resides inside the program

      • The program resides inside the documentation

Documentation of C# Programs
Slide Annotated slide Contents Index
References Textbook 

Documentation of C# programs can be written in documentation comments

Reference

  • Documentation in C#

    • Selected types and members of types are documented

    • Documentation is written in distinguished comments

    • The documentation is intended to be written together with the program

A documentation example in C#
Slide Annotated slide Contents Index
References Textbook 

Documentation of class BankAccount

Program: The class BankAccount - with documentation comments.
using System;

/// <summary> 
///   A simple bank account created as an everyday example
///   for the OOP course. Used in particular for demonstrating inheritance.
/// </summary>
public class BankAccount {

   private double interestRate;
   private string owner;
   private double balance;

   /// <summary>
   ///  Construct a bank account from owner. 
   ///  The interestRate is given the default value 0.0.
   ///  The balance is given the default value 0.0.
   /// </summary>
   /// <param name = "owner"> The owners name. A string.</param>
   public BankAccount(string owner): 
     this(owner, 0.0, 0.0) {
   }

   /// <summary>
   ///  Construct a bank account from owner, balance, and interestRate.
   ///  The interestRate is given the default value 0.0.
   /// </summary>
   /// <param name = "owner"> The owners name </param>
   /// <param name = "balance"> The initial amount of this account</param>
   public BankAccount(string owner, double balance): 
     this(owner, balance, 0.0) {
   }

   /// <summary>
   ///  Construct a bank account from owner, balance, and interestRate. 
   /// </summary>
   /// <param name = "owner"> The owners name </param>
   /// <param name = "balance"> The initial amount of this account</param>
   /// <param name = "interestRate"> 
   ///    The interest rate. 
   ///    Annual interet is calculated as balance * interestRate 
   /// </param>
   public BankAccount(string owner, double balance, double interestRate) {
      this.interestRate = interestRate;
      this.owner = owner; 
      this.balance = balance;
   }

   /// <summary>
   ///  Returns the current amount of the bank account 
   ///  without affecting the account.
   /// </summary>
   /// <value> Accesses the amount of money in the account</value>
   public double Balance {
     get{
      return balance;
     }
   }

   /// <summary>
   ///   Return the interest rate of the account
   /// </summary>
   /// <value> Accesses the interest rate of the account </value>
   public double InterestRate {
     get{
      return interestRate;
     }
   }

   /// <summary>
   ///   Withdraw an amount of money from the account.
   ///   This decreases the balance of the account.
   /// </summary>
   /// <param name = "amount"> 
   ///  The amount of money to withdraw from the account.
   ///  Precondition: Must be non-negative.
   /// </param>   
   public void Withdraw (double amount) {
      balance -= amount;
   }

   /// <summary>
   ///   Withdraw an amount of money from the account.
   ///   This increases the balance of the account.
   /// </summary>
   /// <param name = "amount"> 
   ///  The amount of money to deposit to the account.
   ///  Precondition: Must be non-negative.
   /// </param>   
   public void Deposit (double amount) {
      balance += amount;
   }

   /// <summary>
   ///   Add the annual interest to the account.
   ///   This may increase the current balance of the account.
   /// </summary>
   public void AddInterests() {
      balance = balance + balance * interestRate;
   }    

   /// <summary>
   ///   Return a text string that represents this account
   ///   for output purposes
   /// </summary>
   public override string ToString() {
      return owner + "'s account holds " +
            + balance + " kroner";
   }
} 

Program: The generated XML documentation - augmented manually with xml-stylesheet clause.
<?xml version="1.0"?>
<?xml-stylesheet href="doc.xsl" type="text/xsl"?>
<doc>
    <assembly>
        <name>bank-account</name>
    </assembly>
    <members>
        <member name="T:BankAccount">
            <summary> 
              A simple bank account created as an everyday example
              for the OOP course. Used in particular for demonstrating inheritance.
            </summary>
        </member>
        <member name="M:BankAccount.#ctor(System.String)">
            <summary>
             Construct a bank account from owner. 
             The interestRate is given the default value 0.0.
             The balance is given the default value 0.0.
            </summary>
            <param name = "owner"> The owners name. A string.</param>
        </member>
        <member name="M:BankAccount.#ctor(System.String,System.Double)">
            <summary>
             Construct a bank account from owner, balance, and interestRate.
             The interestRate is given the default value 0.0.
            </summary>
            <param name = "owner"> The owners name </param>
            <param name = "balance"> The initial amount of this account</param>
        </member>
        <member name="M:BankAccount.#ctor(System.String,System.Double,System.Double)">
            <summary>
             Construct a bank account from owner, balance, and interestRate. 
            </summary>
            <param name = "owner"> The owners name </param>
            <param name = "balance"> The initial amount of this account</param>
            <param name = "interestRate"> 
               The interest rate. 
               Annual interet is calculated as balance * interestRate 
            </param>
        </member>
        <member name="M:BankAccount.Withdraw(System.Double)">
            <summary>
              Withdraw an amount of money from the account.
              This decreases the balance of the account.
            </summary>
            <param name = "amount"> 
             The amount of money to withdraw from the account.
             Precondition: Must be non-negative.
            </param>   
        </member>
        <member name="M:BankAccount.Deposit(System.Double)">
            <summary>
              Withdraw an amount of money from the account.
              This increases the balance of the account.
            </summary>
            <param name = "amount"> 
             The amount of money to deposit to the account.
             Precondition: Must be non-negative.
            </param>   
        </member>
        <member name="M:BankAccount.AddInterests">
            <summary>
              Add the annual interest to the account.
              This may increase the current balance of the account.
            </summary>
        </member>
        <member name="M:BankAccount.ToString">
            <summary>
              Return a text string that represents this account
              for output purposes
            </summary>
        </member>
        <member name="P:BankAccount.Balance">
            <summary>
             Returns the current amount of the bank account 
             without affecting the account.
            </summary>
             <value> Accesses the amount of money in the account</value>
        </member>
        <member name="P:BankAccount.InterestRate">
            <summary>
              Return the interest rate of the account
            </summary>
             <value> Accesses the interest rate of the account </value>
        </member>
    </members>
</doc>

Reference

Figure. A screenshot of the HTML rendering of the XML documentation file

The XML Documentation Language for C#
Slide Annotated slide Contents Index
References Textbook 

The elements of the C# documentation language

References

  • <summary> summary text </summary>

    • Describes types as well as type members

  • <remarks>description</remarks>

    • Additional information about a type, supplementing the information specified in a summary.

  • <param name="p">parameter description</param>

    • Description of the parameter p

  • <value>property-description</value>

    • Documents a property (the value which is represented by the property)

  • <typeparam name="name">description</typeparam>

    • Documents a type parameter of a generic type or method

  • <returns>description</returns>

    • Describes the return value of a method

  • <example>description</example>

    • An example of how to use a method. May contain code elements

  • <c>text</c>

    • Text indicated/emphasized as code

  • <code>text</code>

    • Text indicated/emphasized - multiple lines of code

  • <exception cref="e">description</exception>

    • Documents the exception e

  • <include file='filename' path='tagpath[@name="id"]' />

    • Include part of another documentation file in the current documentation.

    • Relies on XPath expressions.

  • <list> ... </list>

    • A bullet list facility. Can be used in summaries.

    • Relies on additional nested elements such as <listheader> ... </listheader> and <item> ... </item>

  • <para>content</para>

    • A paragraph. Used within summaries and remarks for markup of a paragraph.

  • <paramref name="name"/>

    • Used for references to parameters within summary or remarks

  • <see cref="member"/>

    • A reference to a member

  • <seealso cref="member"/>

    • Contributes to a separate "See also" clause of the documentation

  • <typeparamref name="name"/>

    • Format the name of a type parameter in distinct way.

References

In addition to the XML elements mentioned above you can invent and use your own "tags"

Tool support: The C# Compiler
Slide Annotated slide Contents Index
References Textbook 

The /doc: option of the C# compiler and the generated XML file.

  • The C# Compiler

    • Via use of the /doc: compiler option an XML file can be produced

    • The XML file is not useful for direct presentation

    • The XML format does not contain full type information

  • Transformation of XML documentation to HTML

    • Via use of an XSLT stylesheet - made by Anders Hejlsberg

    • A stylesheet is provided with the book C# to the Point

      • Primitive and obsolete!

Tool support: Doxygen
Slide Annotated slide Contents Index
References Textbook 

Doxygen is a third part interface documentation tool written by Dimitri van Heesch, originally developed for C++, C, and Java

  • Doxygen

    • A documentation tool - for multiple programming languages

    • Can produce HTML documentation directly from the C# source

      • Can also produce documentation in other representations

    • The intermediate XML documentation - made by the C# compiler - is not used

    • Can be controlled from a GUI front end: Doxywizard

    • www.doxygen.org

Exercise 15.3. Install Doxygen

Download and install the latest version of Doxygen from www.doxygen.org on your computer. Consult the information about Doxygen on the accompanying slide. Also, consult our simple example of BankAccount documentation made by Doxygen.

More specifically on Windows (as of February 2010) go to the Doxygen Download page and download the binary distribution doxygen-1.6.3-setup.exe. The direct link is here. After installation, start the Doxywizard.

Consult the Doxygen documentation, maybe in particular the documentation of the GUI front-end. In addition, read Dan Jensens note Installing and Using Doxygen.

Exercise 15.3. Give Doxygen a Try

This exercise is guided tour in using Doxygen together with Visual C# 2008 Express. The exercise will help you set up the BankAccount documentation example, which we have seen on an earlier slide page in this lecture.

We will assume that you already have installed Doxygen and that you use Visual C# 2008 Express.

Start Visual C# 2008 Express. Use File > New Project... and make (at least in this exercise) a Class Library project.

Insert the BankAccount class in Visual C# 2008 Express in the usual way.

Do File > Save All. Notice the location of you project. On a piece of paper (or in a text editor) notice the full file path to your Visual C# 2008 project.

Start the Doxywizard program, which comes together with Doxygen.

In the Wizard > Project field: Give a name to your project. Just chose a suitable name.

In the Source Code Directory field, select the full path to the directory where Visual C# 2008 Express stores the source files. This is the directory in which Visual C# 2008 express stores the files with .cs file extension. You find this directory inside the Visual C# 2008 express project directory, which you captured earlier in this exercise. Relative to the way C# source programs are organized, it is usually not necessary to select Scan recursively.

In the Destination directory field select the directory in which you want to store the documentation which Doxygen generates. An existing directory of your choice.

In Wizard > Mode select the extraction mode. Try first documented entities only. It is recommended that you explicitly document the entries which appear in your documentation. Select the Java or C# programming language option.

In Wizard > Output select one of the HTML options (try first plain HTML). Deselect LaTeX.

In Doxygen, save the doxygen setup via File > Save or File > SaveAs.... This will make a file called Doxyfile. The Doxyfile contains all the settings of Doxygen. At another occasion, you can continue working on a particular batch of documentation by doing a File > Open... on the Doxyfile.

Now, in the Run tab, activate the button Run doxygen.

Use the button Show HTML output to look at the generated HTML documentation in your browser.

 

Notice that Doxygen is a very rich tool. Take a look at some of the Expert options in the DoxyWizard. There exists another note, written by a former student, Dan Jensen. You are encouraged read Dans note as your next step in getting familiar with Doxygen.

Tool support: Other possibilities
Slide Annotated slide Contents Index
References Textbook 

  • NDoc

    • Documentation tool that collects documentation from assemblies and XML documentation file

    • Specific to .NET

    • Not actively developed since 2005

      • Does not support C# 2.0

  • Sandcastle

    • Generates MSDN style documentation

      • Based on assemblies (reflection) and the XML documentation file

      • Used internally by Microsoft to generate the .NET library documentation

    • Still difficult to install and use!!!

  • Visual Studio, regular or express

    • The documentation provided in documentation comments can be used by Intellisense

Another documentation example in C#
Slide Annotated slide Contents Index
References Textbook 

Documentation of class BankAccount and its three subclasses

Reference

Program: The base class BankAccount.
using System;

/// \mainpage Doxygen Demo.
/// \section intro_sec Introduction
/// This documentation serves as a Doxygen demonstration.
/// We document the BankAccount class and a number of 
/// specialized bank account classes.

/// <summary> 
///   A simple bank account created as an everyday example
///   for the OOP course. Used in particular for demonstrating inheritance.
/// </summary>
/// <example>
///   <code>
///      BankAccount ba = new BankAccount("Peter");
///      ba.Deposit(100.0);
///      ba.Withdraw(50.0);
///   </code>
/// </example>
public class BankAccount {

   protected double interestRate;
   protected string owner;
   protected decimal balance;

   /// <summary>
   ///  Construct a bank account from owner, balance, and interestRate. 
   /// </summary>
   /// <param name = "o"> The owners name </param>
   /// <param name = "b"> The initial amount of this account</param>
   /// <param name = "ir"> 
   ///    The interest rate. 
   ///    Annual interet is calculated as balance * interestRate 
   /// </param>
   public BankAccount(string o, decimal b, double ir) {
      this.interestRate = ir;
      this.owner = o; 
      this.balance = b;
   }

   /// <summary>
   ///  Construct a bank account from owner and interestRate. 
   /// </summary>
   /// <param name = "o"> The owners name </param>
   /// <param name = "ir"> 
   ///    The interest rate. 
   ///    Annual interet is calculated as balance * interestRate 
   /// </param>
   public BankAccount(string o, double ir):
     this(o, 0.0M, ir) {
   }

   /// <summary>
   ///   Returns the current amount of the bank account 
   ///  with affecting the account.
   /// </summary>
   ///  <value> The amount of money </value>
   public virtual decimal Balance {
     get {return balance;}
   }

   /// <summary>
   /// <list>
   ///   <item> Withdraw an amount of money from the account. </item>
   ///   <item> This decreases the balance of the account. </item>
   /// <list>
   /// </summary>
   /// <param name = "amount"> 
   ///  The amount of money to withdraw from the account.
   ///  Precondition: Must be non-negative.
   /// </param>   
   public virtual void Withdraw (decimal amount) {
      balance -= amount;
   }

   /// <summary>
   ///   Withdraw an amount of money from the account.
   ///   This increases the balance of the account.
   /// </summary>
   /// <param name = "amount"> 
   ///  The amount of money to deposit to the account.
   ///  Precondition: Must be non-negative.
   /// </param>   
   public virtual void Deposit (decimal amount) {
      balance += amount;
   }
 
   /// <summary>
   ///  Add the annual interest to the account.
   ///  This may increase the current balance of the account.
   /// </summary>
   public virtual void AddInterests() {
      balance += balance * (Decimal)interestRate;
   }    

   /// <summary>
   ///   Return a text string that represents this account
   ///   for output purposes
   /// </summary>
   public override string ToString() {
      return owner + "'s account holds " +
            + balance + " kroner";
   }
} 

Program: The class CheckAccount.
using System;

/// <summary> 
///   A specialization of BankAccount.
/// </summary>
public class CheckAccount: BankAccount {

   /// <summary> A constructor that constructs a CheckAccount on the 
   /// basis of an owner and the interestrate</summary>
   /// <param name = "o"> The owners name </param>
   /// <param name = "ir"> The interestrate </param>
   public CheckAccount(string o, double ir): 
     base(o, 0.0M, ir) {
   }

   /// <summary> A constructor that constructs a CheckAccount on the 
   /// basis of an owner, balance, and the interestrate</summary>
   /// <param name = "o"> The owners name </param>
   /// <param name = "b"> The initial balance of the account </param>
   /// <param name = "ir"> The interestrate </param>
   public CheckAccount(string o, decimal b, double ir): 
     base(o, b, ir) {
   }

   /// <summary> Withdraw an amount from the check account </summary>
   /// <param name = "amount"> The amount withdrawn </param>
   public override void Withdraw (decimal amount) {
      balance -= amount;
      if (amount < balance)
         interestRate = -0.10;
   }

   /// <summary> Returns a string which represents the account </summary>
   public override string ToString() {
      return owner + "'s check account holds " +
            + balance + " kroner";
   }
} 

Program: The class SavingsAccount.
using System;

/// <summary> 
///   A specialization of BankAccount for saving purposes.
/// </summary>
public class SavingsAccount: BankAccount {

   /// <summary> A constructor that constructs a Savings account on the 
   /// basis of an owner and the interestrate. The balanced defaults
   /// to 0.0.</summary>
   /// <param name = "o"> The owners name </param>
   /// <param name = "ir"> The interestrate </param>
   public SavingsAccount(string o, double ir): 
     base(o, 0.0M, ir) {
   }

   /// <summary> A constructor that constructs a SavingsAccount on the 
   /// basis of an owner, balance, and the interestrate</summary>
   /// <param name = "o"> The owners name </param>
   /// <param name = "b"> The initial balance of the account </param>
   /// <param name = "ir"> The interestrate </param>
   public SavingsAccount(string o, decimal b, double ir): 
     base(o, b, ir) {
   }

   /// <summary> Withdraw an amount from the savings account </summary>
   /// <param name = "amount"> The amount withdrawn </param>
   /// <exception cref = "Exception"> In case of insufficient funds
   ///    an exception is thrown </exception>
   public override void Withdraw (decimal amount) {
      if (amount < balance)
          balance -= amount;
      else
          throw new Exception("Cannot withdraw");
   }

   /// <summary>
   ///   Add the annual interest to the savings account.
   ///   This may increase the current balance of the account.
   /// </summary>
   public override void AddInterests() {
      balance = balance + balance * (decimal)interestRate 
                        - 100.0M;
   }    

   /// <summary>
   ///   Return a text string that represents this account
   ///   for output purposes
   /// </summary>
   public override string ToString() {
      return owner + "'s check account holds " +
            + balance + " kroner";
   }
} 

Program: The class LotteryAccount.
using System;

/// <summary> 
///   A specialization of BankAccount.
/// </summary>
public class LotteryAccount: BankAccount {

   private static Lottery lottery  = Lottery.Instance(20);

   /// <summary> Construct a lottery account based on 
   ///   owner o and the initial balance b </summary>
   /// <param name = "o"> The owner of the account </param>
   /// <param name = "b"> The initial balance of the account </param>
   public LotteryAccount(string o, decimal b): 
     base(o, b, 0.0) {
   }

   /// <summary> Add interest to the lottery account.
   ///    This may be a lot if a drawn lottery number is
   ///    the winning number. If not, zero interest is added.
   /// </summary>
   public override void AddInterests() {
      int luckyNumber = lottery.DrawLotteryNumber;
      balance = balance + lottery.AmountWon(luckyNumber);
   }    

   /// <summary>
   ///   Return a text string that represents this account
   ///   for output purposes
   /// </summary>
   public override string ToString() {
      return owner + "'s lottery account holds " +
            + balance + " kroner";
   }
} 

Program: The singleton class Lottery - used by LotteryAccount.
using System;

/// <summary> A class which assists LotteryAccount with the selection 
///           of lucky accounts. Encapsulates a secret winning number
///           and the amount won. A singleton class. </summary>
public class Lottery{

  private static Random rdm = new Random(unchecked((int)DateTime.Now.Ticks));

  private int difficulty;
  private readonly int winningNumber;
  private readonly decimal amountWon;
  private static Lottery uniqueInstance = null;

  private Lottery(int difficulty){
    this.difficulty = difficulty;
    this.winningNumber = rdm.Next(difficulty);
    this.amountWon = 500000.00M;
  }

  /// <summary> Returns the unique instance of this class</summary>
  /// <param name = "difficulty"> A measure of the difficulty of winning. </param>
  public static Lottery Instance(int difficulty){
    if (uniqueInstance == null)
      uniqueInstance = new Lottery(difficulty);
    return uniqueInstance;
  }

  /// <value>Draw and return a lottery number </value>
  public int DrawLotteryNumber{
    get {return rdm.Next(difficulty);}
  }

  /// <summary> Return if n is equal to the winning number </summary>
  public bool WinningNumber(int n){
    return n == winningNumber;
  }

  /// <summary> 
  ///   Return the encapsulated amount won if
  ///   luckyNumber is the winning number.
  /// </summary>
  /// <param name = "luckyNumber">Some integer number </param>
  public decimal AmountWon(int luckyNumber){
    decimal res;
    if (WinningNumber(luckyNumber))
       res = amountWon;
    else
       res = 0.0M;
    return res;
  }
}

Reference

Exercise 15.4. Documentation of class Set

In a previous exercise we have worked with the class Set<T>.

Write documentation for the operations insersection, union, and diff (set difference). If you have time and energy, also write documentation for other members.

Generate Doxygen documentation for the class.

You may also want to generate XML documentation for the class.

The natural starting point of this exercise is your own solution to the previous exercises. You can also chose to document my solution.

Conclusion - Documentation of C# Programs
Slide Annotated slide Contents Index
References Textbook 

  • XML Comments in C# programs

    • In principle a good idea

    • The XML documentation repertoire is not comprehensive

    • Voluminous

  • The generated XML documentation file

    • In principle a good idea

    • Should have been self-contained and complete

    • Should "automatically" be translated to good HTML documentation

Microsoft's C# documentation facilities are complicated to use, rudimentary, and of poor quality

Does not meet the standards of C# as such

Far away from the quality of Javadoc from Sun


Project Recommendations

Documentation Recommendations
Slide Annotated slide Contents Index
References Textbook 

Recommendations for program documentation in your project

  • Use of Doxygen

  • Document the client interfaces of all types (all classes) in your project

  • Deliver the documentation as an electronic enclosure

  • Arrange that the documentation is linked to a clean version the actual source program

    • Linked to source program: Expert > Source Browser: SOURCE_BROWSER.

    • Clean version: Expert > Source Browser: STRIP_CODE_COMMENTS

  • The documentation should not be written as a last minute effort

    • It is useful for fellow programmers during the project

The generated type documentation is a much more attractive entry point to your code than the raw source files


Collected references
Contents Index
Comments in C# Earlier in these notes
Doxygen Documentation of class BankAccount
XML Documentation elements Internet Resource
Supported Doxygen XML Commands Internet Resource
Doxygen HTML Commands Internet Resource
Native Doxygen Documentation Commands Internet Resource
Documentation comments in C# Earlier in these notes
Doxygen Documentation of class BankAccount and subclasses

 

Chapter 15: Documentation of Object-oriented Programs
Course home     Author home     About producing this web     Previous lecture (top)     Next lecture (top)     Previous lecture (bund)     Next lecture (bund)     
Generated: February 7, 2011, 12:23:38