Technical Writing for Developers
Write clear, maintainable developer documentation — from README files to full documentation sites.
1. Documentation Strategy
1.1 Diataxis framework
Organize documentation into four distinct types:
CODEBLOCK0
| Type | Goal | Example |
|---|
| Tutorial | Teach a beginner by doing | "Build your first API in 10 minutes" |
| How-to Guide |
Solve a specific problem | "How to add authentication" |
|
Reference | Provide technical facts | API endpoint docs, config options |
|
Explanation | Provide context and reasoning | "Why we chose PostgreSQL over MongoDB" |
1.2 Audience analysis
Before writing, answer:
- 1. Who is reading? (Beginner dev, senior engineer, DevOps, manager)
- What do they know already? (Prerequisites, assumed knowledge)
- Why are they reading? (Learn, solve problem, look up fact)
- Where will they read? (IDE, phone, printed, terminal)
1.3 Documentation lifecycle
CODEBLOCK1
- - Create: Write alongside the code it documents
- Review: Treat docs PRs like code PRs — review for accuracy and clarity
- Maintain: Update docs when code changes (enforce via CI)
- Deprecate: Mark outdated docs with warnings, link to replacements
- Archive: Move to an archive section rather than deleting
2. README Templates
2.1 Library / package README
INLINECODE0
2.2 CLI tool README
INLINECODE1
2.3 API service README
INLINECODE2
3. API Documentation
3.1 JSDoc / TSDoc patterns
CODEBLOCK19 ts
* const user = await getUser("550e8400-e29b-41d4-a716-446655440000");
* if (user) {
* console.log(user.name);
* }
* CODEBLOCK20
3.2 Common JSDoc/TSDoc tags
| Tag | Purpose | Example |
|---|
| INLINECODE3 | Document a parameter | INLINECODE4 |
| INLINECODE5 |
Document return value |
@returns The created resource |
|
@throws | Document exceptions |
@throws {NotFoundError} If resource missing |
|
@example | Provide usage example | Code block with usage |
|
@see | Cross-reference |
@see {@link OtherFunction} |
|
@since | Version introduced |
@since 2.0.0 |
|
@deprecated | Mark as deprecated |
@deprecated Use newFunction instead |
|
@default | Default value |
@default false |
|
@remarks | Additional context | Extended explanation |
|
@internal | Not part of public API | Excluded from generated docs |
3.3 Python docstrings (Google style)
CODEBLOCK21
3.4 Generating docs from code
| Tool | Language | Command |
|---|
| typedoc | TypeScript | INLINECODE20 |
| sphinx-autodoc |
Python |
sphinx-apidoc -o docs/api src/ |
| rustdoc | Rust |
cargo doc --open |
| godoc | Go |
go doc -all ./... |
| javadoc | Java |
javadoc -d docs src/**/*.java |
4. Architecture Decision Records (ADRs)
4.1 Why ADRs matter
ADRs capture the why behind architectural decisions. Code shows what; ADRs explain why that approach was chosen over alternatives.
4.2 ADR template
INLINECODE25
4.3 ADR file organization
CODEBLOCK23
4.4 ADR tooling
CODEBLOCK24
5. RFCs (Request for Comments)
5.1 RFC vs ADR
| Aspect | ADR | RFC |
|---|
| Scope | Single decision | Larger design proposal |
| Length |
1-2 pages | 3-10+ pages |
| Process | Lightweight | Formal review period |
| Audience | Future maintainers | Current team for input |
| Timing | During/after decision | Before implementation |
5.2 RFC template
INLINECODE26
6. Changelogs
6.1 Keep a Changelog format
INLINECODE27
6.2 Changelog categories
| Category | When to use |
|---|
| Added | New features |
| Changed |
Changes in existing functionality |
|
Deprecated | Soon-to-be removed features |
|
Removed | Removed features |
|
Fixed | Bug fixes |
|
Security | Vulnerability fixes |
6.3 Automated changelogs
CODEBLOCK29
7. Runbooks and Playbooks
7.1 Incident response runbook template
INLINECODE28
7.2 Post-mortem template
INLINECODE29
8. Diagram-as-Code
8.1 Mermaid — Sequence diagram
INLINECODE30
8.2 Mermaid — Architecture (C4-style)
INLINECODE31
8.3 Mermaid — Entity Relationship
INLINECODE32
8.4 Mermaid — Flowchart
INLINECODE33
8.5 Mermaid — State diagram
INLINECODE34
8.6 D2 diagrams
CODEBLOCK46
8.7 ASCII art diagrams (for inline code comments)
CODEBLOCK47
9. Writing Style Guide
9.1 Core principles
| Principle | Bad | Good |
|---|
| Be direct | "It should be noted that the function might return null" | "The function returns null if the user is not found" |
| Use active voice |
"The configuration file is read by the server" | "The server reads the configuration file" |
|
Use present tense | "This command will create a directory" | "This command creates a directory" |
|
Address the reader | "One should configure the timeout" | "Configure the timeout in
config.yml" |
|
Be specific | "Set the timeout to a reasonable value" | "Set the timeout to
30000 (30 seconds)" |
|
Avoid jargon | "Hydrate the SSR payload" | "Load the server-rendered data on the client" |
9.2 Formatting conventions
| Element | Format | Example |
|---|
| File paths | Inline code | INLINECODE38 |
| CLI commands |
Code block |
npm install |
| Config values | Inline code | Set
timeout to
5000 |
| First mention of a term |
Bold |
Service worker is a background script... |
| UI elements |
Bold | Click
Settings >
Advanced |
| Keyboard shortcuts |
Kbd style | Press
Ctrl+S to save |
| Variable names | Inline code | The
userId parameter |
| Status/state | Inline code | The request returns
200 OK |
9.3 Sentence structure
- - One idea per sentence. Split long sentences at conjunctions.
- Lead with the action. "Run
npm install" not "You need to run npm install" - Put conditions before instructions. "If using TypeScript, add a
tsconfig.json" not "Add a tsconfig.json if using TypeScript" - Use numbered lists for sequential steps. Use bullet lists for unordered items.
9.4 Inclusive language
| Avoid | Use instead |
|---|
| master/slave | primary/replica, leader/follower |
| whitelist/blacklist |
allowlist/blocklist |
| sanity check | confidence check, quick check |
| dummy value | placeholder value, sample value |
| he/she | they |
| simple/easy | straightforward |
10. Documentation Site Generators
10.1 Comparison
| Feature | Docusaurus | Starlight | MkDocs Material | VitePress |
|---|
| Framework | React | Astro | Python/Jinja | Vue |
| Setup effort |
Low | Low | Low | Low |
| Versioning | Built-in | Plugin | Plugin (mike) | Manual |
| Search | Algolia/local | Pagefind | Built-in | MiniSearch |
| i18n | Built-in | Built-in | Plugin | Manual |
| MDX support | Yes | Yes | No (but extensions) | Yes |
| Build speed | Medium | Fast | Fast | Fast |
| Best for | Large docs sites | Modern docs | Python projects | Vue ecosystem |
10.2 Docusaurus quick start
CODEBLOCK48
CODEBLOCK49
10.3 Starlight (Astro) quick start
CODEBLOCK50
10.4 VitePress quick start
CODEBLOCK51
11. Docs-as-Code Workflow
11.1 CI checks for documentation
CODEBLOCK52
11.2 markdownlint configuration
CODEBLOCK53
11.3 cspell configuration
CODEBLOCK54
12. Code Examples in Documentation
12.1 Principles
- 1. Runnable — examples should work if copy-pasted
- Realistic — use domain-relevant variable names, not
foo/ INLINECODE51 - Progressive — start simple, add complexity gradually
- Complete — show imports, setup, and cleanup
- Tested — run examples in CI to prevent rot
12.2 Example structure
CODEBLOCK55
12.3 Testing code examples
CODEBLOCK56
13. Common Pitfalls
| Pitfall | Impact | Fix |
|---|
| Writing docs after the project is "done" | Docs never get written; knowledge is lost | Write docs alongside code, in the same PR |
| No clear audience |
Docs try to serve everyone, serve no one | State prerequisites and audience at the top |
| Tutorial disguised as reference | Beginners get lost in details; experts skip it | Separate tutorials from reference docs (Diataxis) |
| Undocumented prerequisites | Users fail at step 1 | List all required tools, versions, and setup steps |
| Stale code examples | Users copy broken code, lose trust | Test code examples in CI; pin dependency versions |
| Screenshots without alt text | Accessibility failure; breaks if image URL changes | Always add descriptive alt text; prefer text over screenshots |
| No changelog | Users don't know what changed between versions | Maintain a CHANGELOG.md; automate from conventional commits |
| Docs not in version control | No review process, no history, no blame | Store docs in the same repo as code |
| Wall of text | Readers skim and miss key information | Use headings, lists, tables, code blocks; chunk information |
| Assuming context | New readers don't have your mental model | Link to prerequisite docs; explain acronyms on first use |
| No search | Users can't find what they need | Use Algolia, Pagefind, or built-in search in doc generators |
| Broken internal links | Readers hit dead ends | Run link checker in CI (lychee, markdown-link-check) |
| Mixing instructions with explanation | Readers lose track of what to do | Put context in a separate section; keep steps action-only |
| No contribution guide | Only the original author updates docs | Add CONTRIBUTING.md with docs guidelines |
| Translating literally | Translated docs read unnaturally | Use i18n tools (Crowdin); have native speakers review |
| Over-documenting internal code | Maintenance burden with no external benefit | Document public APIs; use
@internal for private code |
面向开发者的技术写作
编写清晰、可维护的开发者文档——从README文件到完整的文档站点。
1. 文档策略
1.1 Diataxis框架
将文档组织为四种不同类型:
实践型 理论型
(需遵循的步骤) (理解型)
┌─────────────────────┬─────────────────────────┐
学习型 │ 教程 │ 解释 │
(学习) │ 面向学习 │ 面向理解 │
│ 手把手指导 │ 背景、上下文 │
├─────────────────────┼─────────────────────────┤
工作型 │ 操作指南 │ 参考 │
(应用) │ 面向任务 │ 面向信息 │
│ 解决问题 │ 精确、准确、完整 │
└─────────────────────┴─────────────────────────┘
| 类型 | 目标 | 示例 |
|---|
| 教程 | 通过实践教会初学者 | 10分钟构建你的第一个API |
| 操作指南 |
解决特定问题 | 如何添加身份验证 |
|
参考 | 提供技术事实 | API端点文档、配置选项 |
|
解释 | 提供背景和理由 | 为什么我们选择PostgreSQL而非MongoDB |
1.2 受众分析
在写作之前,回答以下问题:
- 1. 谁在阅读?(初级开发者、高级工程师、运维人员、管理者)
- 他们已经知道什么?(前置条件、假定知识)
- 为什么他们在阅读?(学习、解决问题、查找事实)
- 在哪里阅读?(IDE、手机、打印版、终端)
1.3 文档生命周期
创建 → 审查(PR)→ 发布 → 维护 → 弃用 → 归档
↑ │
└────────────────────┘
(更新周期)
- - 创建:与所记录的代码同步编写
- 审查:将文档PR视为代码PR——审查准确性和清晰度
- 维护:代码变更时更新文档(通过CI强制执行)
- 弃用:用警告标记过时的文档,链接到替代方案
- 归档:移至归档部分而非删除
2. README模板
2.1 库/包README
markdown
库名称
该库功能的一行描述。



