April 8, 2015 by Daniel P. Clark

Documenting Your Code

I’ve been hearing a majority of developers saying things like “You’re code should be easy enough to understand that you don’t need to document it.” and “Comments are lies waiting to happen”.  I was okay with this and after hearing this for a while I eventually stopped writing code comments.

I watched a conference talk recently on “Message Oriented Programming” where Brian basically came to a conclusion of a “protocol specification”.  He was showing how when you define a protocol you are setting a standard of what goes in and what goes out.  For a protocol it’s very important to specify types and usages.  This got me thinking.

This past weekend I took part in an un-conference event called “Retro Ruby“.  I spoke to a gentleman named Mark who was adamant about language quality and documentation.  He said he wouldn’t even consider gems/libraries that weren’t documented.  This also got me thinking.

From the band of people who claim that code should read as it’s own documentation, I’ve also heard that the test suite should be the documentation on how to use it.  For my gem, that I’m most proud of, I’ve heavily tested it and refactored it quite a bit so it is “complete” in this sense.

Before I went to the un-conference this past weekend I went ahead and wrote inline YARD documentation for my gem PolyBelongsTo.  I didn’t do it because I felt I had to; it was more like – I can’t think of anything new this needs so I might as well do something just for the heck of it.  To my surprise adding documentation, and a badge for it, has increased the gem’s popularity.  It is picking up star votes, slowly but surely, while the other gems remain stagnant.

All this leads me to believe that not documenting gems is more of a fad where pride is taken merely in the code clarity itself.  If one is not hard headed against documentation then it might be wise to consider others who are of the mind, and/or need, to have documentation available for something they’ll trust and use.  Code doesn’t always reveal all the possible outcomes.  The documentation should clarify what types will be returned, and what are expected as input.  This shows intent and can be used for proof in debugging as the “protocol standard”.  I say ‘protocol’ because it represents something that’s, in a figure of speech, “set in stone”.  Changes to specification should come in stages with advanced documentation notices, depreciation warnings, and semantic versioning to avoid breaking changes in minor versions.  This will establish the highest trust between you, the author of the gem, and the end users.

Why YARD docs?  Because I like the minimalist approach whenever I have the opportunity.  YARD docs, from what I’ve seen, take the least amount of learning to get done.  And you can just specify input required and output expected if you’re feeling lazy.  It’s simple to learn, do, and test.

YARD doc

Unlike Python where you write the inline documentation just inside methods and classes, in Ruby you write it preceding methods and classes.  The basics come down to a commented line (or as many as you’d like) describing what the method/class/module/constant does or is responsible for.  If you have parameters that can be passed then the next line is where you put the @param descriptor along with the internal variable name of that param and type.  And the last line before the method/class/module/constant is the output expected with @return .

# Converts the object into textual markup given a specific format.
#
# @param the_param_name [Symbol] the format type, `:text` or `:html`
# @return [String] the object converted into the expected format.
def to_format(the_param_name = :html)
  # format the object
end

And that’s pretty much it. You can run ‘gem install yard‘ to test the coverage of your project by simply typing the command yard in the project folder.  It will generate a doc/ folder with all the documentation in it and show you how many of each type Modules/Classes/Constants/Methods is, or is not, documented.  Next you will need to add this to your .gitignore file as you don’t need the generated content published online as the tools online and elsewhere will generate documentation themselves.

/doc
.yardoc

Now you may want to look up a few things like different types that can be returned such as an Array with Objects and/or nil.

# @return [Array<Object, nil>]

True or false.

# @return [true, false]

Or maybe something more complex.  The general documentation is at github.com/lsegal/yard/wiki/GettingStarted  But I highly recommend looking at the Tags documentation at rubydoc.info/gems/yard/file/docs/Tags.md

Once you’ve got your methods and such documented and uploaded you can get a badge rating for your documentation with inch-ci.org.  And you can have your online documentation generated by submitting your github repo at rubydoc.info via the “Add Project” button at the top right hand side.

Summary

Some documentation is better than none; if for no other reason than to be thinking about others needs and having transparency.  Also it’s a great way to raise awareness, popularity, and trust.  You don’t have to learn a lot to do it, and you don’t have to write a lot if you don’t want to.  There may be times when you should write a lot; any place where it will save people time and effort I suggest doing so.  YARD doc style isn’t limited to the basics, I believe it supports the full RDoc syntax as well (and some extras).  So style it out as much as you’d like.  In a sense it is a public presentation representing your project.

One thing I have been pondering… since we’re not supposed to test private methods, what about documenting them?  That I don’t have an answer on but it’s worth thinking over.  I feel that Zach would; after watching his talk “A Documentation Talk by: Zach Holman“.  I think I may be inclined to document them for any private methods that “co-workers” may end up using as well; to help prevent them from thinking it should be changed to fit what they think it should do.  I’m open for discussion on it.

One great point from the “Message Oriented Programming” talk, I linked to earlier, is that language itself is as a protocol.  Language has both standards and meanings.  Without the protocol, or better stated “specification”, meaning would be diluted away and language would become unusable/nonsense.  People get confused enough in spoken, or written, language if the context is misunderstood; and it’s the same for programming.  So I urge you to be open in considering documenting your code.

Please feel free to comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!

God Bless!
-Daniel P. Clark

Image by Scott Akerman via the Creative Commons Attribution 2.0 Generic License.

#doc#documentation#gem#github#ruby#yard

Comments

  1. Bala Paranj
    April 8, 2015 - 5:09 pm

    This kind of documentation is best done with unit tests. It will be executable and upto date.

    • Daniel P. Clark
      April 8, 2015 - 5:37 pm

      Hey Bala, what is your reasoning for this conclusion? If you only document unit tests then only people who look at the unit tests will see it. YARD and RDoc do not generate documentation from tests.

      • Bala Paranj
        April 8, 2015 - 8:18 pm

        The unit tests can express all the different input and output that a
        method can handle and express the behavior. The documentation should
        capture what the unit tests cannot express. That is the ‘Why?’, these
        are the design decisions that were made by the developers. Even you
        might forget why you made a certain trade-off in your code. Here is a
        good documentation example from ActiveRecord:

        # We want to generate the methods via module_eval rather than
        # define_method, because define_method is slower on dispatch.
        # Evaluating many similar methods may use more memory as the instruction
        # sequences are duplicated and cached (in MRI). define_method may
        # be slower on dispatch, but if you’re careful about the closure
        # created, then define_method will consume much less memory.
        #
        # But sometimes the database might return columns with
        # characters that are not allowed in normal method names (like
        # ‘my_column(omg)’. So to work around this we first define with
        # the __temp__ identifier, and then use alias method to rename
        # it to what we want.
        #
        # We are also defining a constant to hold the frozen string of
        # the attribute name. Using a constant means that we do not have
        # to allocate an object on each call to the attribute method.
        # Making it frozen means that it doesn’t get duped when used to
        # key the @attributes_cache in read_attribute.
        def method_body(method_name, const_name)

        This method is defined in ActiveRecord::AttributeMethods::Read. By the way, this is a private method. I still think if it was a public method, you should capture the
        design decisions and not protocol specifications in the documentation. Too much documentation is as bad as no documentation. So there is no need to repeat what has been documented in the unit tests.

        • Daniel P. Clark
          April 8, 2015 - 10:50 pm

          Thanks for the explanation. This shows an important use case for having comments.

Leave a Reply

Your email address will not be published / Required fields are marked *