On Documentation

Early in my career, I was passionate about code documentation. Fresh out of college and adrift in a giant codebase that was often difficult to get my head around, I went looking for some structure to make modules and methods more digestible.

For background, this was all long before Node.js existed. CommonJS was barely an idea on paper, and we were one of a small number of companies quietly using JavaScript on the server. Because our stack was custom, no turnkey tools existed to generate code documenation a la PerlDoc.

After some R&D, we came up with a crude but promising solution with YUIDoc. Progress stalled when we ran into a seemingly endless pile of quirks that played out something like this:

Rather than invest time fixing all of the issues, the team reverted to what we'd always done: read the code to figure out what it's doing.

In 2010, we adopted Ruby on Rails for new development. I thought this meant another shot at building robust documentation for our code, but Rails was at 3.0.0.beta2 at the time and nearing the end of the Rails+Merb merge. Much of the community was moving from Ruby 1.8.7 (or REE in our case) to 1.9.2. The whole landscape was changing rapidly. Learning our way around a new stack was enough of a challenge that niceties like generated documentation were pushed to the bottom of the ToDo list.

Recently, I've been inspired by Gary Bernhardt's Destroy All Software series to take a look at my workflows in search of efficiencies, and I decided to take another look at what the Ruby ecosystem has to offer for generating and viewing code documentation.

Oh look, toolsets that actually work

Ruby ships with a command line tool called ri (short for Ruby Interactive) which can search and display the built-in documentation for modules and methods. If you've visited ruby-doc.org, the format will be familiar to you. Code commented in a format that RDoc understands can be extracted to files that ri uses to display documentation similar to a man page.

For the longest time, my rubygems configuration specifically disabled generating this documentation via these directives in ~/.gemrc:

----
install: --no-rdoc --no-ri
update: --no-rdoc --no-ri

When I decided in 2017 to improve my efficiency by learning new tools, I removed those lines, but I still needed to generate the docs for everything I'd previously installed. That lead me to the RVM doc on docs which includes a one-liner to install the documentaiton for all currently installed rubies:

~$ rvm all do rvm docs generate

Once the docs are generated, usage follows the typical method prefix for Class-methods (::) and instance methods (#). Instead of hitting up ruby-doc.org to read up on the any? method in Enumerable, we can see it right in our shell:

~$ ri Enumerable#any?

ri Documentation for Enumerable any

This works for entire modules or classes as well. For instance, if you want to look at the documentation for ActionMailer::Base

~$ ri ActionMailer::Base

This, of course, isn't much faster than typing ruby enumerable any? into Google, but it saves a few seconds. After a few months of use, I find it feels like less of a context-switch to background my editor and view the documentation there than hopping over to Chrome and back to my terminal.

Keep It Personal

The real power, of course, comes from being able to explore and better understand parts of your own codebase that may be unfamiliar. As Zach Holman said, the most important code isn't code. It's undeniably helpful to be able to see a snapshot of all the methods in a Ruby class without having to open up the class in another editor and skim all the method definitions.

Thinking about documentation has forced me to question code I wouldn't normally question. I'm not at a point where I document every class and method, but I have been making an effort to add substantive comments explaining classes and method behaviors for our core code. At times in the course of that I'll find something difficult to explain. If you can't explain in English what something does, what chance does a developer unfamiliar with the code have of understanding the code itself? That's become a warning flag for code that's a good candidate for splitting or refactoring.

I was also surprised how small methods would sometimes elicit entire paragraphs explaining how they came to be, known caveats, links to other related methods, etc. I came to realize in-code documentation needs to tell a story, just like good commit messages. Future you will thank past you for the effort.

As far as I know, I'm the only one on my team that uses ri with any frequency, and none of our pojects publsh rdoc, but everyone benefits from having those explanations right there in the code.

More reading:

λ