功能特性
- - 功能一 — 简要描述
- 功能二 — 简要描述
- 功能三 — 简要描述
安装
bash
npm install 库名称
快速开始
ts
import { something } from 库名称;
const result = something({ option: true });
console.log(result);
使用说明
基本用法
ts
// 展示最常见用例的最小示例
高级用法
ts
// 展示配置选项、边界情况或组合的示例
API参考
functionName(options)
| 参数 | 类型 | 默认值 | 描述 |
|---|
| option1 | string | — | 必需。描述。 |
| option2 |
boolean | false | 可选。描述。 |
返回: ResultType — 返回值的描述。
示例:
ts
const result = functionName({ option1: value });
配置
| 选项 | 类型 | 默认值 | 描述 |
|---|
| debug | boolean | false | 启用调试日志 |
| timeout |
number | 5000 | 请求超时时间(毫秒) |
贡献指南
请参阅 CONTRIBUTING.md 了解开发设置和指南。
许可证
MIT
2.2 CLI工具README
markdown
my-cli
该CLI功能的一行描述。
安装
bash
npm
npm install -g my-cli
Homebrew
brew install my-cli
二进制文件
curl -fsSL https://get.my-cli.dev | sh
快速开始
bash
初始化一个新项目
my-cli init my-project
运行主命令
my-cli run --config config.yml
命令
my-cli init [name]
创建一个新项目。
bash
my-cli init my-project --template minimal
| 标志 | 简写 | 默认值 | 描述 |
|---|
| --template | -t | default | 项目模板 |
| --force |
-f | false | 覆盖现有文件 |
my-cli run
运行主进程。
bash
my-cli run --config custom.yml --verbose
| 标志 | 简写 | 默认值 | 描述 |
|---|
| --config | -c | config.yml | 配置文件路径 |
| --verbose |
-v | false | 详细输出 |
| --dry-run | | false | 显示将要执行的操作 |
配置文件
yaml
config.yml
output: dist
verbose: false
plugins:
- name: plugin-a
option: value
环境变量
| 变量 | 默认值 | 描述 |
|---|
| MYCLICONFIG | config.yml | 配置文件路径 |
| MYCLILOG_LEVEL |
info | 日志级别 |
退出码
一般错误 |
| 2 | 无效参数 |
| 3 | 未找到配置文件 |
2.3 API服务README
markdown
My API
用于管理小部件的REST API。
基础URL: https://api.example.com/v1
身份验证
所有请求都需要Bearer令牌:
bash
curl -H Authorization: Bearer YOUR_TOKEN https://api.example.com/v1/widgets
快速开始
bash
创建一个小部件
curl -X POST https://api.example.com/v1/widgets \
-H Authorization: Bearer $TOKEN \
-H Content-Type: application/json \
-d {name: My Widget, color: blue}
端点
| 方法 | 路径 | 描述 |
|---|
| GET | /widgets | 列出所有小部件 |
| POST |
/widgets | 创建小部件 |
| GET | /widgets/:id | 获取小部件 |
| PATCH | /widgets/:id | 更新小部件 |
| DELETE | /widgets/:id | 删除小部件 |
错误响应
所有错误遵循RFC 7807:
json
{
type: https://api.example.com/errors/not-found,
title: Not Found,
status: 404,
detail: Widget with ID abc not found
}
速率限制
600 |
SDK
本地运行
bash
git clone https://github.com/org/my-api.git
cd my-api
cp .env.example .env
docker compose up -d
npm run dev
3. API文档
3.1 JSDoc / TSDoc模式
ts
/
* 通过唯一标识符获取用户。
*
* @param id - 用户唯一标识符(UUID格式)
* @returns 用户对象,如果未找到则返回 null
* @throws {AuthenticationError} 如果请求未通过身份验证
* @throws {RateLimitError} 如果超出速率限制
*
* @example
* ts
* const user = await getUser(550e8400-e29b-41d4-a716-446655440000);