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:
// // 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.
// ----- // int computeCost() const PRIVATE // Data members modified: NONE // Helper to: getCost() // // Computes cost with current sales tax. // -----This should include four parts.
This includes the return type, name of the function, and whether it's const or not. Also, if it's a private method, it should indicate that it's private.
Write NONE if no data members are potentially changed. Such methods should be const.
Private methods should be helper functions, so they should list which functions they help (including, other private helper functions). Public methods may end up being helpers to other public methods (esp. if you use "size()").
For some, you can just say "copy constructor". For others, write a few sentences.
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.
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.
This includes the name of the file, the author, your login ID, your section, and the date it's due.
On one line, you should write the name of the class.
In a paragraph or two, describe what the class does, and what purpose, if any, it serves.
Between the time that the object is constructed and the time that it's destructed, these conditions hold true about the object. The only time that the invariant is violated is potentially while a method is being run (after the code in the method has run, but before it has completed).
When you list out the conditions, write it in pseudo-English, then in some kind of logic. Since you may not have much experience, do the best you can.
Write a section that looks like:
Data Members
------------
Then, list out each data member, including its type. To its left,
put a + or -. + indicates it's a public data member (which is rare)
and - indicates it's private (this follows a convention used in
UML). Below it, write a one or two line description.
At this point, you will list out all methods implemented in your class. This will consist of doing the following:
Since these methods are so important, list out these methods
separately.
Write a section that looks like:
Constructors/Destructors/Assignment
-----------------------------------
List out any constructors, destructor, or assignment operator
that are IMPLEMENTED.
Mutators are methods that potentially modify data members.
Thus, such methods are not const. List out mutators under
a heading like:
Mutators
--------
Mutators methods can be public or private.
Accessors are "get" methods that return a copy of the data member. If it returns a pointer or non-const reference, list it under the mutators section.
Queries are methods that get some information without modifying the object (for example, how many objects are green).
Both accessors and queries are methods which do not modify the object, so they should be const.
Write this in a section labeled:
Accessors/Queries
-----------------
Accessor/Query methods can be public or private.
These are methods mainly used in the testing of your class. They can be mutators or accessor/query methods. The goal is to have code that tests the class invariants, preconditions, and postconditions. If you have a chance, write some. However, these will (initially) not be graded very heavily.
Write this in a section labeled
Verifiers
---------
Verifier methods can be public or private.
Since this file is rather lengthy, it's HIGHLY SUGGESTED that you document this as you write your code, and if at all possible, write it prior to coding.