Documenting Projects

Documenting is a pain, especially in introductory courses. In later courses, the documentation either increases by a lot (say, software engineering) so that early projects are all about documentation, or not at all (say, networks).

Documentation is often treated as an afterthought, but it's a good idea to get some practice now, because documentation becomes a critical part of larger projects. Even though the documentation you do for this course will probably differ greatly from documentation you have in any job, it is still practice.

Why document? Students complain that they know what their project does, so why should they actually have to write documentation? Sometimes students complain that English is their second or third language, and that documentation shouldn't be required because of this.

Documentation is done for several reasons. First, it lets other people understand what you are doing. This could be the TA or the instructor. In fact, it could be you! Often, students hold onto their old projects, and then they may need to look at it in a later class. Without documentation, reading the code can be very difficult, even if you were the author of the code.

Documentation can also be useful for planning your code. In fact, large software projects often write documentation prior to writing code. That way, it's clear what the responsibilities of the software team is, and also to make sure that the overall code makes some sense. This can occupy a great deal of time, but then once done, the coding, hopefully, is straightforward.

So, to summarize, you document for several reasons:

What To Document

Documentation will consist of several parts: putting your name on the top of each file you submit, commenting code, and writing a separate text file containing information about preconditions, postconditions, etc.

Comment at Top of Code

At the top of EVERY .cpp and .h file, you should have the following
//
// File: rational.cpp
// Description: This program reads, writes and does mathematical 
// operations on rational numbers. A rational number is defined as a 
// fraction whose numerator and demoninator are both integers.
//
//    Author: Bunny Tjaden
//  Login ID: bt14002
//   Section: 0101
//  Due date: February 2, 2002 
// Est. Time: 2 hours           (estimate of time to complete)
//
It should indicate the name of the file, a brief description (two or three sentences is fine), plus your name, your login ID, your section, the due date (optional, but good for historical purposes) and the estimated amount of time to completion.

In the .cpp portion of the code, you should place a header prior to each method implemented. For some methods, a short description of what it does is sufficient (such as copy constructor, assignment operator), while other methods should have something longer.

Comment Before Each Function

// -----
//   int computeCost() const        PRIVATE
//      Data members modified:  NONE
//      Helper to:  getCost()
//
//      Computes cost with current sales tax.
// -----
This should include four parts.

Commenting Within the Body of Code

The easiest place to comment is prior to any condition (loops, if-else statements). What should comments do? Several things: Comments to yourself can be prefaced with capital words, as in CHECK, REMOVE, FILL.

I suggest some repeated letters, like the first character of your name: e.g., "CCC". That way, you can run a tool like "grep" to locate these special comments to yourself.

So, comments aren't always for other people, they are to remind yourself to check something later on, sort of like sticky post-it pads.

Commenting in DOC file

This will be new to all students. You will be asked to comment classes in a separate file. The file should end in a .doc. It should have a header, just like the .h and .cpp files.

Here's an example of what to put in the file

      File: Stack.doc

    Author: Bunny Tjaden
  Login ID: bt14002
   Section: 0101
  Due date: February 2, 2002 

Class: Stack

Description:
   Stack is a class which implements an abstract stack.   It allows
users to push, pop, and determine whether a stack is empty.  It is
implemented using a linked list.

Class Invariants
----------------
   * stack size is non-negative
       size >= 0

   * top is valid
       top == NULL || valid_node( *top )

   * if empty, top is NULL
       size == 0 --> top == NULL

   * size == number of nodes (consistency of data members)
       size = manualCount( top )  where manualCount counts nodes

Data Members
------------
-  int size
      stores size of stack

-  Node *top
      points to top of stack.  NULL, if empty

Constructors/Destructors/Assignment
-----------------------------------
   +  Stack()
       Modifies: size, top
       Efficiency: O(1)
       Postcondition: size == 0 && top == NULL

       Creates empty stack.

   +  Stack( const Stack &other )
       Modifies: size, top
       Efficiency: O(n)   (n steps to copy stack)
       Precondition: true
       Postcondition: size == other.size && *this == other

       Makes a deep copy of other stack

   +  Stack & operator=( const Stack &other )
       Modifies: size, top
       Efficiency: O(n)   (n steps to copy stack)
       Precondition: true
       Postcondition: size == other.size && *this == other

       Makes a deep copy of other stack

   +  ~Stack()
       Modifies: size, top
       Efficiency: O(n)   (n steps to delete stack)
       Precondition: true

       Destructor

Mutators
--------
   +  void push( string str )
       Efficiency: O(1)
       Modifies: size, top
       Precondition: true
       Postcondition: size == size' + 1 && top->getData() == str
                       && *this == str + *this'

       Pushes a node on top of stack

   +  bool pop( string str, string & output )
       Efficiency: O(1)
       Modifies: size, top
       Precondition: true
       Postcondition: size == size' - 1 
                       && top->getData() == top'->getNext()->getData()
                       && *this == str + *this'

       Pushes a node on top of stack

  -   void copy( const Stack & ) const
         Helper To: copy constructor, assignment operator
         Modifies: size, top
         Precondition: size == 0 && top == NULL
         Postcondition: size == other.size 
                        && *this == other

       Copies stack.  No deallocation performed.
         
Accessors/Queries
-----------------
   +  int size() const
       Efficiency: O(1)
       Modifies: NONE
       Precondition: true
       Postcondition: result == size

       Returns the size of the stack

   +  bool isEmpty() const
       Efficiency: O(1)
       Modifies: NONE
       Precondition: true
       Postcondition: result == ( size == 0 )

       Returns true if the stack is empty

Verifiers
---------
   -  bool sizeIsCorrect() const
        Efficiency: O(n)
        Modifies:   NONE
        Precondition: true
        Postcondition: result == ( size == manualCount() )

      Makes sure the size matches with the manual count.  If so,
      return true.

    - int manualCount() const
        Efficiency: O(n)
        Modifies:   NONE
        Precondition: true
        Postcondition: result == "manual count of nodes"
      
      Counts nodes by looping through
This is what you should include in your documentation.