I’m not too sure about this blog post, because I’m not sure this is The Right Way to do this, but I wanted to at least document my progress.

Previously PDQ.js was compiled with emscripten, and the functions were exported as

Module.init = Module.cwrap('PDQ_Init', ...')

which exposed the C PDQ_Init function by using Emscripten’s Module.cwrap, and exports it to the Module object.

But this had no documentation, and I constantly found myself forgetting how to use the lib and having to consult the C documentation. Also, the library has a lot of constants for different concepts, like multi-server vs single-server queues or APPROX vs EXACT solution methods. These all compile down to numbers in C (like #define CLOSED 2), and I was forgetting which was which.

Ideally we could use typescript here, so users wouldn’t mix up the different constant types. I had heard you can generate types from JSDoc comment, so I decided to use JSDoc to document the functions.

Changing export style

JSDoc doesn’t let you comment on assignments like Module.myFunc = cwrap(....) to document myFunc, so I changed the style of my post.js to look like

/** {number} First-come first-serve queueing discipline. */
const FCFS = 8;
Module.FCFS = 8;

This way I could add JSDoc comments to the consts themselves, and then expose them on the Module object. I wish I could have just used export const FCFS = 8, but with my low-toolchain/no bundler setup here and the way this is appended to the Emscripten output, that would have only worked if I was compiling an ES Module (AFAICT).

Emitting types

What’s nice is that I was able to add types to the constants like this

/** @typedef {ISRV | FCFS | PHSR | LCFS} Discipline */

to create a type named Discipline that covers the different queueing disciplines, and then when I run npm run types with the appropriate tsconfig, it generates a file named dist/pdq.d.ts with the equivalent types for TS users:

type Discipline = 7 | 8 | 9 | 10;

I haven’t (and probably won’t) used TS with this library as I don’t want to set up a bundler, but it’s nice to have the option.

Generating docs

I added the following script to my package.json:

    "doc": "rm -rf ./out && node_modules/.bin/jsdoc post.js -R README.md"

Which creates a folder called out with my docs, using the README as the home page. It looks like this: [image tag here]

The next part is uploading this to the internet. This makes me really miss Rust, which comes with

  1. cargo doc by default and
  2. Crates.io that hosts the output of every published crate’s cargo doc command for free, without any fiddling required.

It dramatically raises the baseline amount of documentation for libraries in the ecosystem. Great defaults!

However, it’s getting easier and easier to do-it-yourself: I used more or less word for word the config on the @andstor/jsdoc action, minus a handful of test commits & an hour of fumbling around Github Actions:

name: GitHub pages

on:
  push:
    branches:
      - master

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Build
        uses: andstor/jsdoc-action@v1
        with:
          source_dir: ./interfaces/js/post.js
          output_dir: ./out
          template: minami
          front_page: ./interfaces/js/README.md

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./out

And now I have some docs being built automatically to https://amedeedaboville.github.io/pdq-qnm-pkg/ 🎉!

I have to say, I like these reusable Github Actions. It’s getting easier and easier to do CI & Ops things. I used to have to fumble for several hours to deploy with CI: This blog is deployed using Github Pages on pushes to master, and it took a whole afternoon to configure several years ago. Now these scripts are re-usable & shareable, that’s really nice!

I didn’t add auto-deploying to npm for master pushes because, eh, I’m the only maintainer of this package.

Conclusion

I updated PDQ.js to v0.2 with JSDoc comments, a .d.ts typings file, and made the docs auto-generated on pushes to Git.

I almost didn’t finish this because it was a fair bit of busywork, but I have a goal in mind: I want to build a Queueing Circuit Simulator/Explorer tool. The same way there are electrical circuit simulators where you can hover your mouse over a component to get its resistance, or show the voltage difference across two parts of a circuit, I’d like to make a D3.js based tool where you can add queueing nodes, change system parameters and watch different queueing centers update, all in your browser. Under the hood it would build a description of the queueing circuit as a JSON object and we could feed that to PDQ.js, recomputing when the system changed.

If we had that, we could also throw out the queueing theory and run eg ~1 million different simulations to see how the system behaved. I like this idea because a recurring piece performance measurement/capacity planning thought is “Just build a simulation!”. I’d love to have something like “simpy X queueing-tool” accessible in the browser.


comments powered by Disqus