brandon.hornseth

On Documentation

tech

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:

  • A developer would format a comment incorrectly and the YUIDoc parser would crash while building the documentation
  • Because it was difficult to determine which file caused the problem, we ended up spending significant time fixing documentation problems
  • In an attempt to keep projects on track, we changed the builds to ignore documentation failures
  • Because the documentation step now required someone to actively monitor for and correct problems, the published documentation fell out of date and eventually became useless

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:

Thanks for reading!

If you have any comments or feedback on this article, I’d love to hear from you. The best way to reach me is on Twitter.