PBS 130 of X: Good Technical Documentation (JSDoc)
It’s all well and good to say that you write such good code that it’s effectively self documenting (yes, you actually hear people say that), and sure, comments help make all code more understandable, but really, that’s just not enough. Clear, well commented, code is easy to work at on a small scale — either on small projects, or within parts of larger projects — but they can’t help you with the bigger picture. As your codebase grows, you need a map!
Way back in the early days of this series, when we were just dipping our toes into the programming water I shared one of my favourite programming clichés — comments are like coffee, good comments are great, but any comments are better than none 🙂
That may not even be really true for comments, but it’s definitely not true for technical documentation. What’s worse than no docs? Out of date or inaccurate docs! Code doesn’t become well documented organically — it requires a consciously designed process, and the discipline to stick to it. There simply is no proverbial free lunch to be had here — sorry!
However, like with lunches, good tools can really help. Just like It’s a heck of a lot easier to cook to a well thought out plan in a well equipped kitchen that’s been organised such that you have all the tools and ingredients to hand just as you need them, it’s a heck of a lot easier to write useful documentation with the support of a good toolkit! That’s where documentation generators come in.
Matching Podcast Episode
Listen along to this instalment on episode 706 of the Chit Chat Across the Pond Podcast.
You can also Download the MP3
Instalment Resources
- The instalment ZIP file — pbs130.zip.
Who’s The Audience?
Documentation is a spectacularly broad word. It means so many different things in so many contexts. When I buy a new car I need to know how to turn on the de-mister — I don’t care what size wrench the mechanic needs when replacing the rear left shock absorber! When I sign up for a mortgage I need to know the dates and amounts of the repayments, how I apply for a payment break, and where I can access my current balance — I don’t care what port the Oracle database server holding my data is listening on! I could go on, but you get the idea.
In this phase of the project we’re creating an API for use by developers in their software. The whole point of releasing the module as open source is to encourage developers to re-use it in their projects. This is entirely analogous to our use of jQuery, MomentJS, Bootstrap, etc. We’ve only succeeded in using those open source APIs because they have good technical documentation targeted at consumers of their code.
Are users of the released API our only audience in an open source project? No!
The people creating the API also need documentation, and that documentation needs to describe not just published classes/functions, but all the under-the-hood stuff that powers them. Even when you’re working on a project on your own, you still need this kind of documentation. Trust me, future you will thank current you for making the effort!
So, we have two different audiences we need to cater for:
- Creators of our API
- Users of our API
What Do The Audiences Need?
Before any developer can use an API they need to understand the problem it solves, and the big-picture abstractions it’s built around. However, it’s not just users of the API that need a good understanding of the API’s purpose and mode, people contributing code to the API need that even more!
Similarly, both sets of developers need a clear, technical description of the API itself — what classes exist, what functions do those classes provide, what do those functions return, and what arguments do they expect? Is the API configurable? If so, how? And, what configuration directives are supported, and what values are acceptable for each?
Users of an API will also benefit greatly from a quick-start guide, some simple examples, and a few practical use-cases.
Examples and use-cases can help contributors understand the API’s philosophy better, but they’re not as important to this audience. But, there are things contributors need that users don’t — they need details of the classes, variables, and functions that power the module but are not exported as part of the public API, and they need practical documents like style guides, branching policies, and contributor agreements.
What are our Goals?
Let’s lean in a little and figure out what documentation we want to deliver for the HSXKPasswd JavaScript port this phase of the series is working to deliver.
I want to deliver two sets of documentation — one for the public, and one for contributors. The developer documentation won’t be separate, it will simply be the public documentation with extra detail inserted where needed.
The Public Documentation
- A welcome page with the module’s elevator pitch, a quick-start guide, links to the rest of the documentation, and a link to the GitHub page hosting the project.
- A description of the problem the module aims to solve, how it solves it, and the math that underpins it all.
- The API specification — everything the module exports, all the return types, arguments, etc.
- A contributors guide that outlines:
- The contributor agreement.
- The project’s branching policy.
- The project’s coding style.
- A quick guide for getting a working development environment up and running and building and testing the code.
In my opinion, it’s a healthy sign when an open source project gives the public the tools they need to convert the code into a fully functional build. I’ve never actually built my own customised copy of Bootstrap, but I could, because their docs clearly explain the process.
The Developer Documentation
The developer docs will be identical to the public docs, but, the API specification will include all the internal variables, functions and classes as well as the public ones.
Bart’s Documentation Dogma
I’ve been coding for decades, and in that time I’ve utterly failed at documentation more times than I care to admit, but I’ve also learned a lot of hard lessons from those failures. The most important lesson I learned is that not documenting is a terrible idea, and secondarily to that, I’ve learned a few other more practical lessons too.
Documentation is Source Code
I’m a firm believer that the only way to facilitate complete and accurate documentation is to write the documentation into the source code. In fact, the documentation for a function shouldn’t just be in the same file as the function’s definition — it should be right next to it, so both the docs and the function fit on screen at the same time without scrolling!
Document First
When I need to write a new class or function, or even simply declare a variable, I start by writing the documentation describing the class, function, or variable, then I translate that documentation into code.
Actually, that’s being overly simplistic — what I really do is write the first draft of the documentation, then I try to implement that idea in code, realise there were 50 things I didn’t think about, then tweak the docs, write more code, tweak the docs, write more code … I keep tweaking both the docs and the code until the docs describe what the code actually needs to do, and the code actually does it!
Start Simple and Keep Iterating
When you document first, your first draft will inevitably be very vague, but that’s fine. As long as you have an iterative mindset you know you’ll be revisiting the docs and the code many many more times. As long as each piece of the docs gets better each time you revisit it, you’re on the right track.
Be Consistent
A lot of people abuse Ralph Waldo Emerson’s quote about consistency being “the hobgoblin of little minds” to excuse all kinds of sloppiness, but the full quote adds some important context:
“A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and divines”
He’s referring to the very destructive pressure often put on politicians not to change their minds, regardless of changing evidence — he’s not referring to clear technical communication!
When there’s a single technically correct word, use it, when there’s a few possible synonyms available, pick one, and stick to it. Don’t chop-and-change throughout the docs. You might know it’s a distinction without a difference, but your readers may assume you mean something subtly different when you use one term in favour of the other.
Longer is not a Synonym for Better!
On a related note — better doc does not always mean longer docs! Sometimes more really is more, but particularly as a function, class, or entire API matures, shorter, clearer descriptions are often much better than longer ones. To me, it’s a sign that I’m on the right path when my descriptions become simpler instead of more complex.
To abuse a Mark Twain witticism — I’m sorry I wrote you such long docs, I’m still working on shortening them 😉
Our Toolkit (JSDoc + ESLint)
After a lot of faffing around, I’ve decided to return to the establishment choice for JavaScript API documentation — JSDoc. I’ve had a very mixed relationship with JSDoc over the years. The simple fact is that it’s imperfect — the HTML it produces has a terrible by-nerds-for-nerds feel, putting bling above readability, and there are times you have to adjust your code to JSDoc’s limitations, which definitely feels like letting the tail wag the dog. I go through cycles of getting cranky with JSDoc, trying every new kid on the block that promises to be better, and then being forced to accept that while JSDoc is imperfect, it’s the least imperfect of the bunch.
I’ve spent the last 4 weeks on another revolution of this cycle. On paper, documentation.js looked like it would be a nice improvement over JSDoc, so I did my absolute best to get it to work for me, and yesterday, as the deadline for publishing this instalment loomed over me, I had to accept the inevitable — JSDoc is still the least imperfect tool for the job.
Oh well — at least I have lots of experience with JSDoc and it’s various foibles!
JSDoc’s Key Features
Now that I’ve made it clear that I don’t think JSDoc is perfect, let me explain why I think it’s an extremely powerful tool that will serve us well.
- JSDoc uses variant of the JavaDoc syntax that’s becomes a defacto pseudo-standard generally referred to as doc comments, and is now supported across multiple languages, including PHP (with PHPDocumentor AKA PHPDoc).
- Doc comments are specially formatted code comments, and they’re placed directly before the thing they’re documenting in the source code. Your documentation is right next to your code, so you can update them in unison with ease.
- Because doc comments appear right next to the code they document, the JSDoc engine can infer a lot of information automatically — you don’t need to tell JSDoc that you’re describing a function because it can see that for itself!
- JSDoc provides annotations for marking variables, functions, classes etc. as private, and generating docs with or without those private elements included.
- JSDoc supports the inclusion of standalone pages into the documentation, making it possible to add things like a quick-start guide, contributor agreement, etc.
- JSDoc supports Markdown.
- The code intelligence in many IDEs understands doc comments, allowing them to show the relevant documentation snippets in tooltips, and to generate better code completion suggestions.
- Many linters, including ESLint, support doc comments, helping us to keep our documentation complete and accurate.
- JSDoc supports themes, so in theory, the imperfect default theme could be replaced with a better theme in future, without the need to change any of the documentation by so much as a single character.
While I’ve decided to use JSDoc for the port of HSXKPasswd to JavaScript, I’ve not yet picked a theme. I really dislike the default theme, so I’ve been on the hunt for something better. So far I’ve not found anything that’s perfect, but I have found a few I dislike less than the default.
I’m very much open to suggestions if anyone finds anything promising!
A Quick Demo
We’ll dig into the details in the next instalment, but let’s at least generate some documentation before we end this instalment!
In the instalment’s ZIP file you’ll find a folder named pbs130a
. In here you’ll find a folder named src
that contains a slightly updated version of the sleeps to Christmas calculator module from instalment 128 that’s had a few extra functions added, in the root folder, a file named main.mjs
that uses the module to print the sleeps until Christmas.
To see the code open the pbs130a
folder in a terminal and initialise it as a Node project with:
npm ci
Next, make main.mjs
this file is executable with:
chmod +x main.mjs
Then you can run it to see the calculator in action:
./main.mjs
If you open the module (src/S2XmasCalculator.class.mjs
) you’ll see the code, and, that it’s been commented in an odd way — those are doc comments.
As well as defining the requirements for the sleeps calculator, the package.json
file also lists JSDoc as a developer requirement, and adds an NPM automation script to invoke it. The folder also contains a JSDoc config file (jsdoc.conf.json
).
We can use the NPM automation script to build the docs with:
npm run docs
That should create a folder named docs
, within which you’ll find a static documentation website created by JSDoc from the README.md
file and the doc comments in the module’s source code.
You can view the documentation by opening docs/index.html
in your favourite browser.
This is a very simplistic example and it uses the default theme. To prove my point about it having foibles, all the descriptions are doubled up, and I have no idea why!
Final Thoughts
JSDoc themes can be changed at any time, so the fact that I’ve yet to pick one isn’t going to slow us down. In the next instalment we’ll cover the basics of JSDoc’s variant of doc comments. If you’ve ever used JavaDoc or PHPDoc you’ll soon realise that all these doc comment variants are 90% or more alike, with the few differences that are dictated by the differences in design of the relevant programming languages. When you think about it, that makes sense — all programming languages share a lot of common concepts, but JavaScript isn’t Java or PHP, so of course there’s a need for some customisation to accommodate these differences.
What this means is that learning JSDoc will give us a headstart when we move to PHP, because the documentation syntax will already be familiar to us.