Good documentation is crucial for team success. This comprehensive guide covers best practices for creating and maintaining technical documentation.
Types of Documentation
Documentation Pyramid
flowchart TD
A[API Reference] --> B[Code Examples]
B --> C[Guides & Tutorials]
C --> D[Conceptual Docs]
D --> E[Architecture]
A -.- F[Code First]
E -.- G[Start Here]
style A fill:#e3f2fd
style B fill:#bbdefb
style C fill:#90caf9
style D fill:#64b5f6
style E fill:#42a5f5
README Files
Project README
# Project Name
Brief description of what this project does.
## Features
- Feature 1
- Feature 2
- Feature 3
## Quick Start
```bash
npm install my-project
npm start
Installation
npm install my-project
Usage
import { myFunction } from 'my-project';
const result = myFunction('hello');
console.log(result);
API
myFunction(input)
| Parameter | Type | Description |
|---|---|---|
| input | string | Input description |
Returns: string
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
License
MIT
### Component README
```markdown
# Button Component
A button component with multiple variants.
## Usage
```jsx
import { Button } from './components/Button';
function App() {
return (
<Button variant="primary" onClick={() => {}}>
Click Me
</Button>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | ‘primary’ \| ‘secondary’ | ‘primary’ | Button style |
| size | ‘sm’ \| ‘md’ \| ’lg’ | ‘md’ | Button size |
| disabled | boolean | false | Disabled state |
| onClick | () => void | - | Click handler |
Examples
Primary Button
<Button variant="primary">Primary</Button>
Secondary Button
<Button variant="secondary">Secondary</Button>
Accessibility
- Keyboard navigable
- ARIA labels included
- Focus indicators
## Architectural Decision Records (ADRs)
### ADR Template
```markdown
# ADR-001: Use PostgreSQL as Primary Database
## Status
Accepted
## Context
We need to choose a primary database for our application. Options include:
- PostgreSQL
- MySQL
- MongoDB
## Decision
We will use PostgreSQL.
## Consequences
### Positive
- Strong ACID compliance
- Excellent JSON support
- Great ecosystem
- Strong community
### Negative
- Requires more setup than SQLite
- Horizontal scaling needs more work
## Notes
- Reviewed on: 2024-01-15
- Last updated: 2024-02-01
ADR Index
# Architectural Decision Records (ADR)
| ADR | Title | Status | Date |
|-----|-------|--------|------|
| 001 | Use PostgreSQL | Accepted | 2024-01-15 |
| 002 | Use React | Accepted | 2024-01-20 |
| 003 | Use GraphQL | Proposed | 2024-02-01 |
| 004 | Use AWS | Accepted | 2024-02-05 |
Code Comments
Good Comments
// Calculate discount based on user tier
// Users with 10+ orders get 20% off
function calculateDiscount(user) {
if (user.orderCount >= 10) {
return 0.20;
}
return 0;
}
// Handle API rate limiting
// Exponential backoff: 1s, 2s, 4s, 8s...
async function fetchWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fetch(url);
} catch (error) {
if (i === maxRetries - 1) throw error;
await sleep(Math.pow(2, i) * 1000);
}
}
}
JSDoc Comments
/**
* Calculates the total price including tax and discounts.
*
* @param {number} basePrice - The original price before tax/discount
* @param {Object} options - Calculation options
* @param {number} options.taxRate - Tax rate as decimal (0.1 = 10%)
* @param {number} [options.discount=0] - Discount as decimal
* @returns {number} Final calculated price
*
* @example
* calculateTotal(100, { taxRate: 0.1, discount: 0.1 }); // 99
*
* @since 1.2.0
* @deprecated Use calculatePrice instead
*/
function calculateTotal(basePrice, options) {
const { taxRate, discount = 0 } = options;
return basePrice * (1 + taxRate) * (1 - discount);
}
TypeScript Documentation
interface User {
/** Unique identifier */
id: string;
/** User's display name */
name: string;
/** Email address */
email: string;
/** When user was created */
readonly createdAt: Date;
}
/**
* Creates a new user in the system.
*
* @param data - User creation data
* @returns Created user with generated ID
* @throws {ValidationError} When data is invalid
*
* @example
* const user = await createUser({
* name: 'John',
* email: '[email protected]'
* });
*/
async function createUser(data: CreateUserInput): Promise<User>
API Documentation
OpenAPI/Swagger
openapi: 3.0.0
info:
title: User API
version: 1.0.0
paths:
/users:
get:
summary: List users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
pagination:
$ref: '#/components/schemas/Pagination'
components:
schemas:
User:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
format: email
Gitbook/MkDocs
Structure
docs/
โโโ index.md
โโโ getting-started/
โ โโโ installation.md
โ โโโ quick-start.md
โ โโโ configuration.md
โโโ guides/
โ โโโ authentication.md
โ โโโ deployment.md
โ โโโ troubleshooting.md
โโโ api/
โ โโโ users.md
โ โโโ orders.md
โโโ reference/
โโโ cli-commands.md
โโโ environment-variables.md
Navigation (mkdocs.yml)
nav:
- Home: index.md
- Getting Started:
- Installation: getting-started/installation.md
- Quick Start: getting-started/quick-start.md
- Guides:
- Authentication: guides/authentication.md
- Deployment: guides/deployment.md
- API Reference:
- Users: api/users.md
- CLI:
- Commands: reference/cli-commands.md
Writing Style
Be Clear and Concise
<!-- Bad -->
The functionality of this method is to iterate through the array and return the first element that matches the predicate.
<!-- Good -->
Returns the first array element that matches the predicate.
Use Examples
<!-- Good with example -->
To create a user:
```javascript
const user = await createUser({
name: 'John',
email: 'john@example.com'
});
Include Context
<!-- Good -->
Use `process.env.NODE_ENV` to check the environment:
- `development`: Local development
- `staging`: Testing environment
- `production`: Live environment
Tools
Documentation Generators
| Tool | Description |
|---|---|
| JSDoc | Generates API docs from code |
| Docusaurus | React-based documentation |
| GitBook | Collaborative docs |
| MkDocs | Python-based, Markdown |
| Starlight | Astro-based docs |
JSDoc Example
// jsdoc.json
{
"source": {
"include": ["src"]
},
"opts": {
"destination": "./docs",
"template": "node_modules/docdash"
},
"plugins": ["plugins/markdown"]
}
Maintenance
Review Checklist
## Documentation Review
- [ ] All public APIs documented
- [ ] Code examples tested
- [ ] Links work
- [ ] Spelling/grammar correct
- [ ] Diagrams up-to-date
- [ ] Version numbers current
- [ ] Examples run without errors
Automation
# .github/workflows/docs.yml
name: Documentation
on:
push:
branches: [main]
paths: ['docs/**']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install mkdocs-material
- run: mkdocs gh-deploy --force
External Resources
Conclusion
Good documentation:
- Is clear and concise
- Includes practical examples
- Stays up-to-date
- Is easy to navigate
- Answers common questions
Invest in documentation - it saves time in the long run.
Comments