Writing as Software: Technical and Automatic Documentation Generation

Writing as Software: Technical and Automatic Documentation Generation image

A common strand that unites all programming is the central role that language plays in controlling the behavior and operation of machines and machine-language systems.

In this article, I wanted to draw attention to the increasingly close interplay between technical writing and programming whether for the purpose of guiding open-source contributions, producing academic white-papers for cryptocurrencies, documenting issues, or clarifying how something works, technical writing is increasingly automatically generated (sometimes translated or transpiled) right along with the source code!

This represents additional professional opportunities (for example X-Team's X-Authors program plus the newish API Writing and Technical Writing job roles found at a lot of companies now) and ways to enhance both customer-facing as well as internal communication.

Writing as Software

In the same way that we've seen the rise of devops (or as Andrew Clay Shafer puts it very well, "INFRASTRUCTURE IS [NOW] CODE"), we're now seeing the same with writing itself. For example, the Durham, NC company Automated Insights has been producing 1B+ articles a year that appear in the Associated Press, CNN, Fox News, etc.

Then there's also Markdown which combines full, semantic HTML5 with extra syntactic goodness to simultaneously combine client-side view technology along with natural language documentation giving authors the power to animate text using JavaScript (should they wish to) along with a robust sliver of full-on text-editing power. The conceptual and technical gap to combine web development and "just plain writing" is clearly closing (though both remain distinct areas of professional expertise and responsibility).

Lastly, the advent of great automatic documentation generation tools (like Swagger and JSDoc - both of which we'll survey below) represents the true hybrid of formal, programmatic, and natural language creativity! My hope is that this article will help to make your code management and technical documentation efforts a lot less stressful. Enjoy!

Tools

Let's survey a few tools and bring them all together into a simple example!

JSDoc

I was originally going to showcase ESDoc having used ESDoc in previous projects. At those times, I greatly appreciated the ease of using it and setting it all up.

After doing some recent research, I've come to the conclusion (and what seems to be the consensus view) that JSDoc is at least slightly preferable. Why? More stars on GitHub, missing pages (at the time of writing) in the ESDoc documentation, and more GitHub activity in general for starters.

JSDoc is also easy to add to our project using Bash:

  $ npm install -g jsdoc

or by addition to package.json:

"devDependencies": {
   "jsdoc": "=3.5.5",
}

We can then annotate our source-code like so:

/** * Example Text. * @constructor * @param {string} a - A String parameter. * @param {string} b - A String parameter. */

See the complete list of all the official Tags before you compile up your code:

  $ jsdoc reactAppSrc

Make sure the command is run on the same directory containing our React source! After running the command, you'll see a /out folder with the sample generated .html!

Swagger (OpenAPI)

Swagger provides several core functionalities that can prove invaluable! For starters, SwaggerUI abstracts some of the overhead needed to create API documentation and allow one to very easily auto-generate all API docs.

In our HTML view (presented below as an .ejs partial):

<body>
<% include ./swaggerSvg.ejs %>
<div id="swagger-ui"></div>
<script src="assets/swagger-ui-bundle.js"></script>
<script src="assets/swagger-ui-standalone-preset.js"></script>
<script> window.onload = function () { const ui = SwaggerUIBundle({ url: '/api/swagger/json', dom_id: '#swagger-ui', deepLinking: true, presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset ], plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], layout: 'StandaloneLayout' }) window.ui = ui } </script>
</body>

And, then we can supply our .json configuration from the /api/swagger/json:

{
  "swagger": "2.0",
  "info": {
    "description": "Here's a simple REST API I made for you!",
    "version": "1.0.0",
    "title": "X-Team REST API",
    "termsOfService": "http://swagger.io/terms/",
    "contact": {
      "email": "agerard@x-team.com"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
    }
    //...
}

(See: swagger.json)

Above, we use a pre-generated .json configuration file that we load into our client. The great benefit of this approach is that modifying our .json requires no changes to our Swagger view!

That's just one of many functionalities that Swagger provides - the supplied Node code sample provides several ways to translate between .md, .json, .pdf, and .yml - and you can also automatically generate API documentation directly from your source code to boot (pun fully intended)!

Marked.js

Marked.js is an outstanding library that allows you to inject .md files into your .md or .html (HTML is a subset of Markdown). This presents a number of interesting use-cases and advantages:

  1. Markdown reuse - we can inject a single-source of truth into n-many locations.
  2. We can easily share Markdown between one or more .md files.
  3. We can share Markdown content between projects.
  4. We can share .md content between libraries or frameworks.

Using the newer Fetch API we can snag raw Markdown anywhere we have an endpoint:

const init = {
  method: 'GET',
  headers: new Headers(),
  mode: 'cors',
  cache: 'default'
}

export const get = url =>
  new Promise((firstResolve, firstReject) => fetch(url, init)
    .then(response => response.text().then(data => firstResolve(data))))
get(MD_ETH).then(firstSuccess => {
  let el = document.getElementsByClassName('ethereum')[0], n = document.createElement('div')
  el.appendChild(n)
  n.innerHTML = marked(firstSuccess)
})

and then inject those resources into the DOM.

Jekyll

We can use Jekyll in tandem with some of the previously discussed tools or by itself.

Make sure to grab the Ruby+Devkit if you're installing on Windows and stay below version 2.5.0 to prevent dependency conflicts:

  1. Ruby
  2. RubyGems
  3. Jekyll

The installation will likely entail:

  1. Downloading and running the Ruby installer (try 2.3.1).
  2. Downloading and unzipping the RubyGem install files.
  3. Running $ ruby setup.rb from your unzipped RubyGem directory.
  4. Running $ gem install bundler jekyll -v 3.6.2.

A Bash script is also provided with installation instructions for Linux setup.

Jekyll posts are Markdown files with additionally specified meta information - we can thus use Jekyll Markdown and the Markdown we've generated elsewhere inter-operably.

  $ bundle install
  $ bundle exec jekyll serve
  # http://127.0.0.1:4000/

We can thus combine our content and .md resources in numerous ways imbuing our chosen communication strategy with a lot of flexibility.

Conclusion

We've focused mainly on ways to self-host your technical communications, writing, and documentation needs. Given the close interplay between source-code or API's and their corresponding technical communications, you might find it easier to self-host (which many companies do).

However, it's often the case that tighter integration between core communication services and file-sharing/file-permissions is required. In those cases the following resources might be very useful to you (in no particular order):

  1. GitBooks
  2. Read the Docs
  3. Atlassian REST API
  4. Dropbox Paper
  5. process.st
  6. Apiary
  7. Corilla

Check out the code for this article over on GitHub and thanks for staying tuned!

Shout-Outs and Thank You's

KEEP MOVING FORWARD

Adam Gerard / code