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.
After some R&D, we came up with a crude but promising solution withYUIDoc. 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.
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
riuses to display documentation similar to a man page.
For the longest time, my rubygems configuration specifically disabled generating this documentation via these directives in
---- 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 upruby-doc.org to read up on the
any? method in
Enumerable, we can see it right in our shell:
~$ ri Enumerable#any?
This works for entire modules or classes as well. For instance, if you want to look at the documentation for
~$ 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.
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
riwith any frequency, and none of our pojects publsh rdoc, but everyone benefits from having those explanations right there in the code.