Having a great product is of no use without great documentation, says Adam Butler. In his DevRelCon London 2017 session, he talks about the importance of open source, powerful tooling, contribution guides, automation and Docs Like Code. All elements that have enabled Nexmo to build a powerful and flexible platform for writing rich documentation collaboratively.
Adam: So, this is DocOps, engineering great documentation. Huge thank you for inviting me along to speak today, I’ve actually never been to DevRelCon, so, I wanted to have a little bit of inspiration, so Phil, who’s MC-ing the other stage, he spoke here last year. So, I looked at his talk for a little bit of inspiration, and this is what I got from it.
Phil: So I am Phil Leggetter, I’m a part of a developer relations team at a company called Nexmo. Nexmo. We’re Nexmo, Nexmo, Nexmo, Nexmo, Nexmo, Nexmo, Nexmo, Nexmo, Nexmo, Nexmo group, the Nexmo group. So, I think now you’ve all heard now of Nexmo, let’s get the pitch out of the way, I don’t do marketing, right?
Adam: I can without a doubt on my event form put 100% people have now heard of Nexmo, which is brilliant. So, DocOps. First, I should probably start off with what is DocOps? So, there’s this lovely quote that came up on the Write The Docs podcast, and I’m just going to play that to you quickly.
Jared: I like to call them DocOps, so, instead of DevOps they’re engineers that are responsible for maintaining your documentation tooling, how good your DocOps…
Adam: So, this is a term that Jared came up with on the fourth Write The Docs podcast, and I heard this shortly after joining Nexmo, and it was the first time I’d actually heard a label for the thing that I do, because most of our world is technical writers and there’s not many engineers within that. So, I mainly do the engineering aspect of our documentation, that’s what I’ll be talking about today. If you want to find out about the kind of information architecture and the writing stuff, I highly encourage you to go along to the Write The Docs communities and API The Docs, they cover that stuff really well.
So, I do this, believe it or not, at a company called Nexmo where I work on this platform. So, this platform is called Nexmo Developer, it is a documentation platform where we organise things by product. This is our messaging overview page. We’ve also got these building-block examples, like send an SMS, covered in six different languages in most pages, and I work on this alongside my colleague, Tom. So, Tom is our technical writer and we also get a huge amount of input from our DevRel Team. They contribute a lot of product knowledge and a lot of the code examples for the documentation.
So, a pretty typical relationship within the docs community is something that looks like this. So, it’s a technical writer tends to speak to a product owner, who then speaks to our engineers, and this is a fair…this is quite typical and it works quite well when you’ve got maybe one or two products. But when you’ve got six, seven, or eight then it starts becoming a little bit of a problem. So, as doc owners, we need to make sure we’re not being gate-keepers for this stuff, and we need to make sure that other people can contribute, whilst also trying to keep the quality of the documentation quite high.
So, I come from an engineering background, and I thought, “How can we, kind of, engineer our way out of this problem and build some tools and processes that allow us to give docs back to others?,” because everybody can contribute, kind of in their own way. You’ve got engineers that who know the backend better than anyone else. They have the most complete technical understanding of how the API behaves. Product owners have a huge breadth of knowledge, and they understand the customer needs the best. Technical writers, they’re really focused on the quality and readability and making sure the documentation is approachable to new developers as well as experienced ones. And customers, it’s an unfortunate truth that there are tens of thousands of them, where there’s only a handful of us, so they’re quite often the first people that notice issues in our documentation, and giving them a way to contribute back is really helpful. Where they don’t, that’s where support comes in. So, resolving really commonly reported issues, and, you guys. So, everything I’m going to talk about today is open-source, and you can, kind of, take all the work we’ve been doing over the last year, and use it for your product, and hopefully contribute back to our tool-chain and we can all, kind of, live off there.
So, this breaks down into five things: Engineering, Tooling, Contributing, Contribution guidelines, Automation, and “Docs Like Code.” So, starting off with the most obvious thing is, you can’t encourage contributions really unless your project is open source. So, open source is really just about getting rid of barriers to entry. You don’t want to have to like, fight with us, like, it should just be there and up for grabs at all times, and there’s a few things to make sure that you’re doing, kind of, open source responsibly. Make that sure that you’ve got a really good Read Me that’s thorough. Your Code of Conduct and Contributing Guides are super helpful for people not familiar with the platform already, and then you’ve got licenses so that people can actually legitimately take the stuff and build on top of it. And also making sure that your templates for your issues and your pull requests are really clear, and that way you’ll spend less time faffing about and more time actually doing things that benefit your platform. And this has started to have a positive impact for our documentation. It’s got a long way to go, but so far we’ve had 70 commits, just over 1500 changes from 22 contributors, and just to be transparent, this does include people inside Nexmo, but this only includes people who wouldn’t have previously contributed to the documentation, so that’s a win.
Next, I’m going to talk about tooling, and I’m going to start off using powerful tooling. So, we use Ruby on Rails and Markdown for our documentation, and that’s a little bit unorthodox. Most people are using build tools like Jekyll, and Hexo, and Sphinx, and instead we’ve kind of opted for a framework and I think the word ‘framework’ there is key because it’s something that doesn’t assume what we’re trying to build, what we’re trying to achieve. I wanted something that gave us the flexibility to say, “Yes” to everything.
So, our Slack channel is accessible, so as you probably all know, you have to be invited to join a Slack channel, so you can sign up straight from here, it sends over to the Slack API, and being able to just, kind of build that was really neat. And we’ve got our feedback mechanisms, you have this form that goes on the bottom of every page. We can report on this on a dashboard and everything goes through to our Slack channel as well, and building stuff like that was really trivial. We’re talking about things like internationalisation, and it’s just really great to know that our technology is not the thing holding us back, doing that. And my personal favorite is Code Examples, making sure that we’re customising our Code Examples for customers, so they have something that’s…that just works.
And these things, as well as some of the other practices we do, they require a database, and authentication sessions, and user input, and workers and things like that. So, even though we’ve got these powerful tools, we don’t want to over-engineer our tool like this butter robot here. We need to make sure that we retain the good qualities of those simple tools, like the build, the Jekyll for instance, and we need to make sure that these tools are intuitive.
So, just like any of the build tools, we have all of our documentation and directories. Just because we have a database, we don’t need to use it for all of our content. So, all of our Markdown files are in their own directories and that generates a navigation and things like that. And, we just use Markdown, and there are other formats for documentation that a lot of the people in the Write The Docs communities speak about. I think most people in this room would just default to using Markdown, and when you’re trying to encourage collaboration going for the thing that’s really easy and really popular makes a lot of sense.
Markdown is also readable by both machines and humans which is great, so you don’t need to contact switch very much, and it can be quite powerful. GitHub started using the power of Markdown by adding a few features that benefit their platform. Syntax highlighting, really obvious one, and task lists and tables and things like that. So, when I started working on this project, I wanted to extend Markdown in a way that would benefit technical writers. So, the way that we go about doing that, is we extend Markdown with middleware. So, we start off with GitHub-flavored Markdown and we progressively add features on top of it. So, things like sequence diagrams and tabbed content. But, we extend Markdown whilst also keeping the intuitiveness that we really, kind of, love from that.
So, the Markdown of the…sorry, middleware looks a bit like this. It’s a pipeline, so coming from the left here, you’ve got your Markdown file straight off the disk, unmodified, and it gets changed by a filter in a…in some sort of way, and then it passed that modified result onto the next filter until eventually, you’ve got HTML at the end. And this means that you can keep your concerns really tightly coupled, and you can build on things that you, like, have done in the past, and we go through 22 stages when we do this. We go from Markdown to HTML over 22 filters. The first 15 of these filters happen while the file is Markdown file, the 16th is the conversion from Markdown to HTML and then we perform a further six operations whilst the document has the kind of, structure of being an HTML file.
So, we’ll take a look at a few of these just to give you a little bit of insight, this is all done in Ruby, but you can do it in whatever language you like really. The first one is the front matter filter. It’s the most boring of them all, but it’s also the easiest to explain. So you have the file length, that’s off the disk. We utilise this front matter here in the controller, so for its weight and its navigation and the title of the page. Well, if you pass that to our Markdown-to-HTML renderer, it will spit that out in a “ptag.” We don’t want that, so we need to get rid of that. So, this filter is simple, regex, finds the matching pattern, replaces it with empty string, and then it takes the entire document, minus the front matter, and it passes that on to the next filter.
So, further down the line, we have Tooltips. So this is adding a feature that doesn’t belong in Markdown at the moment, but doing it in a way that if it was native, how might it look. So, this is the syntax here, so you just use a little carrot symbol, and then it works just like Lynx for instance, or similar to images, and again, this is a bit of regex that produces a span tag, puts the content and the data element here, puts the original text, the more in between the span tags. And this ends up to the user, just looking like this, and this is really great for when you have things like acronyms, and you don’t want to break the context by providing that little bit more detail that 99% of people wouldn’t need.
A bit more complicated is our tabbed examples, so we tend to use this for block-type components and we always use the same structure for this. So, you have free backticks, the plugin name, and then in between is always the YAML. It’s all the objects that that particular plugin takes. In this case, we’re providing a source of a directory. So, this example style guide tabbed content directory contains these three Markdown files Alpha, Bravo, and Charlie, and using our filter that just basically just loads all that stuff, puts it into DIVs, sorts the content based on the internal front matter. You end up with this, and from an interface from the technical writer’s point of view, they can just do this. They can add tabbed examples by throwing Markdown files in a directory and then using this tiny, little, kind of, almost include-like snippet, and that’s really cool.
So, there are three types of these extensions. There’s implicit, extended and plugins. So, the implicit ones are where you don’t have to do a thing. It just happens for free. It’s things like headings. Headings get a parameterised ID of the heading so that we can link to specific sections in the documentation, and we also add this icon so that customers can click it and then share references to pages.
And external links. Loads of external links in our documentation platform and the Markdown files I inherited used anchor tags throughout, even though it was Markdown because they wanted to do target blank, and that’s just really sad. It’s just like, we want to go offsite and open it in a new tab so we’ll have to write HTML instead of Markdown, whereas we can just detect that link just goes offsite, therefore, inject this icon and make it target blank automatically.
The extended ones, these are things that look like Markdown, but add new features. So they’re things like this tabbed content…sorry, collapsible content here, which just has pipes down the side. So, in like block quotes, you use angle brackets. If you just use pipes down the side then you get this, this JF sequence diagram stuff and labels. So these are some of the features that we’ve added. Lastly, plugins are a bit more involved, and they include things like this screenshot script here.
So, this is our dashboard here, and everything in there is generated from a script. So, if our dashboard every changes colour slightly – maybe after an acquisition, who knows – then we can just generate these images again, and even that blur, that blur is CSS we’re injecting into the site to hide my API keys and secrets, and that gets put onto the disk as SHA hash of the image, so if it’s not changed nothing goes in the Git history.
You might think this all has a bit of a toll on performance, and it doesn’t so much. I tested…I manually built all of our pages. We’re typically seeing around a 40 millisecond render time, but we do partial level caching, so as soon as it’s been rendered once, we keep it, unless you’re logged in. And, in fact, this is a bit misleading because I did this, realised this all sucks, so I fixed all those. So, it’s a lot better than this but it’s good to see that kind of that was the state before I wrote this talk, so it’s a bit more representative.
Next is contribution guides. So, contribution guides are incredibly important because we can build this stuff relatively easy and documenting new products isn’t that difficult. But keeping them up to date is really, really hard. There’s a lot of content out there. So, by getting the support from outside contributors, that makes maintaining things a lot more easy. So, we have a very thorough contribution section of our documentation platform, and these are some of the pages that we’ve got in there. So, we’ve got our style guide. This covers regular Markdown, as well as our extensions. We’ve got, for example, collapsible content here, tab to code examples, tables, JS sequence diagrams, models – they’ve got to go, horrible things – and our screenshot functionality. We’ve also got guides for contributing code examples, so making sure that we’re using consistent linters throughout. When we use…when we do our API keys and secrets, they need to be consistent enough that we can inject peoples’ keys in as well. Making sure examples aren’t too wide as well.
Our Write The Docs page. This covers basically everything else. Our tone of voice, our placeholder values, what we use for phone numbers, and our structure. So, we’re structured between overviews, guides, building blocks, and tutorials, so each one of those has its own guide as to how should these pages look and how should they function.
Next, is automation, because why do things twice? Automation is really important. We can actually just focus on doing things that have a positive impact for our documentation, instead of just repeating ourselves, and we do this in a few ways. Code examples, screenshots, link testing, and I’m keen to look into things like spelling, and grammar, automation. I’m just going to talk about one of them. The code examples, I think, helps us significantly. So, we keep all of our code examples in an external repository. So, you have all of these different repositories here and our DevRel team is kind of split over language specialists as well.
So, we recently changed our documentation on our node examples from using var, to let and const for instance, and to benefit from those changes in the documentation, like, I don’t want to have to like, pull that stuff down and import in, or copy and paste it and things like that. So, every time you push one of these repos, we actually trigger a Travis CI build that runs these through your break tasks. So, it builds all of the pages, then takes the code changes, builds them all again, and then diffs them, and there were some examples in those repos that aren’t used. So, sometimes you don’t end up with a diff, but if you do, like in this example, it automatically puts in a pull request. It says “These pages have been affected, this is the diff of the HTML out of it.,” and you can just go visit those pages and make sure that they still make sense.
And my last section is on Docs Like Code. So, Docs Like Code is a bit of a kind of, movement to basically take all of the practices that we know as engineers, and apply them to documentation because it’s not been done often in the documentation community. There’s also things like re-using definitions. So, you have, for example, our API reference page, this is our SMS API reference page, and we’ve got all of our, kind of, parameters here, whether they’re required or not, there’s data types, so like string or integer. We’ve got our code examples up here and our responses on what our objects look like. And this particular endpoint takes a lot of properties and has all of these various errors as well, and being able to define them in a way that we have a document that we can share with the engineering team makes so much sense. So, this is an open API 3.0 spec for our SMS API, and this entire page is generated from this document, and it means that you can share that with engineering. They can test their API against it, they can… And the library maintainers, the can possibly even use this to generate libraries in the future, so it’s quite exciting and we’re also mocking servers, so, it’s really useful. If you want to find out a bit more about “Docs Like Code,” I really recommend this book by Anne Gentle. It covers things like Git and GitHub documenting, REST APIs, CI, and automation and reviewing documentation code.
So, to summarise, open source, don’t put barriers in front of your contributors. Projects being open source can even indicate to your colleagues that they don’t need to ask permission to contribute to the project. Tooling, I really recommend the upfront investment in having some powerful tooling, but also keep it nice and intuitive. It will enable you to make your platform really rich. Contribution guides are really essential for getting quality external input and providing resources for your contributors. And automation, don’t repeat things. It’s wasted time. Focus on things that actually add some value. And Docs Like Code, take engineering practices because that works really good for written content as well and allows you to gain a lot of collaboration across your teams.
Just to wrap up, we are hiring another Technical Writer at the moment, so please go to developer.nexmo.com/team if that sounds interesting to you, and if the magical internet automation thing worked, I just tweeted that out as well. So, you can find out information at @labfoo on Twitter. This has been DocOps, thank you very much.