DEV Community

loading...

💻 Documentation as code

adamcoster profile image Adam Coster ・4 min read

Programmers hate writing documentation. Most programmers, anyway. That's just stuff that gets in the way of the Real Work™, right?

The truth is that the Real Work™ of programming mostly consists of things that aren't directly writing code. Determining specs, designing an API, exploring technical limitations, learning best practices, training others, and so on and so on.

Even when a programmer is directly creating code, that code itself must find some middle ground between sometimes-mutually-exclusive goals:

  • The code must solve the problem at hand.
  • The code must be easy to maintain.
  • The code must be efficient enough.

In order to be maintainable, good code must be written for people. Specifically other people. Even if you're a solo developer, your future self will be a different person, at least with respect to the code you're writing now.

One way to deal with this is so-called "self-documenting code". Combining carefully thought-out variable and function names with clean-code practices and industry standards is mostly what this is about.

Self-documenting code is also an excellent practice because it reduces how much documentation is required outside the code (e.g. in comments). Having code in addition to comments that describe that code is a "Don't Repeat Yourself" (DRY) principle violation. The purpose of DRY is to prevent errors caused by changing something in one place without also changing that same thing in another place. If there's only one place, such a mistake isn't possible.

But how do you document bigger-picture stuff? The overarching purpose of a project? Its entry point? Who should be using it? Its dependencies? When it was last updated? What coding standards it's using?

It's a lot harder to keep your project documentation DRY than it is for the lines of code within it. This is where we get into "Documentation as Code" (borrowed from the concept of "Infrastructure as Code"). The goal is to have every piece of documentation somehow coupled to the functionality of the project itself, so that if one changes then both must change.

Wherever possible, anyway.

I admit that this is something I've been historically terrible about, and am trying to find ways to dramatically improve in my projects. I don't have a grand solution, but here are some useful concepts and tools I've been thinking about:

  • Global conventions. When I say "global" I mean across projects and teams. Adherence to convention is a type of documentation. For example, if everyone knows that event-triggered functions are always prefixed with on (e.g. onDownload()), then you can have simpler function names without also needing comments. Or if everyone agrees that callback functions will always start with an error argument, then everyone's code can take advantage of that without additional documentation.
  • Configs everywhere. Tools like "Cosmic Config" make it easy to simultaneously follow general industry practices while also doing things how you prefer to do them. By putting information into parseable, testable configuration files. This brings you into infrastructure-as-code and environment-as-code territory, further reducing documentation needs.
  • Automate everything. If a robot does something, a person doesn't need to know anything about how that something works. If you need to do something regularly in a project, turn that thing into code.
  • Prevent setup errors. All good tools have an init command (or similar) to make it easy to start using that tool with minimum error. The best ones interactively guide the user through decisions they need to make by asking human-friendly questions. Ideally the user would never even need to look at the resulting configuration file(s).
  • Docs and Code should have the same dependencies. This is a tricky one, but also the one I'm most excited about. It's reminiscent of the Dependency Inversion Principle. The idea is this: we normally treat documentation as being dependent on the code, but what if we had both depend on something else? That way we could make changes to that something-else and consequently both the code and docs would stay in tune.

For that last item, you would definitely need documentation to be built by code for it to work. A simple example is using configuration files -- the code that builds your docs can read values out of the same config files that your code does. In effect, the more you can abstract concepts into modular code or data, the more it can be used in automated docs and code.

API documentation is probably the best example of this, especially for languages as flexible as JavaScript: you could use centralized API documentation to dictate both the functionality of your code and the documentation that describes it!

To accomplish this you could use tools like Swagger/OpenAPI, joi,Express Validator, and others.

I've only just started trying to find ways to do this. What tricks and tools do you use?

This article originally appeared in a DevChat Newsletter.

Discussion (14)

pic
Editor guide
Collapse
hassan_schroeder profile image
Hassan Schroeder

Expressive tests make excellent documentation that by definition can't get out of sync with the actual code, regardless of language.

And Elixir, for instance, lets you document each function with code examples that get run along with your unit tests, so that explicit documentation stays in sync with the function code. (See elixir-lang.org/getting-started/mi...)

