Nov 27, 2020

Testable Documentation Spike #1: "It's Just Code"

This is the first spike for the Testable Documentation project.

I call this first spike the "code only" concept. I'm trying to combine code and documentation in a way that we can test and lint the code that we're using as an example. One way to do that is to just keep everything as code with the documentation as comments.

There are a number of code-only examples out there to draw inspiration from:

All of the samples above have something in common: they are code written as educational tools. They are not meant to be deployed but they are fully-functional and, in some cases, under test. The only thing they are missing are the comments that turn them into more of a document than a programming artifact.

If we added comments to these samples, keeping the code functional, we could do some kind of treatment to improve the readability. What comes immediately to mind is the annotated jQuery and Backbone source code. You can read through the code on the right and, as soon as you need a bit more information, the description is on the left.

Docco + Backbone

The tool to make this happen is Docco. The Docco docs themselves are generated from the Docco source code. The last 4 links are a little long in the tooth but, dated styling aside, I think they are still an effective learning tool.

The point here is to write code with comments that serve as the whole example, extra points if they can be compiled into something that looks nice.

Sample Code

First, we need some code examples to test, lint, and document. We don't need anything complex, just enough to make sure we know we're representing the real world.

For this sample, we'll pull in a library, make up some data, and use that library to do something. I'll use this as the code for all the spikes to keep things consistent. Code is here.

I wrote the above out in an editor and ran prettier. Then I wrote a simple test that would simply require the code above, making sure it ran properly. If you look close at the code above, you'll see that it caught something right away:

"expiresIn" should be a number of seconds or string representing a timespan    
7 | };
8 |
> 9 | jwt.sign(payload, "TOKEN_SECRET", {
> | ^
10 | expiresIn: this.tokenExpiresIn,
11 | });
12 |

I copy-pasted that block from a running module and accidentally left in the class reference. Turns out, I could benefit from a system that helps prevent dumb mistakes. Who knew?

Write the Docs

We have the tested, linted code sample, now it's time to write the documentation. In this case, we're writing it as in-line code comments that are Markdown-capable. I did not dig enough into Docco to find the exact Markdown flavor or specifics on how the comments are parsed beyond the library that's used (Marked). We'll just give it a shot and see what happens.

I made a copy of the sample code above and started commenting away. I give almost every line a comment to see how the documentation flow worked (see the code here).

Writing the documentation was not a terrible experience but the multi-line comments were not as natural as the single-line ones. I could definitely see this process interrupting the writing flow quite a bit if there needed to be a lot of explanation. I tried with the // at the beginning of each line but VS Code was not auto-adding that on new lines (probably a setting somewhere). I switched to doc-block style and that seemed to help a bit.

Building the HTML

I've got a well-documented block of code, now it's time to see what processing looks like.

I installed Docco as directed and ran it on the code written in the section above:

npm i -g docco
+ docco@0.8.0
updated 3 packages in 2.449s

❯ docco *.js
docco: sample-1-use-module.js -> docs/sample-1-use-module.html

That was easy! Without passing any options, we generated something that looked like the Backbone docs from above. You can see that here.

While this looked good for a first pass, I was writing the comments visualizing the code and documentation all being the in same column so I added --layout linear and tried again.

Docco in linear layout

That's a bit more like it but I'm not sure about the design details. This method of generation also came with 590 KB of fonts, images, and CSS. The final HTML generated from this process will be included or concentenated somehow with an existing site so the less included the better.

Docco allows for a --template flag that will accept a .jst template file, a format I'm not familiar with. Not really interested to dig too deep into a templating language that time has forgotten, I looked for and found the .jst file used in the "linear" style and stripped that down to the bare minimum. The command complained that I did not indicate a CSS sheet so I added a dummy value.

❯ docco --template docco.jst --css none *.js
docco: sample-1-use-module.js -> docs/sample-1-use-module.html

That was finally outputting something that could be included somewhere. You can see the output here. I was a bit worried that the build process for this would involve stripping or parsing HTML but, thankfully, it does not look like that will be necessary.

Trying it out

With our tested and linted JS getting parsed into somewhat clean HTML, I wanted to see what it would look like imported. I'm using Nunjucks templates processed with Eleventy for my blog so an include directive was all I needed.

Everything between the pointer fingers is the procesed HTML.

👇👇👇

First, install the jsonwebtoken package (npmjs.com):

$ npm install jsonwebtoken

Require it at the top of your module:

const jwt = require("jsonwebtoken");

Now, we export a function to do the heavy lifting.

module.exports = function makeToken() {

The session token payload includes claims typical of an OpenID Connect ID token.

  const payload = {
    aud: "AUDIENCE_ID",
    iss: "https://example.com/",
    sub: "SUBJECT_ID",
  };

This function will return a signed JSON Web Token - JWT - using the second parameter below as the signing key. This token will need that same value to check the token signature when validated. It will be obvious to some but the "TOKEN_SECRET" value below should be long, random, and never stored in the code.

Note that the jsonwebtoken library can accept plain English time representations.

  return jwt.sign(payload, "TOKEN_SECRET", {
    expiresIn: "1 day",
  });
};

And there you have it, a function that returns a signed token!

👆👆👆

Two problems I ran into:

Overall, not a terrible workflow. Eventually, I had a combination script to run Docco, prettier the output, then copy into the include directory for my blog all at once. Eleventy picked it up and processed the pages, and, viola, the new documentated code was displayed. Magic.

Analysis

This spike was definitely a success. I got something working in under a day's worth of work and seeing testable code go to styled output was great, regardless of whether it's the right solution or not.

Original criteria:

Here are a few additional thoughts on this system:

👍 Portable

I like that these examples could be produced into their own pages and served from GitHub pages or Netlify or another static file host. You could have one build process that creates include-able HTML and another that creates servable pages.

👎 Extra build step

We're generating HTML first, which is then included in the documentation. This extra build step adds complexity, both in terms of extra processing and things to go wrong but also a fairly opaque way of indicating your output. The HTML used above is stripped down to nearly nothing in the template file that was used but there is still plenty of HTML in variables that is not configurable.

👎 Forced cadence and order

The order of the comments and code is a limitation. You might find yourself structuring the code in order to make the documentation more clear, which does not feel like the right way to do things.

Or maybe it is if you buy into Literate Programming:

I believe that the time is ripe for significantly better documentation of programs, and that we can best achieve this by considering programs to be works of literature.

This type of documentation-first thinking feels better-suited to the source code itself rather than example code like what we're writing here.

👎 Old technology

The library I'm using here does the trick but it is quite old. Would we need to adopt it at some point? Would PRs be responded to? It's not abandoned entirely but it's worth considering.


So, that wraps up this spike! Stay tuned for the next one, which will explore including code directly into templates.

<Take Action!>

Discuss on Twitter › Suggest changes on GitHub ›

<Read More>

Tags

Documentation Development Testing Technical Research

Newer

Dec 31, 2020

Protect your WordPress REST API with OAuth2 using Auth0

In this post, we're going to add the ability to use Auth0-generated access tokens for WP REST API endpoints that require an account and certain capabilities.

Older

Oct 28, 2020

Technical Research: Testable Documentation

I've been thinking about documentation quite a bit lately, especially the code-centric type, and how to avoid punishing myself for spending time writing it. Here's the start of my research project to that end.