Building a Culture of Documentation

Create engineering cultures where documentation is written, maintained, and valued. Covers documentation-as-code, ADRs, runbooks, onboarding docs, docs-driven development, and the patterns that make knowledge transfer scalable.

Documentation is not a deliverable. It is a shared practice, a habit of writing, sharing, and evolving knowledge across an engineering organisation. Building a Culture of Documentation is the process of embedding documentation into the fabric of how engineers work: from writing code to shipping features, from onboarding to retrospectives. It matters when teams grow beyond a few people, when new members take longer than a week to become productive, when decisions are re-discussed every sprint, and when onboarding documents are outdated before they’re printed.

Establishing a Foundation

Before documentation becomes a culture, it must be *expected*. Every engineer must know that writing documentation is part of their job, not an extra task. The foundation is built through clear expectations, accessible tools, and a shared understanding of what good documentation looks like.

Define the "Documentation in a Box"

Every new engineer should receive a single, self-contained guide that answers: *What do I do when I start here?* This guide includes:

The CONTRIBUTING.md must contain the exact command sequence to contribute:


git clone [email protected]:org/project-name.git
cd project-name

# Set up the environment
make setup

# Run the test suite
make test

# Submit a PR
git checkout -b feature/new-endpoint
# ... make changes ...
git commit -m "Add endpoint for user profiles"
git push origin feature/new-endpoint

# Open PR with template
gh pr create --title "Add user profiles endpoint" --body "Closes #123"

The DEVELOPMENT.md includes a Makefile with common targets:

.PHONY: setup test serve lint

setup:
	pip install -r requirements.txt
	pip install -r requirements-dev.txt
	createdb project_name
	./manage.py migrate

test:
	./manage.py test --failfast

serve:
	./manage.py runserver 0.0.0.0:8000

lint:
	flake8 src/ --count --select=E9,F63,F7,F82 --show-source --statistics
	mypy src/

The make setup command ensures that a new engineer can get up and running with a single command, regardless of their environment.

Enforce Consistency with Pre-Commit Hooks

A shared configuration for linting and formatting enforces a uniform style across documentation and code. Use pre-commit with the following configuration in .pre-commit-config.yaml:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-toml
      - id: check-json
      - id: sort-lines
      - id: check-added-large-files
      - id: double-quote-string-literal
      - id: fix-encoding-pragma
      - id: mixed-line-ending
      - id: detect-private-key
      - id: markdownlint
      - id: rstcheck
      - id: commit-message-check
        args: [--min-length, "10", --max-length, "72"]

Each commit runs a suite of checks. A commit with a title shorter than 10 characters or longer than 72 fails with:

ERROR: commit message is too short (10 chars minimum): "Fix bug"
ERROR: commit message is too long (72 chars maximum): "Add user profile endpoint with validation and error handling"

The markdownlint hook validates that documentation files use consistent headers, spacing, and link formats.

Embedding Documentation in the Workflow

Documentation must be part of every step in the engineering lifecycle: design, code, review, deployment, and iteration.

Write Documentation as Part of Design

Before writing code, engineers must write a decision record. This is not a PDF or a Confluence page with a title and body. It is a structured file in DECISIONS/ with a standard format:

---
title: Add GraphQL API to User Service
status: implemented
created: 2024-03-15
authors: [alice, bob]
decision: "Use GraphQL over REST for the User Service API."
context: |
  The current REST API is underperforming under high load. Clients require flexible data fetching, and the current schema is rigid. We need to allow clients to request only the fields they need.

  Alternatives considered:
  - Use OpenAPI with custom code generation (costs time, improves type safety).
  - Use gRPC (high performance, but requires new tooling and client libraries).
  - Use JSON API (lightweight, but limited flexibility).

  GraphQL provides the best balance of flexibility, performance, and tooling maturity.
consequences: |
  - Pros:
    - Clients can fetch only the data they need.
    - Schema evolution is easier.
    - Tooling for introspection and debugging is mature.
  - Cons:
    - Increased complexity in server-side caching.
    - Need for a GraphQL client library in the frontend.
    - Learning curve for new engineers.

result: |
  We will implement a GraphQL API using Apollo Server. The schema will be defined in `schema.graphql` and versioned with `@graphql.schema.version` directives.

The DECISIONS/ directory contains one file per decision, named YYYY-MM-DD-title.md. A CI job runs make validate-decisions that checks for:

A failed validation produces:

