Documentation with JSDoc
— JavaScript, Documentation, Software Development — 4 min read
Recently my team did a bit of refactoring and decided to break out our Page Object Model and API interaction functions into separate libraries.
While this abstraction allowed for cleaner code in our step definitions it came with the side effect of members of the team seeing the library as a mystery box of functionality that they needed to jumble through to find what they needed.
In order to communicate what was available to the team I set myself the task of adding documentation to the code base with JSDoc so there was an easy way to access break down of the code and what it could be used for.
Writing docstrings
I feel there’s an art to writing docstrings which is hard to master; It’s often easy to write something like the following:
1/*2* Adds one to the supplied number3*4* @param {number} number - Number to add one to5* @returns incremented number6*/7addOneToNumber(number){8 return number + 1;9}
While this docstring is correctly explaining what will happen to the value supplied to it, it doesn’t really explain why the person wishing to use the function would use it. There’s no context of why it was written.
The function could have been written to make it easier to convert 0 based array indexes into nth-child selector indexes and the original developer had given the function a very generic name.
1/*2* Adds one to the supplied number to allow nth-child index access3* when selecting elements in a list4*5* @param { number } number - Number to add one to6* @returns incremented number7*/8addOneToNumber(number){9 return number+1;10}
As the use cases for the function grow they should also be added to the docstring. This allows for easier refactors, as the consequences of changing the function are clear to the developer taking on that work.
I personally favour all classes and functions having docstrings, no matter how small and insignificant they appear. As the code grows, so will reliance on these functions and it’s a good idea to get into the habit of updating docstrings early before things get unmanageable.
There is a great eslint plugin called eslint-plugin-jsdoc that will add checks on the docstrings as part of the linting process.
Ultimately the decision on whether a docstring is useful and accurate is down to those consuming it, so if you’re building a library in a silo it’s important to have someone external in the code review even if they are there just to check the documentation will be useable.
Adding structure to the documentation
The output of JSDoc on your first run will most likely be a collection of classes and a massive ‘globals’ section, especially if you’ve got a very functional code base.
JSDoc by default lumps all these functions into the one category regardless of how well laid out your files are which I found to be a pain when adding JSDoc to our API library as I wrote that in a very functional manner.
Luckily JSDoc has a @module
keyword that allows you to declare a structure for the different functions. It requires a little bit more effort but you can add the declaration at the top of the .js file and all functions in the file will inherit it.
Adding tutorials
One of the best parts of the JSDoc is the ability to create tutorials. These are separate pages that explain how to use the library’s functionality but can also be linked to from the docstrings, which help add the context that I mentioned earlier.
To add tutorials you do the following:
- Add a folder that will contain the tutorial markdown files
- Add a markdown files that explain how to use the library and it’s functionality
- Add a JSON file that adds metadata to the markdown file (such as providing a clear title or setting out a tutorial hierarchy)
- Add a
@tutorial
keyword that links the docstring to the tutorial page
You can then use these tutorials to communicate how the members of your team should use the library and if they find themselves looking up how a particular function works they have a link to this tutorial to help them if they are stuck.
Automating things
Documentation is pointless if it’s not kept up to date, versioned correctly and not readily available.
Luckily we live in an age where storage is cheap and we are spoilt for choice when it comes to continuous integration solutions.
My team is using Jenkins to run tests so I set up a job that listens to updates to the master branch of our git repo for the libraries, builds the documentation and publishes the documentation at a set URL.
To ensure we’re not overwriting documentation for different versions I used JSDoc’s package.json functionality to publish based on the package version, as the library is develops this version is bumped so those using an older version will still have access to accurate documentation.
End user testing
As mentioned before, the person who will be using the library and consuming the documentation is the best person to make a judgement call if the documentation being provided is valuable.
I set aside some time to do a spike of the documentation approach I was taking before getting feedback from my team and made changes based on their feedback. I then made the rules for documentation that they wanted as part of the development process.
Summary
Here’s a few points I think it’s worth driving home before wrapping up:
- Talk to the people who will be using your library. If they don’t get any value out of the documentation then it’s a wasted effort
- When writing docstrings add as much context for the use of the function, this will not only help future development but those using the library
- JSDoc has a lot of really great tools and features that aren’t blatantly obvious and if you’re looking to generate documentation it’s worth investing some time to test these out
- Be careful with generating documentation with loads of ‘global functions’, structure these so it’s clearer on which function belongs to which module
- Automate the generation of documentation but make sure it’s versioned so those on older versions aren’t stuck looking at inaccurate information.