Avoid these common mistakes:
All information poured into README
, with too much detail
(cognitive overload)
6-line header comment for a 4-line function
Undocumented representations
Undocumented private functions
Exposed representations that should be abstract
Here is what I expect:
Stratify your documentation into three layers: architecture, interfaces, implementations.
Your README
should document the architecture of the system.
Each interface may get a short description, but no more.
Architecture means "how the modules fit together", and it's
needed only for more ambitious projects. By definition,
architectural documentation is not associated with any one module,
so it goes in the README
file.
Rule of thumb: data types may be mentioned (in the world of ideas) but functions should not be mentioned.
Each interface should be documented with
An overall header comment briefly explaining
The general purpose (in many cases one line is enough)
The declared data types and what they stand for in the world of ideas
General knowledge needed to understand and use the interface (e.g., references to man pages or other info), if any
Well-chosen names!! (critical form of documentation)
Short documentation for each function. Aim for about one line per function---but recognize that sometimes it is clearer to document a small group of functions and let the names and types speak for themselves.
Don't forget to document the element types of arrays, sequences, and tables!!
Each implementation should be documented with
Descriptions for each declared type and global variable. What does it represent in the world of ideas? What are its invariants?
Descriptions of any functions private to the implementation:
Private functions must be declared static
.
These functions should have prototypes.
The prototypes should be documented in much the same way as the function prototypes in a .h file.
As noted by Fred Brooks, if the data types are well documented and a private function is well named, it may not need any more documentation.
Bodies of functions should be documented only where code is tricky, long, or difficult to understand.
Remember that an invariant is a claim whose truth can be checked at a single point in time.
The contract for a function describes two points in time: just before the function is called and just after it returns.
If you write a narrative description of a sequence of events in time, that is not an invariant or a contract: it is a description of an algorithm. Very rarely in COMP 40 is it useful to document an algorithm---if you tell me the data structures, their invariants, and the contracts of the functions, the algorithms are obvious.
A good invariant is usually divided into parts. The invariant is deemed true if and only if all the parts are true.
A good invariant has no redundant parts.
A good invariant mentions every part of the representation.
Some parts of a good invariant may refer only to the representation.
A good invariant relates the implementation to an abstraction in the world of ideas. If a representation satisfies all parts of the invariant, it will determine exactly what thing in the world of ideas each valid representation stands for.