Day 6 – The Future Of POD6

by Kay Rhodes

Some people believe that “code should be self documenting”. They believe that we don’t need inline docs because you can just look at the code and see what it’s doing. The reality is that everyone’s brain works differently. Everyone processes new information differently.

My brain’s extra divergent. I have a working memory that approaches that of your average goldfish. I’m rediscovering the little plastic castle, every time around the bowl. As a result, I’ve spent a lot of time thinking about how to convey knowledge to future me. Inline documentation of our code is one of those ways.

When we write internal docs there are three main aspects to it: what we choose to write, how we organize it, and how we encode it.

Tools Matter

Here in Rakuland we use Pod6 for our inline docs. I don’t think many people really think about it. Folks seem to use it because it’s there, and because it’s what the people before them have used. “That’s what we’ve always done” doesn’t mean the thing you’ve always done is the best it could be. It doesn’t mean that it’s what you should be doing. It might be, but that’s not a given.

To be explicit, I have a lot of respect for Pod6, its predecessor Pod, and the folks that worked on both of them. If it wasn’t for the amazing Pod docs written by the developers who came before me, I might not have the career I do. But, Pod(6) has never made me happy. In my travels beyond the shores of Perl and Raku I’ve learned about a number of other ways of documenting code, and what those things can do for us.

I’m hoping that by the end of this post, some of you will be inspired to dig into Pod6 and make it do more for us. I’m also hoping that some of you will be inspired to write an alternative.

What we choose to write

Over in Ruby land we have YARD. YARD isn’t the greatest code documentation tool, but there’s a lot it does well. It’s also the one I’m most familiar with.

YARD, like Pod6 never explicitly says “you should write this stuff here”. Unlike Pod6, it implicitly sets expectations about what should be written. It does this in two ways. First it provides a simple mechanism for encoding different types of information whose usage is self-evident. Second, it provides examples that use those mechanisms to actually document code.

If we provide examples of best practices for documenting code we set expectations. We also provide a helpful references for new users who haven’t memorized the syntax yet. If we do that when we introduce the documentation tool people have a pattern to follow from the start. Pod6’s docs don’t really do that. While there are some examples of Pod6 next to code none of them actually show how to document that code. Instead, they show how a given mechanism works.

If we look at YARD’s features page the first code example we see is this:

# Reverses the contents of a String or IO object.
#
# @param [String, #read] contents the contents to reverse
# @return [String] the contents reversed lexically
def reverse(contents)
  contents = contents.read if respond_to? :read
  contents.reverse
end

This doesn’t begin to cover the full capabilities of YARD. What it does do is set early expectations, both of what it’s like to use YARD, and how they expect you to use it. This example implicitly conveys what YARD’s creators expect its users to include:

  • a short description of what the function does
  • a list of its parameters, their types and some idea of what those params are expected to contain.
  • the same information about what the method returns.

I’ve written thousands of lines of Raku at this point, and I have no idea what is expected when documenting my methods. With no clear guidance, we each go off and do things our own way. Even if we manage to convince people that inline docs are worthwhile, there’s nothing guiding what they put in them. As a result, there’s no consistency, and we can’t have any expectation about what kind of support those docs will provide to the people who need them.

Flexibility is great, but guidance is great too. I honestly believe that one of the single best things we could do, to help people considering, and learning Raku is to be consistent about what we document about our code. We need a standard. It doesn’t have to be an “official” standard approved by the core team. But it needs to be something that every developer has a passing familiarity with. We need to provide clear guidance for people learning Pod6, but we also need to follow that guidance when we write our code.

A good standard for documenting code is something can be understood without ever reading the docs for the tool. If you’re a new Ruby dev, and you see a handful of examples like the one above, you’ll know what’s expected of you when you add functions. You’ll document what they take in, what they put out, and give them a short description.

So, what does Raku consider best practices for documenting our code, and what can we do to help make sure that every developer understands them?

How we organize our docs

How do we organize our docs? Do we document a class at the start of the file, or the end? When do choose to document the inputs and outputs of a function, do those come before or after the description? What about example usage? Where does that go? When I document a function, should I do that directly above the function, or should I put all the documentation at the end in one big section?

I don’t know.

Raku seems to be following in Perl’s footsteps; “There’s more than one way to do it.” I have some opinions about where things should go, and how we should order them. You do to. You write your code according to yours. I write my code according to mine.

This is easy for us, but it’s terrible for the people we want to use our code. First, they can’t have any expectations about what will be documented. Now, they can’t have any expectations about where they’ll find it.

A consistent organizational structure enables readers to rapidly find the information they need. I may not even realize you have docs, if I’m expecting them inline, but you’ve put them all at the bottom. When we don’t organize the things we do write consistently, readers have to spend time reading all of it to find what they need.

YARD’s examples make it clear that in Ruby we organize a method’s docs by first providing the description, then the inputs, then the outputs. But, what about usage examples? Where do they go? Honestly, I don’t know. I think shouldgo after documenting the return value. I’ve seen unofficial docs that show examples after the parameters and beforethe return. That seems weird to me. The end result is that without clear guidance from the creators, I put them in one place, and other people put them elsewhere.

When we provide guidance – be it implicit, or explicit – we need to be sure that it covers all the things that are expected. This includes the things that don’t come up very often. Providing usage examples is pretty uncommon. We should still know exactly where to put it.

How we encode things

When it comes to encoding things, Pod6 is a lot more like Markdown than a code documentation tool. It can help you format your text in useful ways, but it doesn’t really provide us any tools to encode information about our code.

Because we have no way to specifically encode parameters, we have no way to extract parameters. This means we can’t generate HTML docs that consistently include notes about parameters, and when they do we can’t guarantee where the notes about each one will appear. This is the organizational problem all over again. It’s harder to find things if you don’t know where they’ll be and they’re not consistently there.

