Friday, September 7, 2007

Thoughts on documentation: Conventions

While working on the Rails Documentation Project, it's been interesting to see the veritable array of documentation styles and conventions present in a single (albeit, open-source and slightly heterogeneous) code base. Sometimes the options hash is documented fully, other times it's not. Sometimes they document it once at the head of the class, sometimes it's for every method. Sometimes they put one sentence that is essentially a humanized method name (e.g., check_box_tag = "Makes a check box tag"), sometimes they include an entire essay about the method. Of course, it isn't unique to Rails nor open source, but Rails is the first project where I've combed through the documentation from front to back (and, of course, side to side, because you know how I work it).

But what about conventions? One of the things I've learned from those who do "technical writing" as a career is that they typically have quite rigid standards, styles, and conventions to follow when writing. Whether it's a style guide that indicates which case of a verb to use in every instance or a specification that dictates the structure of every piece of documentation, the "real world" of technical documentation isn't as free wheeling as we like to treat it, and this cavalier treatment of documentation is one reason that Rails (and, to an extent, Ruby) isn't taken seriously by a large portion of "corporate" entities. First question anyone will ask when considering using a technology is, obviously, "How do you learn how to use it?" Obvious answer: the documentation (less obvious, blogs, mailing list, talking, training, and so on, but the most obvious and useful answer is the documentation). If your documentation looks like a hodge podge of documents that have been scraped from a blog, then how can you expect anyone to take it seriously? Compare that with the documentation for the .NET framework, Python, or a lot of larger Java projects. They have conventions, and I think we should take a careful look at what they do with them.

First, they enforce documentation for every piece of code. Nothing goes in the framework or project that isn't documented. Granted, some things don't need documentation (thanks :nodoc:!) because they don't need to be used by anyone but the framework, but anything that is exposed and usable, should be documented. I'm using the term documented in a very specific meaning here: not the loose context that people consider "documented." Documented is not humanizing the method name or stating the obvious. Documenting is connecting what a functional unit of software does with how to make it do it. It is drawing the schematic for the builder. OK, I'm out of metaphors, but you get the idea: you're showing something hidden.

Now, this doesn't mean you need to pad your documentation with a lot of narrative. To the contrary, it's usually better if you don't. For example, my check_box_tag example earlier was a little unfair. About the best you can do with narrative is something like, "Generates a checkbox tag (<input type="checkbox">) in a form" (and even then, that's a little more than needs to be said in most cases...). Typically you would reduce your narrative and explain in depth with examples, where you can reveal the underlying functionality in practice. For example, you could do...


Generates a checkbox tag (<input type="checkbox">) in a form. Your options are :disabled, which if set to true, the user will not be able to use this input, while any other key creates standard HTML options for the tag.

Calling check_box_tag 'accept' will generate a checkbox tag that will have the id of accept, and the value of 1: <input id="accept" name="accept" type="checkbox" value="1" />.

[And so on...]



OR, you could get a lot more bang for your word and do something like this...


Creates a check box form input tag.

Options
- :disabled - If set to true, the user will not be able to use this input.
- Any other key creates standard HTML options for the tag.

Examples
check_box_tag 'accept'
# =>

check_box_tag 'rock', 'rock music'
# =>

check_box_tag 'receive_email', 'yes', true
# =>

check_box_tag 'tos', 'yes', false, :class => 'accept_tos'
# =>

check_box_tag 'eula', 'accepted', false, :disabled => true
# =>


Now the user can evaluate the method's functionality without a lot of verbosity, and see what the method does in real usage. This example-driven documentation style has been criticized, but I don't think you can argue with it.

Second, by enforcing standards, you gain usability. It's easy to flip to a piece of documentation and know how to find exactly what you're looking for. This is something that was a big concern for us when working on the Rails documentation because as the documentation stood before, many things could be placed in a disjointed manner (even in the same file or class). One of the best examples of documentation I found was Assaf Arkin's assert_select module. We were doing something very similar to what he was doing before, but we definitely took a few pages from his book and beefed up our standards. The options explanations were in the same place and formatted the same, the examples were always last, and every method or class had an introductory blurb with a general overview of what it did. Following a single convention all the way through makes it incredibly easy to find exactly what you want.

Third, by using a solid convention, it makes it easier to write and maintain. I think it's funny that Rails embraces conventions so much inside the framework that they haven't taken the same stance with its documentation. Having a simple set of conventions to follow would make the documentation so much easier to update. Change or add an option? Fix it in the options sections. Change a parameter? Change the parameters list. Totally change the way a method behaves...well, at least you'd have a template to start over with. :)

So, what sort of conventions do I use? In dcov, I check for a laundry list of obvious things in the standard quality analyzer:


  • Everything must have examples

  • All options hashes must be documented somehow.

  • All parameters must be documented in some form.

  • All default values must be explained.



These are obvious things, though, right? To really have a set of conventions, you need to dig deeper and get more specific. I'm a fan of tighter conventions rather than a loose style manual when it comes to this sort of thing, so here's the setup that I use in RDoc:


Introductory material goes here, where I explain the jist of the method and mention a few key parameters if I need to.

==== Parameters
* parameter - Explains all parameters if the list can't be easily explained in the introduction.

==== Options
* option - Explains all available options, possible values, and default values.

==== Examples
# A few examples, documented in comments if possible
puts "Howdy!"


I think this is a fair start for most Ruby code, but I'd like your input. Is it too verbose for most cases? Should it be rearranged or compressed?

1 comment:

Ben said...

Good thoughts - I like the proposed standard a great deal.

Here's a question, though: how should generated code be documented? There's a lot of metaprogramming magic in Rails, and all of that gives rise to a number of methods that don't show explicitly up in the code.