Arnt Gulbrandsen
About meAbout this blog
2009-11-04

Writing (mostly) to write

Most people who talk about literate programming seem to care mostly about the output. The written documentation. I care more about the actual writing, and the result of the writing process.

When you write something, when you explain it, you gain a deeper insight yourself. That's a cliché, to be sure, but it can be leveraged to write better code. There are two parts to it: Helping yourself and having your tool help you.

Helping yourself

Helping yourself is about writing the documentation in such a manner that you learn about the code, and e.g. catch thinkoes with minimal effort.

The key to do that is to write the documentation that helps clarify your thoughts and reveal obvious mistakes to yourself, and skip other documentation. (You can write more, but doing so can interrupt your programming flow. Or it can help.)

An example in udoc syntax:

/*! As Output::addClass(). \a text is output as-is, and the name of \a c is remembered for later mention in the See Also section.

*/

void ManPage::addClass( const String & text, Class * c )
{
....

The best way to write this is to start with the signature, then the first sentence of the documentation (As Output::addClass()), then the rest of the documentation, then the implementation.

You write the signature the way you're used to. Next, you describe the function in a single sentence. This sentence often mentions the function arguments, but not always. The one above doesn't.

Then comes elaboration. Look at your sentence, consider what it misses, and write a sentence (or more) about each missing aspect. The example above misses the specifics of ManPage, ie. it doesn't explain the difference between how Output handles addClass() and how the ManPage output class does it. The second sentence describes that difference.

When you've done this, you should have mentioned all the arguments and special cases. If you haven't, you've probably forgotten to mention something, or you haven't thought enough about that thing, or the function signature is wrong, or the basic design of the function is. Either way, it's time to lean back and think a bit.

The function above doesn't have any special cases. It might have had, e.g. c being a null pointer or text being empty, or text not meeting the syntax demands of the output format. But as it happens, it's like Output::addClass() in all these respects. This happens quite often when you document your code. As you type function does this, except that if foo is null, it instead does that you learn to dislike typing such distasteful prose. Put differently, the act of writing the documentation points out to you which function interfaces should be simplified, and you do it, improving your code.

Don't skimp here. Half the point of writing this stuff is to save time while implementing. You're explaining your thoughts and intentions, and the act of explaining clears the mind. With practice, writing the documentation only takes thirty seconds in the typical case and a minute on average (and much more in a few cases). You easily save a minute by having clearer and better ideas when you start implementing.

At some point I'd better write another entry on this, with lots of fine examples, and some not-so-fine ones. And another entry on how to write the same thing for classes, variables, enum values. Not today.

Getting help from a tool

In udoc, I consider the error messages to be the most important output, and why there are many more error messages than directives in udoc. Its list of error messages is half of how I think a tool can help. There's more, for example udoc doesn't do as much as it could with respect to enums.

Udoc doesn't produce output without input. This is a feature, and it's meant to be helpul: It's easy to produce e.g. a list of function signatures, but I do not think that's appropriate for a documentation tool. A documentation tool should help produce documentation. I'd rather have a sensible error message about each undocumented function in the file I work on than a manpage/webpage containing nothing but function signatures.

Udoc orders its error messages cleverly. It tries to report errors related to the most recently changed file first, and not report too many errors.

The ordering is extremely important to me personally. If I get an error message for the file I'm editing in a second, my attention will still be on that file. If I have to wait, my attention may have drifted off to my mail reader.

The idea behind reporting only a few errors is... shall we say motivation? Seeing two thousand error messages would be so depressing. The tool should try to report the error messages that are relevant to the developer's focus of attention. Reporting other errors isn't helpful. Which errors are relevant? A difficult question, but heuristics help.

If you get the impression that I think udoc is the only good tool for this, well, that's true. I do think so. I wish there were more.