Documentation as Code
Treating Docs Like Software
The docs-as-code approach applies software development practices -- version control, code review, continuous integration, automated testing -- to documentation. Instead of documentation living in a disconnected wiki that rots quietly, it lives alongside the code it describes, goes through the same review process, and is deployed through the same pipeline. For QA teams, this approach is particularly powerful because test documentation, test reports, and quality metrics can be generated, validated, and published automatically.
Why Docs-as-Code
Traditional documentation tools (Google Docs, Confluence, SharePoint) have a fundamental problem: they are disconnected from the codebase. When the code changes, the documentation does not automatically update. Nobody notices when a wiki page becomes inaccurate. There is no review process to catch errors. There is no version history that correlates with code changes.
| Traditional Docs | Docs-as-Code |
|---|---|
| Stored in a wiki or shared drive | Stored in a Git repository alongside code |
| Edited through a web UI | Edited in a text editor or IDE |
| No review process | Pull request reviews, same as code |
| Version history is buried | Git history shows every change with context |
| No CI/CD | Automated builds, link checking, spell checking |
| Disconnected from code changes | Documentation changes in the same PR as code changes |
| Formatting varies wildly | Consistent formatting through linters and templates |
| Difficult to search across repos | Standard text files are searchable with any tool |
Choosing the Right Format
Markdown
The most common format for docs-as-code. Simple, readable as plain text, widely supported.
Strengths:
- Nearly zero learning curve
- Readable without rendering
- Supported by GitHub, GitLab, Bitbucket, and most static site generators
- Great tooling ecosystem (linters, formatters, editors)
Weaknesses:
- Limited formatting options (no admonitions, tabs, or complex layouts without extensions)
- No native support for includes or content reuse
- Table syntax is cumbersome for complex tables
Best for: README files, test documentation, runbooks, API guides, most QA documentation.
AsciiDoc
A more powerful markup language with native support for complex document structures.
Strengths:
- Native admonitions (NOTE, TIP, WARNING, IMPORTANT)
- Includes (import content from other files)
- Table of contents generation
- Conditional content (show/hide based on variables)
- Cross-references between documents
Weaknesses:
- Steeper learning curve than Markdown
- Less tooling support than Markdown
- Not natively supported by GitHub rendering (rendered as basic text)
Best for: Comprehensive test strategy documents, standards documents, documentation that requires complex structure.
reStructuredText (rST)
The standard for Python documentation. Powerful but with the steepest learning curve.
Strengths:
- Native directives for complex content
- Excellent for API documentation (Sphinx integration)
- Strong cross-referencing
- Industry standard in Python ecosystem
Weaknesses:
- Unfamiliar syntax for most developers
- Less readable as plain text than Markdown
- Smaller community outside Python
Best for: Python-based test frameworks, projects that already use Sphinx.
Format Comparison
| Feature | Markdown | AsciiDoc | reStructuredText |
|---|---|---|---|
| Learning curve | Very low | Medium | High |
| Readability as plain text | Excellent | Good | Moderate |
| Tables | Basic | Advanced | Advanced |
| Includes / reuse | Extensions only | Native | Native |
| Admonitions | Extensions only | Native | Native |
| GitHub rendering | Excellent | Basic | Good |
| Static site generators | Many (Hugo, Jekyll, MkDocs, Docusaurus) | Antora | Sphinx |
| IDE support | Excellent | Good | Good |
Recommendation for most QA teams: Start with Markdown. It has the lowest barrier to adoption. Switch to AsciiDoc or rST only if you hit limitations that Markdown extensions cannot solve.
Documentation Generators
Docusaurus
React-based static site generator from Meta. Excellent for project documentation with versioning.
| Aspect | Details |
|---|---|
| Format | Markdown (MDX with React components) |
| Versioning | Built-in document versioning |
| Search | Algolia DocSearch integration |
| Best for | Product documentation, QA knowledge bases with versioning needs |
| Setup effort | Medium (requires Node.js) |
MkDocs (with Material theme)
Python-based, simple, fast. The Material theme adds a polished UI with excellent search.
| Aspect | Details |
|---|---|
| Format | Markdown |
| Search | Built-in full-text search |
| Extensions | Admonitions, tabs, code annotations, diagrams |
| Best for | QA teams that want simplicity and speed |
| Setup effort | Low (pip install mkdocs-material) |
GitBook
Commercial platform with a clean UI. Good for teams that want a hosted solution.
| Aspect | Details |
|---|---|
| Format | Markdown (edited through web UI or Git sync) |
| Collaboration | Real-time editing, comments, review |
| Best for | Teams that want a managed documentation platform |
| Setup effort | Very low (SaaS) |
| Cost | Free for open source, paid for teams |
Confluence
The most common enterprise wiki. Not strictly docs-as-code, but can be integrated.
| Aspect | Details |
|---|---|
| Format | Rich text editor (with Markdown import plugins) |
| Integration | Deep Jira integration, Atlassian ecosystem |
| Best for | Enterprise teams already in the Atlassian ecosystem |
| Limitation | Not version-controlled, no CI/CD, hard to keep in sync with code |
Test Documentation in the Repo
Co-Locating Test Docs with Test Code
The most effective place for test documentation is next to the tests themselves.
Repository structure example:
project/
├── src/
│ ├── checkout/
│ │ ├── checkout.ts
│ │ └── checkout.test.ts
│ └── payment/
│ ├── payment.ts
│ └── payment.test.ts
├── tests/
│ ├── e2e/
│ │ ├── checkout.spec.ts
│ │ └── README.md ← What these tests cover
│ ├── performance/
│ │ ├── load-test.js
│ │ └── README.md ← How to run, thresholds, history
│ └── test-data/
│ ├── fixtures/
│ └── README.md ← How test data works
├── docs/
│ ├── test-strategy.md ← Overall test strategy
│ ├── test-environments.md ← Environment setup guide
│ └── runbooks/
│ ├── deploy-verification.md
│ └── incident-response.md
└── README.md
Benefits of co-location:
- Developers see test documentation when they change test code
- Documentation changes are reviewed in the same PR as code changes
- Git blame shows who wrote the documentation and when
- Documentation is always version-matched with the code
What to Put in the Repo vs. External Wiki
| In the Repo | In the Wiki/External |
|---|---|
| Test strategy and approach | Meeting notes and decisions |
| How to run tests | Team processes and ceremonies |
| Test data documentation | Onboarding guides |
| Environment setup | Architecture decision records |
| Runbooks for automated processes | Troubleshooting guides (evolving) |
| API test documentation | Cross-team documentation |
Automating Documentation
Test Reports
Automated test reports generated by CI/CD pipelines provide up-to-date quality metrics without manual effort.
What to generate automatically:
| Report | Tool | Trigger |
|---|---|---|
| Unit test results | JUnit XML + report generator | Every CI run |
| E2E test results | Playwright HTML report, Allure | Every CI run |
| Code coverage | Istanbul/NYC, JaCoCo, coverage.py | Every CI run |
| API documentation | Swagger/OpenAPI generators | On API changes |
| Performance benchmarks | k6, Gatling, Locust reports | Nightly or weekly |
| Dependency audit | npm audit, Snyk, Dependabot | Daily |
| Test flakiness | Custom tracking or test analytics tools | Weekly |
Coverage Reports
Coverage reports can be generated and published automatically:
# Example GitHub Actions step
- name: Generate coverage report
run: npx nyc report --reporter=html --reporter=text
- name: Publish coverage to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./coverage
Documentation Linting
Automated checks that keep documentation quality high:
| Tool | What It Checks |
|---|---|
| markdownlint | Markdown formatting consistency |
| vale | Prose quality, style guide compliance |
| textlint | Grammar, spelling, readability |
| linkcheck | Broken links in documentation |
| cspell | Spell checking with custom dictionaries |
Example CI configuration for documentation linting:
# .github/workflows/docs.yml
name: Documentation Quality
on: pull_request
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint Markdown
uses: DavidAnson/markdownlint-cli2-action@v14
- name: Check links
uses: lycheeverse/lychee-action@v1
with:
args: --verbose docs/**/*.md
- name: Spell check
uses: streetsidesoftware/cspell-action@v5
Documentation Review Process
Who Reviews
| Documentation Type | Primary Reviewer | Secondary Reviewer |
|---|---|---|
| Test strategy | QA Lead | Engineering Manager |
| Test cases / plans | QA peer | Developer (for technical accuracy) |
| Runbooks | QA peer | DevOps (for operational accuracy) |
| API test documentation | QA author | API developer |
| Onboarding guides | Recent hire (validates accuracy) | QA Lead |
When to Review
- On change: Every documentation change goes through a PR review, just like code
- On schedule: Quarterly review of all active documentation for accuracy and relevance
- On trigger: When a related incident occurs, review relevant runbooks and documentation
How to Review Documentation
| Check | Question |
|---|---|
| Accuracy | Is the information correct and current? |
| Completeness | Is anything missing that a reader would need? |
| Clarity | Would someone unfamiliar with the context understand this? |
| Actionability | Can the reader follow these instructions successfully? |
| Consistency | Does it follow the team's style guide and templates? |
| Freshness | Is this still relevant? Are there references to deprecated tools or processes? |
Keeping Docs Fresh
Automated Staleness Detection
Set up systems that alert when documentation has not been updated in a defined period:
- Git-based: Script that checks the last commit date for each doc file and flags those older than 90 days
- Wiki-based: Confluence and Notion both support "last updated" tracking; some support automated reminders
- CI-based: Add a job that runs weekly and creates issues for stale documentation
Example staleness check script concept:
# Find documentation files not updated in 90 days
find docs/ -name "*.md" -mtime +90 -print
Ownership Model
Every document should have a designated owner. The owner is not necessarily the author -- they are the person responsible for keeping the document accurate.
| Role | Responsibility |
|---|---|
| Owner | Ensures the document stays accurate and relevant; reviews quarterly |
| Author | Wrote the original content; may no longer be the owner |
| Reviewers | Check accuracy when changes are proposed |
| Consumers | Report inaccuracies and suggest improvements |
Maintenance Schedules
| Documentation Type | Review Frequency | Trigger for Immediate Review |
|---|---|---|
| Test strategy | Quarterly | Major product change, new team member |
| Runbooks | Monthly | Related incident, process change |
| Onboarding guides | With each new hire | New hire feedback |
| Test environment docs | Monthly | Environment changes |
| Tool documentation | Quarterly | Tool version upgrades |
Hands-On Exercise
- Move one piece of test documentation from your wiki into your code repository. Set it up as a Markdown file in the appropriate location.
- Add a documentation linting step to your CI pipeline (markdownlint, link checking, or spell checking).
- Set up automated test report generation and publishing for your project.
- Create a documentation ownership table for your team's key documents. Identify any orphaned documents.
- Implement a staleness detection mechanism: either a script, a calendar reminder, or an automated check that flags documents older than 90 days.