How We Built Our Brand New Developer Portal. And Why…
Great technology products do not work unless they also provide a great developer experience. Especially when the technologies are complex and difficult to comprehend, which is the case of digital banking security plugins that we do, the developer onboarding can be a big decision making factor. However, building a comprehensive developer portal is a challenging and never-ending task.
The documentation was always a big topic for us. In fact, we are one of the few companies whose entire business started with the documentation. This is our Wultra commit number one. As you can see, our repository began as one big README.md
file with a documentation of an ideal authentication protocol. As time went by, our documentation (and our software in general) became more complex and had to evolve.
Github Wikis
At some point, a single README.md
file with documentation simply became way too long. We also suddenly had more than one repositories. Initially, we used Github Wikis for the documentation of each individual repository. For some time, this worked relatively well. We cannot give Github enough credit for helping us with the development infrastructure. Having a free Wiki with every Github project was extremely convenient.
After some time, however, we met another issue. We had well-documented components, not well-documented software. It was better than having nothing. However, we didn’t have a single place for documentation that the developers working with our products could simply visit and find what they are looking for.
We eventually got caught up with confused questions from our partners, who were looking for documentation in a wrong repository, and we ended up just dispatching the correct links as the questions arrived, over and over again.
Github Pages… ish… Kind Of…
In a poor attempt to tackle this issue, we prepared a lightweight Github Pages project that would link the individual Wiki pages. In our typical ”fairytale hippie graphic design” of that time, we built our first “download portal.”
It was nothing more but a single index page that still pointed to the Github Wikis and releases pages, hosted directly on Github. But at least it provided some reasonable umbrella site for all the components we had at the time. It was an improvement. Then things got more complex again… and we had to change everything again…
Complex Software, Complex Requirements
It didn’t take long, and we saw that we could not just put a sticker over the bigger issue in the documentation structure we had. We suddenly ended up discussing topics such as:
- Versioning: How do we version the documentation, to capture the fact that some components require specific versions of dependencies?
- Overview Documentation: How do we document a situation in which several components need to be deployed at the same time, to achieve specific customer setup?
- Maintainability: How do we make sure that the documentation does not deteriorate (broken links, too loose structure, …)?
But we also discussed the most basic, yet the most necessary topic of all: Developer Experience. The high-level goal of every developer portal is clear. The developer should visit the documentation site, learn about the topic as much as possible, and successfully implement the integration.
We shared this simple goal too. However, we saw that we are not even close to achieving it.
Solutions Too Small, Solutions Too Big
We started looking at the options for the developer portal platform. And while it was not the solutions’ fault, we were not really happy with them.
On one end of the spectrum, we saw some very nice documentation tools, such as Readme.com or Docsify.js. However, we evaluated that these tools are just too small and too simplistic for our use-case. Our software is not “the one thing” that we need to document. It is a complex componentized system with many configurations. To put it in the practical terms: Our left menu would just contain too many items that would seem in a way unrelated to each other. We also saw some specialized documentation tools, such as Apiary.io or Swagger. These are an excellent complement to some parts of our product documentation. But we could not use them as the main developer portal platform. We are not an API product either…
On the other end of the spectrum, we saw the generic and much more robust documentation tools, such as Confluence (which we discussed quite a lot), various Wiki platforms, or CMS platforms (Wordpress, Drupal). These have one common issue that we know very well from our own experience in various companies. While we could do almost anything with these tools and set up any documentation structure, we would eventually end up with a collection of assorted pages. We saw Confluence or Wikis fall apart way too often. We knew that if we decided on this approach, we would end up with mess documentation that nobody would want to use. Whenever I see the software documentation hosted on Confluence or a Wiki platform, I leave and look for another option.
Square Peg in a Round Hole
“Neither of the existing docs tools is good. We need to write our own.”
Whenever I encounter this statement from a developer (including thinking it myself), I automatically become suspicious. It is rarely the case anyone needs to build anything in-house these days. However, in our situation, this seemed to be the correct solution.
Our software is different. Specific. Unusual. Special. Are we delusional? Maybe… Of course, whenever we talk about this with someone, we hear the same generic advice clichés, which we could basically translate to: “Your software is wrong.” We were advised to simplify things and define the product better. Thanks to this, we should fit into the existing documentation tools.
However, the more time we spend with our software components, the more we know that the software is, in fact, done right. We found that our customers can easily choose the appropriate set of our components and put them together to build a unique setup specific for their requirements, be it on mobile or web. Authentication is a complex topic where one can use the same components to create an entirely different end-customer setup.
Building Our Own Developer Portal
Instead of thinking about why our software is wrong, we started to think about what we need from the documentation. We put together the list of basic requirements:
- The documentation is written in a simple to write text format.
- The documentation is created naturally alongside the product.
- The documentation is versioned according to the release.
- Flexibility — ability to create a new type of documentation.
- Eye-catching and consistent styling that is easy to read and navigate.
- Simple updates of current and previous versions.
- Documentation exports.
- Maintainability and automation.
After we put some thoughts into these requirements, we agreed on the following technology stack.
Our approach was the following:
- We will use the Github Flavored Markdown to write the documentation inside of the Github repositories. We will create a special repository for generic documentation.
- We will use an in-house-made command-line tool to do the documentation pre-processing and validation.
- We will compile the pre-processed documentation using Jekyll into the Liquid templates to obtain static HTML documents.
- We will host the resulting documentation on Github Pages.
The key low-level component of our documentation stack is our own DocuCheck tool. It takes the configuration JSON file as an input and loads all markdown files from various Git repositories (from the right tag or branch) specified in the config file:
{
"repositories": {
"ssl-pinning-ios" : {
"remote": "wultra/ssl-pinning-ios",
"tag": "1.2.0"
},
"powerauth-server": {
"remote": "wultra/powerauth-server",
"branch": "releases/0.24.x"
}
},
"repositoryParameters": {
"ssl-pinning-ios" : {
"singleDocumentFile": "README.md"
}
},
"globalParameters": {
"releaseIdentifier": "2020.05",
"parameters" : {
"docPath": "docs",
"homeFile": "Readme.md"
}
}
}
Then it pre-processes the markdown files, validates that the documentation is consistent (checks and fixes the links, required repo structure, headings, …), and compiles the pre-processed and enhanced (using Front Matter) markdown files into the resulting documentation bundle.
The second component is the repository with our developer portal. This repository contains the Jekyll project with Liquid templates and scripts. The scripts provide abstraction on top of the “releases,” and they call the DocuCheck tool to compile the resulting documentation bundles and turn them into the HTML files. These are then hosted on Github Pages.
This sounds great. But I must admit that the developer portal’s first version was still a bit rough on the edges.
From the visitor’s perspective, it did not provide much more over the “index page pointing to Github Wikis” approach. However, there were some significant improvements:
- The documentation was on one domain, rendered consistently with the index page, and allowed more straightforward navigation back and forth.
- The documentation moved from Github Wikis to the
/docs
sub-folder in the repositories. This enabled versioning of the docs with the software and included the documentation changes in each pull request review. - We fixed a lot of broken links and missing resources.
- We had a new toy we could be excited about! 😊
It was not a quantum-leap improvement, but it was a big step forward.
A Brand New Developer Portal
One day, we just decided to take some extra steps and launch a new project codenamed “The Brand New.” We took the same technology stack and made everything better.
First of all, we had to make our documentation portal better looking. To do that, we decided to go for a relatively inexpensive but very effective solution. We bought a premium Vesperr Bootstrap template. After we removed most of the unnecessary JavaScript plugins, cleaned up the template a bit, and translated the template concepts to several other pages, we ended up with an elegant HTML template. See the before-and-after reveal for yourself.
The change was big visually. However, it was also big under the hood.
Introducing The Tutorials
Besides the component documentation, we finally added some general guides and tutorials. We currently do not have many of those, but we can now add them swiftly as the new topics emerge.
From a technical standpoint, a tutorial page is a page like any other. Tutorials and generic documentation items have their special Github repository with a structure that follows the same principles as any other component repository.
As you can see, there is also information about a document author. Believe it or not, this is still done in a simple markdown thanks to the DocuCheck meta-data support. In any Markdown file, developers can simply write:
<!-- AUTHOR joshis_tweets 2020-05-04T00:00:00Z -->
The author’s metadata is then rendered into the Liquid template according to information in the _data/authors.yml
(link) file in the developer portal project. The benefit of using HTML comments for the Markdown metadata is simple: They are omitted during rendering in any other tools, including the Github Markdown file preview.
Per-File Sidebars That Stick With You
In the previous version of the documentation, we relied on the Github Wiki convention of having a _Sidebar.md
file in the repository, which results in placing the sidebar on the page. However, this approach had some limitations. We had to use the same sidebar for all documentations in the document folder — there was no way to specify a different sidebar. Also, the sidebar could be very long. It always had to scroll with the document content. Otherwise, we would end up with annoying sidebars that either scroll weird, or make some links inaccessible at the bottom.
In the latest developer portal, we use another DocuCheck meta-data item:
<!-- SIDEBAR _Sidebar_Server.md sticky -->
This allows us to specify a particular sidebar file for the particular documentation item. We can also decide to make the sidebar sticky if it contains a reasonably small amount of the links. This is extremely handy, especially in the tutorials.
Code Samples With Language Tabs
In typical Markdown-based documentation, we usually ended up selecting a single language for the particular piece of documentation or writing examples in multiple languages below each other, making them harder to navigate. In our developer portal, we use code tabs.
Our developers can simply annotate multiple code samples, like this:
{% codetabs %}
{% codetab Kotlin %}
```kotlin
val result = PasswordTester.getInstance().testPassword("test")
```
{% endcodetab %}
{% codetab Swift %}
```swift
let strength = PasswordTester.shared.testPassword("test")
```
{% endcodetab %}
{% endcodetabs %}
And documentation will render appropriate code tabs:
Full-Text Search
Thanks to a fantastic DocSearch project by Algolia, we quickly extended our developer portal with a precise and beautifully presented full-text search.
With this brilliant enhancement, our visitors will be able to find their documentation quicker.
Accessible Support Channels
Of course, despite our best effort, sometimes reading the documentation does not help. We made the option of reaching out to us on various support channels easy and accessible to everyone.
Summary
Of course, we know that we are not done yet. Writing and improving documentation is one of those tasks that never end. We still need to tackle the more advanced issues, such as including the developer success stories, video tutorials, handle the versioning of the components that develop at different paces, prepare better documentation for REST APIs, introduce the FAQ and Troubleshooting sections, and many more.
However, we are proud of the progress we made in the way we write, maintain, and present our documentation. From a single README.md
file, we elevated our documentation into a robust platform built on the well-chosen technologies. The recent improvements will enable us to develop and improve our developer portal in the long run. As a result, we will be able to provide the best experience to our partners and customers.
Do you have a tip for a new tutorial we should write? Let us know!