Writing technical documentation: Why we get it wrong, and how to do it right

In Ye Olden Days, I was a COBOL programmer, working on a Unisys E1100 system with a CODASYL database. CODASYL-generated errors were mostly six-digit codes, so “000313” might mean that a FIND or FETCH (the CODASYL equivalent to SQL’s SELECT) failed to fulfill a search.

Generally, these were common errors: as soon as you saw that “000313” you knew what happened. But that number was actually a series of codes. Unfamiliar errors meant we’d hunt up the team’s DML book and cross-reference the applicable codes.

It was a pain. I thought: “Surely I can do better than that!” And so I did. I wrote a module for our COBOL programs, a decoder that translated the codes into human-readable messages, so it would show you:

  • The exact command that gave the problem. No looking up source code!
  • The exact error it gave. (Such as, “No matching records of this type exist in the set of related data elements.”)

This was, if I’m being humble and all, proof of my genius…at least, as long as one used the exact version of CODASYL I’d built it against. As soon as we updated our CODASYL database, my decoder was out of sync. And because I’d used a double-indexing system to save space and time for the error lookup, nobody could easily figure out how it worked, or how to update it.

That error-decoding system lasted for years, trusted but wrong when needed most to identify an error that wasn’t instantly recognizable. It remained so until they moved over to SQL databases entirely.

The real problem was that even though I built something that people relied on, I documented it poorly. It was a fine attempt, but ultimately a failure because of the lack of documentation.

Why documentation is important

Documentation really isn’t a luxury. It’s not something you add “if there’s time.” Documentation communicates with intent, maintains continuity and keeps systems alive after the original authors, even you (maybe especially you) have moved on.

Here’s a big-picture theory of documentation: it’s not just what to write down, but why, for whom and how to do it so it actually works. If you only document something when it excites you, or leaning on auto-generated fluff, you’re not doing anyone or yourself any favors.

It’s also about more than just inconvenience or technical debt. It’s about risk. Systems without documentation are fragile by default. When the knowledge lives only in one developer’s head, or in comments nobody reads, any change — a version upgrade, a team reshuffle, an unexpected outage, even a change in hardware capabilities — can reveal just how brittle the setup is. What seems solid is often held together by memory and luck.

What proper documentation is

If bad documentation is a signpost to nowhere, good documentation is an atlas, with landmarks and roads plus a history of the roads and surroundings. It doesn’t chart every hill and tree, but it shows how the parts fit, why they matter and what to do when things change.

A human-oriented interface to your system

Think of documentation as an API for people. It explains how the system is meant to be used, what its responsibilities are, and how the pieces fit together.

A Record of Intent

Your codebase shows what the system does. Documentation should tell us why. Intent is fragile. When you capture it, you give future developers the chance to understand decisions without reverse-engineering the codebase.

A guide through complexity

No matter how simple your architecture diagram looks, reality is more complicated. Documentation gives people the tools to navigate complexity by offering fallback strategies, showing critical paths, and surfacing failure modes.

What documentation is not

Most of us, including me, don’t actually document. Instead, we record.

Moreover, we record the wrong things. We scribe on cave walls to show we were there, knee-deep in code, but what we leave behind says little more than “I was here.” Future coders must guess if the etching is a Venus figurine, an antelope or a windmill.

Code comments are not documentation. They can help if they’re written to record intent and not what the code expresses, but they’re meant for code divers and not helpful for anyone who’s looking at the structure of your codebase.

Even at the code level, such documentation must record what the code is trying to do and why. Increment x by 1 is a classic example of an utterly useless code comment. It literally describes what the code instruction x++; does. What programmer won’t already know that? Worse, such code comments have an annoying tendency to get out of date and become worse than useless. They stop being accurate, and in effect lies about what the code now does. It’s actively harmful.

Other autogenerated documentation mechanisms such as OpenAPI endpoint documentation also have this problem. They document what exists (hopefully) but not why it exists, nor how to use it, in what order, or how to change it safely.

What is your team’s ‘bus factor’?

A bus factor refers to the ratio of the team members you could lose before the team is badly affected. If a 10-person team were to lose one member or a specific member’s role and the team would collapse, that team has a high bus factor. Such dependency and fragility is not tolerable.

A team with a low bus factor is resilient and rebuildable. Knowledge isn’t hidden in a few heads, and the systems and people are loosely coupled.

Some might view a resilient team like that as flawed and replaceable. Anyone who does that is a bad manager, leader and team member. Value people who can build those resilient teams, and don’t punish them.

Who to write documentation for

As mentioned earlier, documentation isn’t just meant to tell them programmers what the code does, or is meant to do. Effective documentation also provides insights and instructions to help understand the system holistically. Here’s a list of who benefits from careful documentation:

Your future self.  You will forget more than you think. Documentation is your gift to yourself down the road.

New hires and contractors.  They don’t know your organization’s acronyms or architecture. Documentation saves onboarding time and prevents unnecessary interruptions.

QA and DevOps. QA needs workflows and DevOps needs recovery procedures. Documentation makes those possible without tribal knowledge or Slack guesswork.

Stakeholders and non-developers. They don’t read code. Documentation builds trust and helps cross-functional collaboration.

What to include in a technical document

Besides pitfalls to avoid, what components make up a well-crafted technical document?

Architecture. Structure, components, and interactions. Use diagrams. Keep it current.

Decision history. Log tradeoffs, failures, and forks in the road. This prevents painful rediscovery.

Critical paths. What breaks the system? What’s essential? How can you avoid lighting your chair on fire?

Dependencies. Internal and external. Don’t assume anything is “obvious.” Track the who, where, and why.

Operational playbooks. How do you recover? Where are the logs? What do alerts mean? Document this before you’re under pressure.

Common technical documentation failures

Those who write technical documentation need to avoid several habits that will muddle their efforts and frustrate the intended audience, including your future self.

Documenting trivia, not workflows. Don’t just describe code; explain user flows and real-world processes.

Ignoring system boundaries, ownership and integration points. Without those details, nobody knows who owns what or what breaks what. Confusion is the enemy of knowledge, so stamp it out wherever you can.

Treating documentation as static. Docs must evolve with your system. If they haven’t changed in six months, that’s a red flag.

Using documentation as a dumping ground. Documentation that is not curated is worse than having no documentation, because it sends people down dead ends.

Effective habits for writing technical documentation

Besides bad habits to avoid that lead to poor technical documentation, what habits should technical writers adopt to ensure well-crafted technical documentation?

Keep docs in version control. Docs should live with the code. That way, they grow together.

Use lightweight, living formats. Markdown. Mermaid. Anything diffable and accessible. Prefer tools devs enjoy using.

Treat docs as first-class in code review. If a PR changes behavior, it should update docs. Review both.

Encourage team ownership, not gatekeeping. Everyone should be able to write and fix docs. Make it easy, and celebrate contributions.

Don’t let templates fossilize. Start with a structure, such as README templates or decision logs, but let them evolve with the project.

Final thoughts on writing technical documentation

Documentation isn’t a chore. It’s how your system stays alive.

Start small. Update a README. Capture one decision. Write a sentence. Explain one config. Momentum builds from there.

Ask yourself: “If I disappeared tomorrow, could someone else pick this up?”

If not, write the page you wish you’d found.

Joseph B. Ottinger has held senior roles in software engineering and project management. He’s written countless articles and multiple books on various languages, architectures and implementations, including Hibernate and Spring.