documentation

Thoughts on writing better documentation

Reasonable defaults

I like Python so much because the developer experience working is amazing - it's an incredibly productive language because of the Zen of Python. It explicitly calls out: there should be one-- and preferably only one --obvious way to do it..

It means Python library and modules often have one, clear, canonical way to do things and that implementation will typically have a 5-10 line sample that will cover user needs 99% of the time. It will try to handle all the 'gotchas' for you in a reasonable manner, and only if you want to customize it do you need to check the API docs. It doesn’t preclude having different ways of doing things, but there should be one obvious way.

Building blocks

Technical documentation sets will typically show you documentation for class API surface areas, maybe auto-generated from source comments. That's great! Except... it's probably not that helpful to the people who need it most. Developers are not trying to problem-solve how to use your class' API, they're problem-solving for scenarios. They are after desired behavior, and your class' API surface area is the afterthought.

A big gripe I have with documentation - in particular that of C#/.NET - is how often it falls into the trap of documenting the usage of specific methods or class basic building blocks without documenting the broader interactions, resulting in a myopic view of the overall desired behavior a developer is after.

It leaves users to stumble through assembling pieces to solve their scenario the hard way - akin to if a LEGO instruction booklet listed only all the different ways in which each LEGO shape could be used, but contained no step-by-step assembly instructions.

Knowing your audience

Writing quality documentation is about knowing your audience. Readers of documentation will generally fall into two buckets:

  1. People who have used your project before, and just need a refresher on API surface area
  2. People who are trying to figure out how to achieve specific desired behavior, are new to your project, and seeing if the fit is right.

Very specific API documentation best helps the former, while good examples and detailed remarks help the latter.

API documentation does little to help the latter group. It assumes they know about how the parts of your project are supposed to interact, within itself or with the language's standard library. That's a great way to have users to shoot themselves in the foot, instead of guiding users the right direction.

For example, if you are deeply experienced in the C#/.NET ecosystem and patterns, you probably already have an idea of what classes need to interact together to achieve the desired behavior and the patterns necessary to avoid gotchas down the line - it's extensive and wonderful, in-depth API docs are perfect for you!

But if you are a developer reading the docs with a fresh eye, trying to figure out "how do I issue HTTP GET in C#?" or "how to I verify a self-signed X.509 certificate with .NET?", you won't have as good luck. You'll probably end up implementing HttpClient in the obvious but sub-optimal way that causes socket exhaustion, or be lulled into a false sense of security from X509Chain.Build() without realizing nuance in the .NET implementation details warrants additional verification on top of the X.509 class methods.

Example - Polly and REST APIs

Say you want to make REST API calls to an external dependency, and want to also use Polly to add resiliency those calls. Luckily, there's a whole docs page for that! It'll even (briefly) touch upon that socket exhaustion gotcha with HttpClient.

It shows building blocks - how to add a policy to a HttpClient instance, and how to select policies.

However, the first real-world problem a user is going to run into is going to be needing multiple policies. Different endpoints are going to have different needs, and most importantly: POST is not idempotent, so applying retries are going to wreak havoc when the developer encounters their first failed POST call.

After hitting that, a user may realize their error and search along the lines of 'polly httpclient (idempotent OR idempotency)' on the upstream docs or Microsoft docs and promptly come up with no results.

Broaden the search results to any website and the top post is a helpful from Scott Hanselman
Scott Hanselman that mentions this specific issue:

GOTCHAS

A few things to remember. If you are POSTing to an endpoint and applying retries, you want that operation to be idempotent.

Since official docs are all focused on tying policies to HttpClient and subsequently how to inject it with DI, what's clear is that policies were intended to be tied a HttpClient instance - so the obvious question would be then how do I consume multiple HttpClient references via DI so I can apply different policies?

And just like that, the docs led the user down an obvious path, but a wrong one that shoots them in the foot: you shouldn't try and inject multiple HttpClient instances.

Let's go back to our idempotency search and pick results further down the page: blog posts by twilio and no dogma, both talking about this gotcha and demonstrating how to vary policies on a single DI-injected HttpClient based on the HttpRequestMessage properties (i.e. REST method) using AddPolicyHandler() or AddPolicyHandlerFromRegistry() respectively.

In short

Remember the Zen of Python?

There should be one-- and preferably only one --obvious way to do it.

Documentation should make the recommended implementation, avoiding gotchas, obvious; Include a remark about idempotency in sections that apply retry policy to HttpClient. Include a code sample that shows explicitly how to tie multiple policies to a single HttpClient, and also the recommended way to inject it with IHttpClientFactory.

What would amount to under 50 lines of sample code could show developers with fresh eyes a canonical implementation working around issues 99% would likely face, and save users hours of debugging. That's good documentation.

XMLmind's XML Editor

DocBook is a great tool for any documentation writer, but it can be a real pain to get adjusted to. I had decided to use it for the fwbackups 1.43.2 user guide the end result was great (less a few spelling mistakes), but coding it by hand took a long time and isn't something I would want to do again

I have been using XMLmind's XML Editor to rewrite the documentation for fwbackups 1.43.3 in DocBook 5 and it's been great. It has a WYSIWYG interface and although the program has a small learning curve, once I got used to the hotkeys my productivity went way up. Version 4.6.0 (released about two weeks ago) also includes a new Link tool can be enabled in the Preferences (under General > Features) that is excellent for creating cross-section links in your documents. After giving a section an xml:id name in the Attributes section, highlight a piece of text and select Edit > Add or Change Link... from the menu. All of the document's xml:ids for will be listed and selecting one will create the link automatically.

The license for the personal edition license allows XMLmind's XML editor to be used to write documents for any open source software (as defined by the OSI) - if you need a quick way to write great looking documentation, consider paying XMLmind's website a visit.