Skip to content
StackPractices
beginner By Mathias Paulenko

Technical Documentation Strategy: Docs as Code

A practical guide to treating documentation as code: versioning, review workflows, structure, and tools that keep docs accurate, discoverable, and maintainable.

Topics: devops

Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.

Technical Documentation Strategy: Docs as Code

Introduction

Documentation is the single highest-impact activity in software engineering. A well-documented system reduces onboarding time, prevents repeated mistakes, and preserves context across team changes. Treating docs as code means applying the same rigor — version control, code review, automated checks — to documentation that you apply to source code.

The Four Essential Documents

Every system should have these four docs. They answer different questions at different depths.

DocumentAnswersAudienceUpdate Frequency
READMEWhat is this? How do I run it?New developers, usersEvery major change
Architecture Decision Record (ADR)Why did we choose this?Current and future maintainersOnce per major decision
RunbookHow do I fix it when it breaks?On-call engineersAfter every incident
API ReferenceWhat does this endpoint do?API consumersAuto-generated from code

Docs as Code Workflow

Developer writes docs in Markdown

Opens a pull request (same repo as code)

Reviewer checks code AND docs

CI runs: markdown lint, link checker, spelling

Merge → docs publish automatically

Why It Works

PrincipleHow Docs as Code Applies It
Version controlGit history shows when docs changed and why
Code reviewReviews catch technical inaccuracies, not just typos
AutomationCI ensures consistent formatting and valid links
BranchingDoc changes ship with the code they describe

README Structure

A README should answer these questions in order:

# Service Name

One-line description of what this service does.

## Quick Start

How to run it locally in under 5 minutes.

## Architecture Overview

High-level diagram and key dependencies.

## Configuration

Required environment variables with examples.

## Testing

How to run unit, integration, and E2E tests.

## Deployment

How this service is deployed (CI/CD link, environment list).

## Troubleshooting

Common errors and how to resolve them.

## Contributing

Link to contribution guidelines and code of conduct.

Architecture Decision Records (ADRs)

ADRs capture the context and consequences of major technical decisions. They prevent future debates about “why did we do it this way?”

ADR Template

# ADR-042: Adopt Kafka for Event Streaming

## Status
Accepted

## Context
The order service needs to publish events to 4 downstream consumers. REST callbacks are unreliable and create tight coupling.

## Decision
Adopt Apache Kafka as the event streaming platform.

## Consequences

### Positive
- Decouples producers from consumers
- Supports replay for new consumers and debugging
- Handles backpressure via consumer lag

### Negative
- Operational complexity (ZooKeeper, brokers, partitions). See [event-driven architecture](/guides/architecture/event-driven-architecture-guide).
- Team needs to learn [event-driven patterns](/guides/architecture/event-driven-architecture-guide)
- Eventual consistency requires Saga pattern for some flows

Rule of thumb: Write an ADR for any decision that costs > 2 weeks to reverse.

Runbooks

A runbook is a step-by-step guide for responding to a known alert or failure mode.

Good Runbook Structure

# Runbook: Database Connection Pool Exhausted

## Symptoms
- Alert: `db_pool_connections_exhausted`
- User impact: API requests timeout after 5 seconds

## Diagnosis
1. Check current pool usage: `SELECT count(*) FROM pg_stat_activity;`
2. Identify slow queries: `SELECT * FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;`
3. Check for connection leaks in application logs

## Resolution
1. If caused by slow query: kill query, [add index](/recipes/performance/database-indexing), or scale [read replicas](/guides/databases/database-design-guide)
2. If caused by connection leak: restart app pods (temporary), then deploy fix
3. If persistent: increase pool size in config and redeploy

## Escalation
If resolution fails after 15 minutes, escalate to Database Team on-call.

Documentation Tools

ToolUse CaseProsCons
Markdown in GitREADMEs, ADRs, runbooksUniversal, versioned, freeNo built-in search
MkDocs / DocusaurusProduct documentation sitesSearch, versioning, themingRequires build step
Notion / ConfluenceLiving knowledge baseWYSIWYG, easy collaborationNo git versioning
Swagger / OpenAPIAPI referenceAuto-generated from codeLimited to API surface
Mermaid / PlantUMLDiagrams as codeVersioned diagramsLearning curve