Collapse
adamcoster profile image
Adam Coster Author

Ooooh, that's neat! The trick there would be finding such a system that has full support in the IDE (intellisense, linting, etc). I'll have to poke around for JavaScript/Typescript equivalents.

Collapse
stereoplegic profile image
Mike Bybee • Edited

Uh, JSDoc? One setting in VS Code for Intellisense (enable for JavaScript), one ESLint plugin (eslint-plugin-jsdoc), and you no longer need TS for static type checking. You can (and probably should) document examples too.

Actually install jsdoc as a dev dependency (which isn't required for the above paragraph, instead just requiring JSDoc comment syntax), and you get a generator for code docs.

Thread Thread
adamcoster profile image
Adam Coster Author

JSDoc is great, and gets at a subset of the general problem.

JSDoc doesn't cover all the functionality that Typescript does for type information, and is quite verbose in comparison. Using both allows Typescript to handle types and JSDoc to handle non-code metadata (explanations, samples), which can all be pulled together with TypeDoc and similar tools.

Thread Thread
stereoplegic profile image
Mike Bybee

True. You have to write fewer types just for the sake of other types.

Collapse
nickmaris profile image
nickmaris

In the following I would add "The code must be written within your time and budget constraints" as this applies to documentation too. Anyway, its the kind of things that you have to fail to appreciate it and only if you are willing to work with people who care about quality in any aspect. Sometimes we let ourselves get trapped in environments that don't care about quality in any form.

The code must solve the problem at hand.
The code must be easy to maintain.
The code must be efficient enough.

Collapse
jhelberg profile image
Joost Helberg

Great write! Have a look at literate programming. Also, every business decision leading to code should be documented in such a way that the dependency is clear and ready to be found when the business decision changes.

Collapse
cubiclesocial profile image
cubiclesocial

Programmers hate writing documentation. Most programmers, anyway.

I don't. For me, it's probably the most enjoyable and exciting part of writing software because it usually represents the last step of a software release, which means something's about to head out the door. Also, while writing documentation, I usually am looking at the source code and typically spot at least one or two last-minute mistakes (bugs) that would have made it into the release.

Basically, if you aren't writing documentation for your software, you are missing out on supplying your customers with good documentation such that they will constantly bother you by opening tickets/issues (i.e. waste your time) AND your software will have more bugs in it. That's right, good documentation = fewer open issues on issue trackers. For me, most issues that get opened are actually documentation bugs, not software bugs (e.g. not enough code samples such that users try to use my software incorrectly and get lost/confused).

Collapse
bertilmuth profile image
Bertil Muth

This is a topic I have been thinking about and working on for a long time. I‘m a big fan of “living documentation” - documentation that is never outdated because it is generated from the code or other technical artifacts (like the API docs you mentioned).

I’ve created a library for representing use cases as code, including complicated workflows, with the option of generating documentation from it: github.com/bertilmuth/requirements...

I’ve also created a library for generating diagrams from source code: github.com/diagramsascode/diagrams...

You can also run it as a script using JBang. Here’s the gist:
gist.github.com/diagramsascode/90b...

Collapse
nvcnvn profile image
Nguyễn Văn Cao Nguyên

Gherkin provide a great "framework" for writing Documents as Code ;)
cucumber.io/docs/gherkin/

English is not my native language, so the world "testing" confused me when writing automated test, I away think tests are "documents that can check their own correctness".

Collapse
itsmnthn profile image
Manthankumar Satani

Outstanding craftwork learned few things, do share as you explore.

Collapse
habutre profile image
Rogério Ramos • Edited

I have a strong preference for RestDoc+Asciidoc rather Swagger, it’s integrated with tests while documents the API

And as mentioned before, good unit tests works very well as a live/integrated documentation

edit: it’s for Java/Spring

Collapse
zilti profile image
Daniel Ziltener

A great idea would be literate programming, stuff like NoWeb, but there's pretty much no tooling for it so people shy away from using it.

Collapse
habutre profile image
Rogério Ramos

Someone knows some doc/test tool that can track live code for events in even-driven architecture?