… because everyone loves writing documentation.
Abstract
In this lesson we will examine several common categories of program documentation:
We’ll explore the reasons why source code comments and many traditional forms of charting have declined in perceived value, and why there is increasing emphasis on API documentation and project reports.
We will look at automated tools for generating and publishing API documentation and project reports.
widely used
widely abused
McConnell has a good & balanced discussion on this.
Source code commenting is often a crutch to hide
Still useful for
Modern focus has shifted considerably away from commenting bodies towards API documentation.
double m; // mean average
double s; // standard deviation
double meanAverage
double standardDeviation
// Sum up the data
double sum = 0.0;
double sumSquares = 0.0;
// Add up the sums
for (double d: scores)
{
sum += d;
sumSquares += d*d;
}
// Compute the average and standard
// deviation
double meanAverage = sum / numScores;
double standardDeviation =
sqrt ((sumSquares - numScores*sum*sum)
/(numScores - 1.0));
// Subtract the average from each data
// item and divide by the standard
// deviation.
for (int i = 0; i < numScores; ++i)
{
scores[i] = (scores[i] - meanAverage)
/ standardDeviation;
}
// Compute summary statistics
double sum = 0.0;
double sumSquares = 0.0;
for (double d: scores)
{
sum += d;
sumSquares += d*d;
}
double meanAverage = sum / numScores;
double standardDeviation =
sqrt ((sumSquares - numScores*sum*sum)
/ (numScores - 1.0));
// Normalize the scores
for (int i = 0; i < numScores; ++i)
{
scores[i] = (scores[i] - meanAverage)
/ standardDeviation;
}
// Compute summary statistics
double sum = 0.0;
double sumSquares = 0.0;
for (double d: scores)
{
sum += d;
sumSquares += d*d;
}
double meanAverage = sum / numScores;
double standardDeviation =
sqrt ((sumSquares - numScores*sum*sum)
/(numScores - 1.0));
// Normalize the scores
for (int i = 0; i < numScores; ++i)
scores[i] = (scores[i] - meanAverage)
/ standardDeviation;
void computeSummaryStatistics (
const double* scores, // inputs
int numScores,
double& meanAverage, // outputs
double& standardDeviation)
{
double sum = 0.0;
double sumSquares = 0.0;
for (double d: scores)
{
sum += d;
sumSquares += d*d;
}
meanAverage = sum / numScores;
standardDeviation =
sqrt ((sumSquares - numScores*sum*sum)
/(numScores - 1.0));
}
void normalizeData (double* data,
int numData,
double center,
double spread)
{
for (int i = 0; i < numData; ++i)
data[i] = (data[i] - center) / spread;
}
⋮
double meanAverage;
double standardDeviation;
computeSummaryStatistics (scores, numScores,
meanAverage, standardDeviation);
normalizeData (scores, numScores,
meanAverage, standardDeviation);
void computeSummaryStatistics (
const double* scores, // inputs
int numScores,
double& meanAverage, // outputs
double& standardDeviation)
{
double sum = 0.0;
double sumSquares = 0.0;
for (double d: scores)
{
sum += d;
sumSquares += d*d;
}
meanAverage = sum / numScores;
standardDeviation =
sqrt ((sumSquares - numScores*sum*sum)
/(numScores - 1.0));
}
void normalizeData (double* data,
int numData,
double center,
double spread)
{
for (int i = 0; i < numData; ++i)
data[i] = (data[i] - center) / spread;
}
⋮
double meanAverage;
double standardDeviation;
computeSummaryStatistics (scores, numScores,
meanAverage, standardDeviation);
normalizeData (scores, numScores,
meanAverage, standardDeviation);
void computeSummaryStatistics (
const double* scores, // inputs
int numScores,
double& meanAverage, // outputs
double& standardDeviation)
{
double sum = accumulate(
scores, scores+numScores);
double sumSquares = accumulate(
scores, scores+numScores,
[](double x, double y)
{return x + y*y;});
meanAverage = sum / numScores;
standardDeviation =
sqrt ((sumSquares - numScores*sum*sum)
/(numScores - 1.0));
}
⋮
// Normalize the scores
double meanAverage;
double standardDeviation;
computeSummaryStatistics (scores, numScores,
meanAverage, standardDeviation);
transform (
scores, scores+numScores,
scores,
[] (double d) {
return (d - meanAverage)
/ standardDeviation});
Repeat of the code
Useless
Explanation of the code
Only useful if the code is confusing
In which case, first priority should be to simplify the code.
Markers
notes not intended to be left in final code
If standardized, useful
e.g., // TODO
in Eclipse
Summary of the code
Description of intent
similar to summary, but describes problem rather than solution
Information that cannot be expressed in the code
e.g., authors, copyright, date of modification
Self-Documenting code relies on good programming style to perform most of the documentation.
Classes
Does the class’s interface present a consistent abstraction?
Is the class well named, and does its name describe its central purpose?
Does the class’s interface make obvious how you should use the class?
Is the class’s interface abstract enough that you don’t have to think about how its services are implemented? Can you treat the class as a black box?
Routines
Does each routine’s name describe exactly what the routine does?
Does each routine perform one well-defined task?
Have all parts of each routine that would benefit from being put into their own routines been put into their own routines?
Is each routine’s interface obvious and clear?
Data Names
Are type names descriptive enough to help document data declarations?
Are variables named well?
Are variables used only for the purpose for which they’re named?
Are loop counters given more informative names than i, j, and k?
Are well-named enumerated types used instead of makeshift flags or boolean variables?
Are named constants used instead of magic numbers or magic strings?
Do naming conventions distinguish among type names, enumerated types, named constants, local variables, class variables, and global variables?
Data Organization
Are extra variables used for clarity when needed?
Are references to variables close together?
Are data types simple so that they minimize complexity?
Is complicated data accessed through abstract access routines (abstract data types)?
Control
Is the nominal path through the code clear?
Are related statements grouped together?
Have relatively independent groups of statements been packaged into their own routines?
Does the normal case follow the if rather than the else?
Are control structures simple so that they minimize complexity?
Does each loop perform one and only one function, as a well-defined routine would?
Is nesting minimized?
Have boolean expressions been simplified by using additional boolean variables, boolean functions, and decision tables?
Layout
- Does the program’s layout show its logical structure?
Design
Is the code straightforward, and does it avoid cleverness?
Are implementation details hidden as much as possible?
Is the program written in terms of the problem domain as much as possible rather than in terms of computer-science or programming-language structures?
(McConnell, ch 32)
How many forms of software documentation charting do you know?
Flowcharts
Nassi-Schneidermann Charts
Structure (call) charts
Data-Flow Diagrams
For as long as people have been writing source code, they’ve been looking for ways to ease the effort of documenting that code.
Earliest examples were automatic flowchart generators
Generating flowcharts from source code.
Still offered in reverse engineering tools ( e.g. )
A hallmark of so-called CASE (Computer-Aided Software Engineering) systems
API documentation tools are now more common
Reflect modern emphasis on re-usable interfaces
Combine info from
a (limited) language parser
and specially formatted blocks of comments embedded in the source code
Encourages updating comments as code is modified
Comments become a legitimately useful tool for application writers.
Application writers have less need to access actual code.
Generate linked documents to facilitate browsing of referenced type names and other entities
Some IDEs understand this markup as well and use it enhance “live” help while editing code.
Perhaps the best known tool in this category
part of the standard Java distribution
achieved prominence when Sun used it to document the Java “standard library”.
Javadoc markup is enclosed in comments delineated by /** ... */
A comment block precedes the entity that it describes
In addition to “free-form” text, can contain special markup
Common Javadoc Markup
@author authorName
@version versionNumber
@param name description
@return description
@throws exceptionClassName description
@see crossReference
Running javadoc
Command line
javadoc -d destinationDir -sourcepath sourceCodeDir \
-link http://docs.oracle.com/javase/7/docs/api/
Eclipse: Project
⇒ Generate Javadoc ...
ant
<javadoc packagenames="edu.odu.cs.*"
destdir="target/javadoc"
classpathref="javadoc.classpath" Author="yes"
Version="yes" Use="yes" defaultexcludes="yes">
<fileset dir="." defaultexcludes="yes">
<include name="extractor/src/main/java/**" />
<include name="generatedSource/gen-src/**" />
<exclude name="**/*.html" />
</fileset>
<doctitle><![CDATA[<h1>ODU CS Extract
Project</h1>]]></doctitle>
</javadoc>
the most popular API generator for C/C++
Markup is essentially identical to javadoc
Output can be HTML, LaTeX, or RTF
Can also generate
Running doxygen
Command line
doxygen configFile
PROJECT_NAME = C++ Spreadsheet
INPUT = src/model
OUTPUT_DIRECTORY = target/doc
EXTRACT_ALL = YES
CLASS_DIAGRAMS = YES
GENERATE_HTML = YES
GENERATE_LATEX = YES
USE_PDFLATEX = YES
Eclipse: Eclox plugin
Ant task for doxygen
Because a documentation generator needs to module and function structure and function parameters, a distinct parser is needed for each programming language.
This leads to a variety of language-specific tools, e.g.,
jsDoc for Javascript
YARD for Ruby
sandcastle for .Net
We’ve already looked JUnit, which can be used to generate test reports like this one.
This is generated in ant via the junitreport
task:
<project name="code2html" basedir="." default="build">
<record name="ant.log" action="start" append="false" />
<taskdef classpath="JFlex.jar" classname="JFlex.anttask.JFlexTask" name="jflex" />
<echo>loading build-${os.name}.paths</echo>
<include file="build-${os.name}.paths"/>
<target name="generateSource">
<mkdir dir="src/main/java"/>
<jflex file="src/main/jflex/code2html.flex"
destdir="src/main/java"/>
<jflex file="src/main/jflex/code2tex.flex"
destdir="src/main/java"/>
<jflex file="src/main/jflex/list2html.flex"
destdir="src/main/java"/>
<jflex file="src/main/jflex/list2tex.flex"
destdir="src/main/java"/>
</target>
<target name="compile" depends="generateSource">
<mkdir dir="target/classes"/>
<javac srcdir="src/main/java" destdir="target/classes"
source="1.6" includeantruntime="false"/>
</target>
<target name="compile-tests" depends="compile">
<mkdir dir="target/test-classes"/>
<javac srcdir="src/test/java" destdir="target/test-classes"
source="1.6" includeantruntime="false">
<classpath refid="testCompilationPath"/>
</javac>
</target>
<target name="test" depends="compile-tests">
<property name="mypath" refid="testExecutionPath"/>
<echo>testExecutioPath is ${mypath}</echo>
<echoproperties/>
<mkdir dir="target/test-results/details"/>
<junit printsummary="yes"
haltonfailure="yes" fork="no"
>
<classpath refid="testExecutionPath"/>
<formatter type="xml"/>
<batchtest todir="target/test-results/details">
<fileset dir="target/test-classes">
<include name="**/*Test*.class"/>
</fileset>
</batchtest>
</junit>
<junitreport todir="target/test-results">
<fileset dir="target/test-results/details">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="target/test-results/html"/>
</junitreport>
</target>
<target name="build" depends="test">
<jar destfile="codeAnnotation.jar" basedir="target/classes">
<manifest>
<attribute name="Main-Class"
value="edu.odu.cs.code2html.Code2HTML"/>
</manifest>
</jar>
</target>
<target name="clean">
<delete dir="target"/>
</target>
</project>
Other common test reports
Javadoc of unit test code
Coverage reports
Many tools that we will cover later for analyzing code can produce useful (or at least, impressive) documentation as a side effect.
Configuration managers (to be covered later) generate reports about the dependencies among the software components.
Examples:
Traditionally hand-constructed
Some build managers will generate websites linking together reports
You can also add instructions to your build manager to post files to a website.
Common cases:
The web server is on the same file system as the development machine.
e.g., You are developing on atria.cs.odu.edu
and can publish web pages on http://www.cs.odu.edu/~yourName
by simply placing files in ~yourName/public_html
.
The web server is on the a separate file system, possibly a spearate local network, from the development machine.
You will need an account on the web server through which you can do ftp
or sftp
file transfers.
Continuous Integration servers often integrate web services for automatically generated reports.
We’ll look at examples of the first two cases now, and the third later n the semester.
<property name="deploymentDestination"
location="/home/zeil/public_html/myProject/"/>
⋮
<target name="deploy" depends="build"
description="Sync with the website directory"
>
<sync todir="${deploymentDestination}/reports"
includeEmptyDirs="true" granularity="2000">
<fileset dir="target/reports">
<include name="**/*.html"/>
<include name="**/*.png"/>
<exclude name="**/*.xml"/>
</fileset>
<preserveintarget>
<include name="**/.ht*"/>
</preserveintarget>
</sync>
</target>
<property name="webserver"
location="atria.cs.odu.edu"/>
<property name="website.path"
location="/home/zeil/public_html/myProject/"/>
⋮
<target name="publish-reports" depends="reports"
description="send project reports to web server">
<tar destfile="target/project-reports.tz" compression="gzip"> ➀
<tarfileset dir="target">
<include name="project-reports/**/*"/>
</tarfileset>
</tar>
<input message="login name for ${webserver}:" addproperty="scp.login"/> ➁
<input message="password for ${webserver}:" addproperty="scp.password"/>
<scp file="target/project-reports.tz" sftp="true" ➂
remoteToDir="${scp.login}:${scp.password}@${webserver}:${website.path}"/>
<sshexec host="${webserver}" username="${scp.login}" password="${scp.password}"
command="cd ${website.path}; tar xzf project-reports.tz"/> ➃
</target>
A software forge is a collection of web services for the support of collaborative software devlopment:
Project web sites
Networked access to version control
Communications (e.g., messaging, wikis, announcements)
Bug reporting and tracking
Project personnel management
Forge Examples
Among the best known forges are
the original, SourceForge, (1999)
Google Code, (2006)
GitHub, (2008)
The CS 350 course has its own forge