$ make validate-decisions
ERROR: DECISIONS/2024-03-15-add-graphql-api.md: Missing 'context' section
ERROR: DECISIONS/2024-03-15-add-graphql-api.md: 'status' must be one of: proposed, review, implemented, rejected
ERROR: DECISIONS/2024-03-15-add-graphql-api.md: 'result' section is missing

This ensures that every design decision is discoverable, auditable, and reusable.

Make Documentation a Code Review Requirement

Every pull request must include a documentation update. The PR template includes:

## Documentation

- [ ] Update `README.md` with new feature details
- [ ] Add entry to `CHANGELOG.md`
- [ ] Add a new decision record if this is a major design change
- [ ] Update `DEVELOPMENT.md` with new setup steps
- [ ] Add examples to `examples/` directory

Add a link to the documentation PR: https://github.com/org/project-name/pull/123

The CI pipeline checks that at least one documentation file has changed:

# In CI job: check-documentation-changes
#!/bin/bash
if ! git diff --name-only HEAD~1 HEAD | grep -E "README.md|CHANGELOG.md|DECISIONS/|examples/"; then
  echo "ERROR: No documentation changes in this PR."
  exit 1
fi

If the PR lacks documentation updates, the CI job fails with:

ERROR: No documentation changes in this PR.
Please update at least one of:
- README.md
- CHANGELOG.md
- DECISIONS/
- examples/

The code review checklist becomes a contract: you cannot merge a PR without updating documentation.

Maintaining and Evolving Documentation

Documentation is not static. It decays. A culture of documentation ensures that it is regularly reviewed, updated, and kept relevant.

Schedule Regular Documentation Sprints

Every quarter, teams run a documentation sprint. During the sprint, engineers:

These sprints are announced in a #docs Slack channel with a shared agenda and a tracking issue. Each sprint produces a SPRINT-2024-Q1.md file in the DOCS/ directory, which includes:

The sprint itself is documented: the team records a 15-minute video walkthrough of the process, which is embedded in the SPRINT-2024-Q1.md.

Automate Documentation Publishing

Documentation is published automatically with every merge to main. The pipeline includes:

# .github/workflows/publish-docs.yml
name: Publish Documentation
on:
  push:
    branches: [main]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Build documentation
        run: |
          cd docs
          mkdocs build --clean
      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./docs/site
          publish_branch: gh-pages
          force_orphan: true
          commit_message: "Deploy documentation"

This generates a static site hosted at https://org.github.io/project-name, with a consistent URL structure:

Each decision record is available at https://org.github.io/project-name/decisions/YYYY-MM-DD-title.html.

Establish a Documentation Review Cadence

Every month, a team of engineers conducts a documentation review. They:

They leave comments directly on the Markdown files via GitHub pull requests. A review comment might look like:

> # Review: README.md
>
> ## Issue: Missing setup for database migrations
>
> The `DEVELOPMENT.md` mentions `migrate`, but `README.md` does not.
>
> ## Suggestion:
>
> Add a section "Database Setup" in the README:
>
> ```markdown
> ## Database Setup
>
> Run migrations with:
>
> ```bash
> python manage.py migrate
> ```
>
> Ensure the database is created and accessible.
> ```
>
> ## Suggestion: Add a diagram
>
> A diagram of the service architecture would help new engineers understand the system.

These reviews are tracked in a REVIEW-2024-03.md file that links to the PRs, and each review becomes a living record of the state of documentation.

Cultivating the Culture

Documentation is not a task. It is a practice. To sustain it, teams must regularly reflect on their documentation practices.

Conduct Documentation Retrospectives

After each sprint, teams run a retrospective focused solely on documentation. The meeting agenda includes:

The output is a RETROSPECTIVE-2024-03.md file that includes:

These retrospectives are not optional. They are part of the sprint cycle, and the documentation team maintains a shared calendar of upcoming reviews, sprints, and retrospectives.

Recognize Documentation Contributions

The culture is reinforced by visibility and recognition. Every documentation change is highlighted in a monthly “Docs Spotlight”:

This recognition is not just symbolic. It is tied to career progression: engineers earn points for each documentation contribution, and these points contribute to promotions.

Building a culture of documentation is not about writing more pages. It is about making documentation a shared, expected, and evolving practice. It is the quiet, consistent work that makes engineering teams resilient, adaptable, and deeply knowledgeable.

This page was rewritten on 17 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.