Documenting Go Code with Gonotes

July 26, 2018

When writing code, an abundance of documentation is always welcome to guide future readers and contributors (which includes yourself). Documentation is so important in Go, that the language was designed with a standardized approach to writing good code comments that could be autogenerated into documentation (see the Go team’s official blog post on documentation).

There are amazing tools that expose the power of Go documentation, such as godoc. At the heart of godoc, is a simple package in the standard library called doc. The doc library provides the notion of notes that annotate code in a structured fashion. Originally, notes first appeared as a mechanism for documenting bugs: // BUG(r). Today, the notion of bug annotations are deprecated in the doc library in favor of a more general notation marking. I like to refer to these notes as gonotes. These notes take the form of a marker, a UID, and a body:

MARKER(uid): note body

The marker labels the category of comment. For example, you may have a comment related to describing a known bug, in which case the marker would be BUG. You could also have a marker for labeling a TODO item, where the marker would be TODO. In both cases, the UID could be a username responsible for following up on that issue. The note body contains any related details.

Here are a few examples of godoc notes from the Go standard library:

The godoc tool has some support for displaying notes. To show notes, provide the notes option to the command:

godoc -notes=TODO go/doc

The output of that command:

use 'godoc cmd/go/doc' for documentation on the go/doc command 

PACKAGE DOCUMENTATION

package doc
    import "go/doc"

    Package doc extracts source code documentation from a Go AST.

// YATTA YATTA YATTA

TODOS

   Recognize "Type.Method" as a name.

   There may be exported methods of non-exported types that can be called
   because of exported values (consts, vars, or function results) of that
   type. Could determine if that is the case and then show those methods in
   an appropriate section.

   fix this

Unfortunately, the godoc tool only displays notes for the current package. Viewing nested packages in one view is not possible (I think…). To allow a project space to be parsed, I wrote a small library called notes that recursively parses each Go package in a directory and returns all notes. Additionally, there is a CLI tool front end to the library that can be used to output JSON:

$ go get -u github.com/pokstad/gomate/notes/notes
$ notes -output json $GOPATH/src/github.com/pokstad/gomate
{"ASSET":[{"Tag":"ASSET","UID":"markdown.css","Body":"used for styling the HTML\n","Loc":{"AbsPath":"/Users/paulokstad/go/src/github.com/pokstad/gomate/cmd/gomate/main.go","Line":23,"Column":2,"RelPath":"/Users/paulokstad/go/src/github.com/pokstad/gomate/cmd/gomate/main.go","Filename":"main.go","Excerpt":"ASSET(markdown.css): used for styling the HTML\n"}}],"TODO":[{"Tag":"TODO","UID":"1","Body":"add more tests using golden files\n","Loc":{"AbsPath":"/Users/paulokstad/go/src/github.com/pokstad/gomate/html/getdoc_test.go","Line":13,"Column":1,"RelPath":"/Users/paulokstad/go/src/github.com/pokstad/gomate/html/getdoc_test.go","Filename":"getdoc_test.go","Excerpt":"TODO(1): add more tests using golden files\n"}}]}

Formatted in a pretty fashion, the JSON looks like this:

{
  "ASSET": [
    {
      "Tag": "ASSET",
      "UID": "markdown.css",
      "Body": "used for styling the HTML\n",
      "Loc": {
        "AbsPath": "/Users/paulokstad/go/src/github.com/pokstad/gomate/cmd/gomate/main.go",
        "Line": 23,
        "Column": 2,
        "RelPath": "/Users/paulokstad/go/src/github.com/pokstad/gomate/cmd/gomate/main.go",
        "Filename": "main.go",
        "Excerpt": "ASSET(markdown.css): used for styling the HTML\n"
      }
    }
  ],
  "TODO": [
    {
      "Tag": "TODO",
      "UID": "1",
      "Body": "add more tests using golden files\n",
      "Loc": {
        "AbsPath": "/Users/paulokstad/go/src/github.com/pokstad/gomate/html/getdoc_test.go",
        "Line": 13,
        "Column": 1,
        "RelPath": "/Users/paulokstad/go/src/github.com/pokstad/gomate/html/getdoc_test.go",
        "Filename": "getdoc_test.go",
        "Excerpt": "TODO(1): add more tests using golden files\n"
      }
    }
  ]
}

Try it out, let me know what you think.