In the prior section I said that I wasn’t sure where the “right” place to document example usage was in YARD docs. But, the fact that it’s a thing with a specific encoding mechanism provides a huge value. The HTML docs I generate can always have it organized according to the standard. Even if I’m completely ignorant of what that standard is. Even if I’m inconsistent in how I do it in my code. The generated HTML docs can consistently create produce a standard organizational structure. The tool knows what its working with, so it can put it in the right place.

Because Pod6 doesn’t really have a way to encode elements of our code, we can’t generate a consistent output. We can’t help people find the information we need.

More importantly, we can’t extract any specific type of information, so we can’t write tools that do useful things in it.

Imagine you’re working in the REPL, figuring out how something works. You start to call a method but realize you don’t remember what order the parameters go in, or what it returns. Because we have no way of specifically encoding a method’s parameters or return value we can’t extract them. You have to leave the REPL, go find the file that contains it, and then the method in that file. If it’s coming from a dependency you may have to track that library down on GitHub and start hunting around.

It doesn’t have to be that way. In some languages it isn’t. There are languages with documentation tools that leverage their structured encoding to expose that information in the REPL. In those languages you can ask the system for a functions docs within the REPL. You can also ask for the specific pieces that might be encoded in it. You can have it tell you just the return value of the foo method.

If we want the benefits that come from having specific ways of recording different types of information then one of three things has to happen.

Extend Pod6 itself

Obviously, we could extend Pod6 itself. This would be great for the community, but it might take years because of conflicting beliefs about what’s important, and how we should do it.

Build something that supports a superset of Pod6

This is what YARD did. YARD took the standard Ruby documentation tool (RDoc), and made a new tool that supported a superset of its functionality. It gives you all of the old stuff, plus the additional features they wanted.

This was a pretty great choice. It means that someone familiar with YARD finds codebases with RDoc totally readable, and vice versa. It also means that those old codebases can have their docs regenerated using YARD’s tooling.

One of the biggest benefits to this approach is that it can be easy to get started. If you’re happy with the Pod6 codebase, you could just fork it, add a single feature. Do that and you’ve improved something for yourself. One feature is not really worth releasing as a new codebase, but this approach makes it easy to iterate towards a goal. It gives you something functional that can be used, and improved as you have time.

Write something else

The last option is to make a completely separate alternative.

Twenty years ago I would probably think “Yeah, right. I’ll ‘just’ make my own Pod6 alternative.” However, a while back I was writing a fair bit of Chicken Scheme, and I wanted to be able to write structured inline docs using Markdown. I wanted to be able to provide docs with a description, parameters, what it returns, code examples, and arbitrary notes. I also wanted all of those things to be exposed when I was working in the REPL. So, I started writing.

It took me about 400 lines of new code to have a tool that did all of that. 1000 in you include a couple files i copied from another project of mine. That’s not because I’m some amazingly efficient Scheme developer. I’m really not. I love scheme, but I’m not that great at it.

It was because I did a lot of creative corner cutting. The following example is not something great. It’s just an example to show how much you can do when you combine a tiny bit of code with some creative thinking.

(doc-fun "greet"
	  "## Public: greet [name]
	Generates a greeting string.

	### Parameters:
	* name - (optional) the name of the person to greet

	### Returns:
	a string

	### Examples:
	    (greet "Bob")

	### Notes:
	This is *obviously* a contrived example.")

Because I delimited each “type” of information with a Markdown header, all I had to do to extract a section was to look for a line starting with hashtags. Then I’d read everything up to the next one or the end. Markdown’s intended to be human readable, so I don’t need to do anything fancy when I display it in the REPL. No markdown parser required. While I love the details that YARD gives me about parameters I don’t actually need code to specifically encode them to improve my quality of life. Instead, I just needed to set expectations for how we document things with this tool.

Parameters appear in a list. They start with the parameter name followed by a hypen a parenthesized note if its optional, and a description. Future versions could break each list item into its component parts.

I didn’t even write something to convert it to HTML. I didn’t need to. There are lots of Markdown to HTML converters out there. Inserting an HTML snippet into a pretty template is trivial. My tool just generates a folder structure of Markdown files that I can run through other people’s tools.

Is it cheating? Maybe. Does it work? Yup. Could it be better? Sure.

I love what my tool can do for me. I love how it increased my productivity when writing Scheme. I can iterate on it and give future versions more capabilities.

Writing a tool that matches your thinking, and supports your desires can be done in such a small amount of code. Knowing that, I’d like you to take a moment and consider what would your ideal documentation tool look like? Is it something that others might want to use?

Summary

Pod6 is a great starting point. It can do a lot, but I think we can do better. I think we can do better in how we introduce new developers to documenting their Raku. I think we can do a better job of showing them what they should document, and how they should organize it. I think we can improve the features it offers developers.

I don’t care how we solve these problems. I just care that they get solved. I’d love to see Pod6 get new capabilities. I’d love to have an alternative to Pod6.

Mostly, I’d love to see people start valuing inline documentation more. I’d love to open up your codebase and find the help I need, where I expect it. I don’t want to have to figure out your quirky way of organizing things.

We few Raku devs have the world’s greatest text manipulation tool just waiting for us to use it. Let’s do that. Let’s make our documentation tools as bad-ass as the code they document.

3 thoughts on “Day 6 – The Future Of POD6

  1. Instead of documenting/updating Type information for input/output parameters manually, why not just put them in the signature of your methods/functions?

    A good way to attach the „short why-sentences“ to a function is using the declarator blocks

    https://docs.raku.org/type/Mu#method_WHY

    Why not also attach the examples usage at the tail, maybe in a way such that EVAL can run them?

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.