In the world of technology, it’s not only crucial to write good code, but to effectively document it, especially if you build an API. In Devengo’s journey toward efficiency and clarity, we have optimized and automated our process of generating and publishing documentation. We want to share this process with developers in the tech industry looking to abandon the static in favor of the dynamic and testable.
The Value of Documentation
Before delving into the details of Devengo’s evolution, let’s take a look at the limitations of our old workflow. We used to deal with static documentation that often became outdated and could be error-prone, especially if the documentation had some lines of code or JSON payloads. This not only made it difficult to maintain, but also could cause confusion to our users seeking to understand and utilize our services.
For this reason, we started to search for a system to have effective and current documentation for our API. Our documentation is the UI of our product, so we want to offer a pleasant, easy to understand, and up-to-date documentation at all times. Managing files with code manually wasn’t an option.
From Static to Dynamic
Our goal was to create a more intuitive and comprehensive documentation experience by implementing a series of improvements in our process that allow it to adapt to the specific needs and questions of developers in real-time.
Our documentation consists of two distinct parts: API Reference for our API’s endpoints and Guides to provide an overview and practical examples to use those endpoints. We continuously update both of them with every change we make in our code. Both parts of our documentation greatly benefit from a dynamic approach.
What We Have Built
We have evolved towards dynamic generation of documentation. Now the content we display is generated by our CI service from the release that is in production at any given time.
When writing our documentation, we take into account that certain parts require up-to-date portions of code or JSON. Therefore, we link these portions to parts of our code and, using introspection techniques, we are able to inject this dynamic content and display up-to-date examples in the documentation. If our build process detects any change on those linked portions, the documentation will be updated automatically.
We would also like to mention that we document our API with API Blueprint, something we will talk about more in future posts. To publish it with ReadMe, we have created a custom process that automatically converts it to OpenAPI during the CI build, and we use that generated proxy to interact with ReadMe. In the development team, we believe that documentation is a core, vital component of our product, and we have therefore created a publishing pipeline that is tightly integrated with our monorepo and development practices.
How We Build It
Let’s now discuss the process that makes this possible. This process consists of a builder that is made up of three different pieces:
- Templates: Where we define the structure of the content that our users will see. Our template engine allows us to reference values that are found in the code.
- Contexts: Which have direct access to the template being rendered, application code and general helpers that we have created ad-hoc for our platform.
- Renders: Which instantiate a context and inject the result into the template, thus generating the final version.
The combination of these three pieces working together is what allows us to have a dynamic render and generate a worry-free process for our documentation and avoiding out-of-date code. Finally, since the build process is executed within the context of the application, it also has access to the business logic of the application. This way we achieve the introspection feature we had talked about before.
Let’s see a simple example of a guide where we input the amount of money your brand-new Sandbox account receives once it’s created. This is a very simple example but easy to understand the process. Once you understand it, imagine that what you are injecting is the JSON payload of all the events you are sending to your user’s endpoints. JSON generated by your own CI cycle.
As you can see, the process we use to generate dynamic documentation is not very different from the generation of views in the widely extended MVC pattern in the development community.
Finally, with our documentation dynamically generated, we upload it to README using a simple script which is part of our deployment process. This script overwrites only the pages of documentation that has been changed.
After evolving this process, the improvement in our quality of life as developers has been huge, so the need for dynamic documentation has become even clearer in any development that aims to offer a pleasant ride for its team. Thanks to this, our clients have greatly benefited by being able to access accurate and up-to-date information at all times.
There is always room for improvement. In our case, the steps to follow in the future consist of improving the way we manage comments, opinions, and suggestions from our community to enrich our documentation and make it more valuable for everyone.