How do you write comments for DocJet?
If you clicked on this topic first, give yourself a gold star! When
evaluating a documentation tool, it's easy to get caught up in all the glitz and
glamour of the GUI configuration tools and whatever, but the bulk of the time
you'll spend in your documentation effort should be in writing comments.
The comment parser is the real "user interface" of any documentation
tool.
It's DocJet's comment parser that really separates DocJet from its
competitors. DocJet is built on the idea that one of the necessary steps
in getting people to write comments is to make it as easy as possible to write
good comments.
This fact is at the core of DocJet's design philosophy. DocJet is built
to accommodate a wide variety of commenting schemes, including that used by NDoc
and JavaDoc. It does this through a variety of plug-in interfaces.
But the preferred method of writing comments for DocJet is in the freeform ASCII
style that people have been using since the concept of the comment was invented.
There's no requirement for how you introduce your comments either, the comment
just has to be adjacent to the object being defined.
It's hard to fully describe what we are talking about here because DocJet
supports so many different languages and many different conventions employed in
each language. But let's throw an example out there:
// Description: Starts a paragraph finding
//
// Arguments:
// bmfo - The markup function used to combine the elements of the
// paragraph finding
//
// Return Value:
// The new, empty, block
//
// Remarks:
// Before calling CreateBlock again, you need to call either
// SetBlockLimits or CancelBlock.
[ ... ]
HRESULT CreateBlock( [in]IBlockMarkupFunctionObject *bmfo,
[out,retval]IBlock **out );
You can see that the comment is broken up into sections with words, like
"Description:", but that isn't really necessary. While it's
pretty much necessary to do a proper job of commenting a method, it's really not
needed when documenting, say, an enumeration constant or a member
variable. The introductory words are, of course, under your control.
In the case of the "Description:" section, the comment author chose to
start the text on the same line as the introductory word. Elsewhere the
author chose to start a new line. That's fine, DocJet can adjust.
DocJet will automatically hyperlink the output. That is, when the
"Remarks" section is processed, the words "SetBlockLimits"
and "CancelBlock" will become hyperlinks. This hyperlinking
mechanism is quite sophisticated - if, for instance, we were implementing a
class that inherited from a class that implemented an interface named "CancelBlock",
that would still be picked up. Similarly, if "CancelBlock" was a
function in a namespace visible from the current object through a "using
namespace" statement, it would also be resolved.
The comment showed here is pretty basic in terms of its formatting
requirements. If you need something more, like preformatted blocks for
code examples, numbered lists, etc., they can be done as well. Pretty much
anything that a human can figure out how to format, DocJet can figure out how to
format.
Documenting the Obvious
What do we mean by "fully documented?" On the surface, we
might say that a system is fully documented if every published interface has a
comment associated with it that fully describes the interface. That turns
out not to be a very good definition on a couple of fronts. One of them is
rather surprising: it's not necessary to comment each and every public
interface.
Take a look at these two constructors:
void CFoo::CFoo()
// Default constructor
{...}
void CBar::CBar()
{...}
Would you say that CFoo's constructor is documented and CBar's
is not? CFoo does have a comment in front of it, but the
comment doesn't say anything that isn't immediately obvious from the
declaration. For all practical purposes, CFoo and CBar are
both equally well commented and the author of CFoo wasted effort in
creating the comment.
DocJet understands the code it's documenting a great deal better than your
average documentation tool. As a result, one of the things it's able to do is
supply comments for obvious cases like what we have above. If you submit that code to DocJet, it would fill in the blank on CBar::CBar,
producing documentation that is essentially the same as that for the commented CFoo.
Let's increase our sophistication a bit and move on to the
copy constructor:
CFoo::CFoo( const CFoo &c )
{...}
Suppose you were a programmer on a documentation binge and came across
that dude. In the absence of DocJet's automatic commenting, almost all
programmers would either type in "// Copy constructor" or cut &
paste the comment from another copy constructor into this spot.
Programmers know a downhill road when they see one.
However, if you were commenting along and ran across this and you knew that a
reasonable default will be provided for you, you could either (1) skip the
comment altogether, or (2) provide more detail. For instance, in DocJet,
if you supplied:
// This makes a deep copy of c.
CFoo::CFoo( const CFoo &c )
{...}
Your comment, regarding the deep vs. shallow copy, would become the
"Remarks" in the output and the default copy constructor brief
description would be used as well. To put it another way, writing that,
above, would be as good as writing this, in NDoc:
// <description>This creates a new instance of the object.</description>
// <remarks>This makes a deep copy of c.</remarks>
CFoo::CFoo( const CFoo &c )
{...}
What DocJet is doing here goes beyond code. DocJet's goal is to
provide an environment where the easiest thing for the programmer to do is also the
best thing a programmer can do. When faced with the constructor, the
programmer is asked to think, "Is there anything that is special about this
particular copy constructor?" If so, they can supply a comment that
specifically addresses that. If there really isn't anything special about
the constructor, fine, move on to another object
where there is something important to say.
The Perils of Commenting by Cut&Paste
Now let's
take it up another notch into the world of inherited methods:
interface IFoo {
// <extensive comment>
void frob();
};
class CFoo implements IFoo {
void frob();
};
DocJet employs the notion of inherited comments as well as the automatic
comments we discussed before. In this case, any comment you put in front
of CFoo::frob would override and complement IFoo::frob in much the
same way as we discussed before for DocJet's notion of automatic
commenting. For just about any reasonable case, the root method defines
the purpose and interface of a method. That is, in IFoo::frob, you
would talk about what the inputs are, what the effects are, and what the output
is. In CFoo::frob, all that would continue to be the same; all you
have to add there is any comments on how the class implements the
method. In most cases, there's no need to put any comment at all on CFoo's
frob method, because, in most cases, the reader of the documentation really
doesn't care how CFoo implements frob.
Now that we have talked about the advantages of inherited documentation,
let's talk about what happens in its absence.
In that event, given the mandate to "document" all the code, how would
a programmer react to seeing this bit:
void CFoo::frob();
{
...
In most cases, a programmer will "document" the above code by
cutting&pasting the extensive comment from IFoo. That certainly
works for the first go at documentation, but what happens later when someone
updates the interface to IFoo::frob? Only the most determined
optimist would expect that the comment for CFoo::frob will get updated to
reflect the change.
Summary
Probably the most crucial thing you have to understand when selecting a
documentation tool is this: no matter how good the tool is, it won't produce
anything useful if the programmers don't write good comments. Motivating a
programmer to write a good comment takes three things. First, you have to make
it as simple as possible to write comments. Second, you have to give the
writer confidence that their comments will be part of a high-quality document
that people will actually read.
In this article, we have discussed how you make DocJet makes it easy to
write comments. But comments are not the whole of a good document, you also
need organizational and supporting documents to tie the whole thing together.