LUNAROPS · OPERATIONAL UPLINK 100% UPTIME 1,247d POSTS 893 JEFF.MOON@LUNAROPS.DEV UTC --:--:--

Technical Writing for Developers

writingdocumentationcommunication

Good technical writing is a superpower. It scales your knowledge and helps your team move faster.

The Inverted Pyramid

Put the most important information first:

Most Important (what, why)
        ↓
Supporting Details (how)
        ↓
Background (context)

Don’t make readers wade through history to find what they need.

README Structure

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Project Name

One-line description of what this does.

## Quick Start

\`\`\`bash
npm install myproject
npm start
\`\`\`

## Features

- Feature 1
- Feature 2
- Feature 3

## Installation

Detailed installation steps...

## Usage

Examples of common use cases...

## Configuration

Available options...

## Contributing

How to contribute...

## License

MIT

Write for Scanning

People scan before they read:

  • Use headings liberally
  • Keep paragraphs short (3-4 sentences max)
  • Use bullet points
  • Bold key terms
  • Include code examples

Show, Don’t Just Tell

Weak:

The function accepts various parameters.

Strong:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def create_user(name: str, email: str, role: str = "user") -> User:
    """Create a new user.

    Args:
        name: Full name of the user
        email: Email address (must be unique)
        role: User role, defaults to "user"

    Returns:
        User: The created user object

    Example:
        >>> user = create_user("John Doe", "john@example.com")
        >>> user.role
        'user'
    """

Use Active Voice

Passive:

The configuration file should be edited by the user.

Active:

Edit the configuration file.

Be Specific

Vague:

This may cause performance issues.

Specific:

Processing more than 10,000 items may exceed the 5-second timeout.

Error Messages

Good error messages tell users what happened and what to do:

Bad:

Error: Invalid input

Good:

Error: Email address is invalid.
Expected format: user@example.com
Received: "not-an-email"

API Documentation

For each endpoint, include:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
## Create User

Creates a new user account.

**Endpoint:** `POST /api/users`

**Request:**
\`\`\`json
{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "securepassword"
}
\`\`\`

**Response:** `201 Created`
\`\`\`json
{
  "id": "user_123",
  "name": "John Doe",
  "email": "john@example.com",
  "created_at": "2026-01-09T10:00:00Z"
}
\`\`\`

**Errors:**
- `400 Bad Request` - Invalid input
- `409 Conflict` - Email already exists

Commit Messages

# Format
<type>: <subject>

<body>

<footer>

# Example
feat: add user authentication

Implement JWT-based authentication with refresh tokens.
Sessions expire after 24 hours of inactivity.

Closes #123

Types: feat, fix, docs, refactor, test, chore

Runbooks

For operational procedures:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Service X Restart Procedure

## When to Use

- Service is unresponsive
- Memory usage exceeds 90%

## Prerequisites

- Access to production servers
- Notify team in #ops channel

## Steps

1. Check current status
   \`\`\`
   systemctl status service-x
   \`\`\`

2. Graceful restart
   \`\`\`
   systemctl restart service-x
   \`\`\`

3. Verify service is healthy
   \`\`\`
   curl http://localhost:8080/health
   \`\`\`

## Troubleshooting

- If restart fails, check logs: `journalctl -u service-x`
- If still failing, escalate to on-call

## Rollback

Not applicable for restart.

Editing Checklist

  • Clear purpose in first paragraph
  • Scannable with headings
  • Code examples included
  • Active voice used
  • No jargon without explanation
  • Proofread for typos

Good writing takes practice. The more you write, the better you get.

Comments