What Works

  • Write the README first — if you cannot explain how to run the service, the service is not ready
  • Keep docs close to code — docs in a separate repo rot faster than code
  • Automate link checking — broken links destroy trust; CI should catch them
  • Use diagrams as code — Mermaid and PlantUML keep diagrams versioned and editable
  • Review docs in PRs — a code change without a doc change is an incomplete PR
  • Set a freshness policy — flag docs not updated in 12 months for review

Common Mistakes

  • Writing docs only for beginners — experts need docs too (API refs, architecture overviews)
  • Creating a wiki graveyard — wikis become outdated because there is no review process
  • Documenting what, not why — the “why” is what you forget in 6 months
  • Over-documenting — if the code is self-explanatory, do not explain it; explain the intent instead
  • Separating docs and code in different repos — the friction of context switching guarantees docs will not be updated

Frequently Asked Questions

Who should write documentation?

The engineer who built the feature. They have the context. Technical writers can polish, but the source of truth must come from the implementer. Make doc writing part of the Definition of Done.

How do I keep docs from becoming outdated?

Treat outdated docs as a bug. In your bug tracker, create a label “documentation” and prioritize it alongside code bugs. Require README updates in the same PR as code changes.

Should we use Confluence or Markdown in Git?

Use both for different purposes. Git-based Markdown for code-adjacent docs (READMEs, ADRs, runbooks) that change with the code. Confluence/Notion for cross-team knowledge, onboarding, and process docs that evolve independently.

Advanced Topics

Scenario: Documentation System for Platform

System: Platform with 50 teams, 200 services
Strategy: Diataxis framework (4 doc types)

Diataxis Framework:
  | Type | Purpose | Audience | Examples |
  |------|---------|----------|----------|
  | Tutorial | Learn | Novices | "Create your first service" |
  | How-to | Solve | Practitioners | "How to configure Redis" |
  | Reference | Consult | Everyone | API docs, CLI flags |
  | Explanation | Understand | Curious | "Why we use Kafka" |

Docs structure (Backstage):
  services/
    payment-service/
      README.md          # How-to: how to run locally
      api.yaml           # Reference: OpenAPI spec
      runbook.md         # How-to: what to do when it breaks
      architecture.md    # Explanation: design decisions
      on-call.md         # How-to: on-call procedures
    order-service/
      ...

  tutorials/
    new-microservice.md  # Tutorial: step by step
    new-endpoint.md
    local-dev-setup.md

  adr/
    001-record-events.md
    002-use-postgresql.md
    003-adopt-kafka.md

Runbook template:
  # Runbook: Payment Service
  ## Symptom: Error rate > 1%
  1. Check error dashboard
  2. Check recent deploy: kubectl rollout history
  3. If recent deploy: rollback
  4. If not: check logs in Loki {service="payment"}
  5. Check DB: active connections, locks
  6. Escalate: contact DBA if DB saturated
  7. Post-mortem within 48h

  ## Symptom: p99 latency > 500ms
  1. Check trace in Jaeger
  2. Identify slow span
  3. If DB query: check EXPLAIN ANALYZE
  4. If external API: check status page
  5. If CPU: check HPA scaling
  6. Post-mortem if > 10 min

Documentation metrics:
  | Metric | Target |
  |---------|--------|
  | % services with README | 100% |
  | % services with runbook | 100% |
  | Docs updated in last PR | > 90% |
  | Onboarding time | < 1 day |
  | Searches with no result | < 10% |

Lessons:
  - Diataxis separates doc types with distinct purposes
  - Runbooks are living docs: update after every incident
  - ADRs preserve the "why" behind decisions
  - Backstage centralizes service catalog and docs
  - Measure doc quality like you measure code quality

How do I keep documentation up to date?

Make doc updates part of the Definition of Done. Block PRs that change code without updating docs. Run automated checks: broken links, stale diagrams, APIs that do not match specs. Assign owners to every document. Review docs quarterly like you review code.

End of document. Review and update quarterly.