6.1 五类技术文档的结构差异
程序员每天读的英文文档大致分五类,它们的写作传统、密度、目标读者都不同。把它们当作同一种文体读是低效的。
| 类型 | 典型来源 | 密度 | 读法 |
|---|---|---|---|
| RFC / spec | IETF, W3C, ECMAScript | 极高(每一字都重要) | 逐字、对照术语表 |
| API 文档 | MDN, Stripe, AWS | 中(参数表 + 示例) | 查阅式,先看 example |
| man page | UNIX 手册 | 中等密度 | SYNOPSIS → DESCRIPTION → EXAMPLES |
| 论文 | arXiv, ACM, USENIX | 高(带数学) | 速读法(见 6.4) |
| 源码注释 | 项目 README, godoc | 低 | 顺读 |
下面我们逐类拆解。
6.2 RFC:MUST / SHOULD / MAY 关键词系统
RFC(Request for Comments)是互联网协议的"圣经"。例如:
- RFC 2616 / 7230 / 9110 — HTTP
- RFC 5321 — SMTP
- RFC 6749 — OAuth 2.0
- RFC 7519 — JWT
- RFC 8259 — JSON
RFC 写作有一份"元规范"——BCP 14 / RFC 2119 / RFC 8174——规定了几个关键词的精确含义。这些关键词在 RFC 文本里大写出现:
| 关键词 | 等价 | 含义 |
|---|---|---|
MUST | REQUIRED, SHALL | 绝对要求,必须实现 |
MUST NOT | SHALL NOT | 绝对禁止 |
SHOULD | RECOMMENDED | 强烈建议;除非有充分理由不做 |
SHOULD NOT | NOT RECOMMENDED | 强烈不建议 |
MAY | OPTIONAL | 可选;不实现也合规 |
实例(HTTP RFC 7230):
"A server MUST NOT send a response containing Transfer-Encoding
unless the corresponding request indicates HTTP/1.1 (or later)."
"A client SHOULD send a Host header field in all HTTP/1.1 request
messages."
"A user agent MAY attempt to recover from such an error condition."
这三句话有完全不同的法律意义:第一句违反 = bug;第二句违反 = 允许但不推荐;第三句做不做都行。读 RFC 时如果忽略大小写,等于完全没读懂。
RFC 阅读顺序
不要从头读。推荐顺序:
- Abstract(摘要):5 行内的目的陈述。
- Status of This Memo:是 Internet Standard 还是 Informational?
- Table of Contents:扫一遍框架。
- Introduction:动机和背景。
- Terminology:必读,定义后续所有术语。
- Examples(如有):直接抓住协议的样子。
- 核心章节按需读,遇到不懂的术语回到 Terminology 查。
- Security Considerations:安全要点(最容易忽略的部分)。
RFC 高频句型
# 定义术语
"For the purposes of this document, the following terms are used:"
# 设定边界
"This specification does not define ..."
"The mechanism described herein is intended for ..."
# 正式禁止
"Implementations MUST NOT rely on ..."
# 警告
"It is RECOMMENDED that implementations ..."
# 引用其他 RFC
"... as described in [RFC7234] Section 5.2 ..."
# 表示弃用
"The use of this header is deprecated; see Section X for migration."
6.3 API 文档:先看 example,后看 spec
大多数现代 API 文档遵循类似 Stripe / GitHub 的结构:
1. Endpoint description — 一句话说明
2. URL — POST /v1/charges
3. Parameters — 表格列出所有参数
4. Returns — 返回什么
5. Errors — 可能的错误
6. Examples — curl, code snippets
7. Webhooks / Events (如有)
读 API 文档的高效顺序:example → parameters → errors → spec。这与 RFC 完全相反——API doc 是"查阅式"文档,目的是让你快速调通。
关键词识别
# 必填 vs 可选
required # 必填
optional # 可选
nullable # 可为空
deprecated # 已废弃,下个 major 版本会移除
beta / alpha # 实验性,可能变
preview # 预览版
# 数据类型术语
string, integer, boolean, array, object,
timestamp (Unix epoch / ISO 8601),
enum (枚举),
union (多类型),
recursive (递归结构)
# 行为修饰词
idempotent # 幂等:重复调用结果相同
atomic # 原子性
eventually consistent # 最终一致
strongly typed # 强类型
backward compatible # 向后兼容
breaking change # 不兼容变更
# 限制
rate limit # 速率限制
quota # 配额
throttling # 节流
pagination # 分页 (cursor / offset / page-based)
Stripe API doc 实例分析
POST /v1/charges
Creates a new charge object.
Parameters
─────────
amount integer REQUIRED
A positive integer representing how much to charge in
the smallest currency unit (e.g., 100 cents to charge
$1.00).
currency string REQUIRED
Three-letter ISO currency code, in lowercase. Must be
a supported currency.
source string OPTIONAL
A payment source to be charged. ...
Returns
───────
Returns a charge object if the charge succeeded.
Errors
──────
402 card_declined - The card was declined.
402 insufficient_funds - The card has insufficient funds.
注意几个英文写作细节:
- "in the smallest currency unit" — 用具体例子 (100 cents = $1.00) 而不是抽象描述。
- "Must be a supported currency" — Must 在 API doc 里通常等价于 RFC 的 MUST。
- 错误码的描述用过去时("was declined", "has insufficient")— 描述客观事实。
6.4 论文速读法
程序员读论文的目的不是"完全理解"——是"判断这个想法对我有没有用"。S. Keshav 的经典论文《How to Read a Paper》提出三遍阅读法:
第一遍:5-10 分钟
- 读 Title + Abstract + Introduction
- 跳过 Related Work 和数学
- 读 Section / Subsection 标题(不读内容)
- 看 所有 Figures + Tables
- 读 Conclusion
- 瞄一眼 References,标记自己已读过的
第一遍后你应该能回答 "5 个 C":
- Category:这是什么类型的论文?(measurement, system, theory)
- Context:和哪些工作相关?
- Correctness:假设看起来合理吗?
- Contributions:主要贡献是什么?
- Clarity:写得好吗?
如果第一遍后判断 "对我没用",就停在这里。
第二遍:1 小时
- 仔细读 figure 的 caption,理解 axis 标签、线条含义。
- 读关键章节(通常是 method / approach)。
- 跳过证明的细节,但要看清算法步骤。
- 把不懂的术语标出来,但不查——继续读,看上下文能否推断。
第三遍:4-5 小时
如果你需要复现这篇论文:把自己当成作者,逐句重建论证。这一遍才需要查所有不懂的术语。
论文常见英文句型
# Introduction 开场
"In recent years, X has become increasingly important ..."
"Despite significant progress in X, the problem of Y remains ..."
"X is a fundamental problem in Y ..."
# 表达贡献
"In this paper, we present / propose / introduce ..."
"Our key insight is that ..."
"Our contributions are threefold: (1) ... (2) ... (3) ..."
"To the best of our knowledge, this is the first work to ..."
# 实验描述
"We evaluate our approach on ..."
"Our method outperforms the baseline by X% on Y benchmark."
"Compared to prior work [REF], our approach achieves ..."
# 局限性(必读)
"Our approach has several limitations. First, ..."
"We leave the extension to ... as future work."
# 结论
"In conclusion, we have shown that ..."
"This work opens up several directions for future research ..."
6.5 Changelog 和 Release Notes
读 changelog 是工程师每天都做的事——升级依赖、追踪 breaking changes。Keep a Changelog(https://keepachangelog.com)规范定义了 7 种条目:
| 类别 | 含义 |
|---|---|
Added | 新功能 |
Changed | 已有功能的变化 |
Deprecated | 即将移除 |
Removed | 已移除 |
Fixed | bug 修复 |
Security | 安全修复 |
Performance | 性能改进(非标准但常见) |
升级时的关注点:Removed → Deprecated → Changed → Security → Added → Fixed。前三类决定你要不要改代码。
常见 Release Note 关键句
# 重要性标记
🚨 BREAKING CHANGE: ...
⚠️ Deprecation notice: ...
🔒 Security fix: CVE-2024-XXXX
# 描述变化
"X is now Y" # 正面陈述
"X has been replaced by Y" # 替换
"X is no longer supported" # 不再支持
"X has been moved to Y" # 迁移
# 迁移指南
"To upgrade, run ..."
"You will need to update your config from X to Y."
"See the migration guide at ..."
# 致谢
"Special thanks to @username for ..."
"This release was made possible by contributions from ..."
6.6 Stack Trace / 错误信息的英文
错误信息是程序员每天读的英文 — 但很多人没系统化它的词汇。
常见错误类型词汇
| 词 | 含义 | 典型语言 |
|---|---|---|
NullPointerException / NPE | 空指针 | Java |
nil pointer dereference | 解引用 nil | Go |
SegFault / SIGSEGV | 段错误 | C, C++ |
panic | 不可恢复运行时错误 | Go, Rust |
OOM / Out of Memory | 内存耗尽 | 所有 |
Stack Overflow | 栈溢出(递归过深) | 所有 |
TLE (Time Limit Exceeded) | 超时 | 算法 / OJ |
Race condition | 竞态 | 并发 |
Deadlock | 死锁 | 并发 |
Livelock | 活锁(一直让步) | 并发 |
Heisenbug | 观察就消失的 bug | 调试 |
Memory leak | 内存泄漏 | 所有 |
Buffer overflow | 缓冲区溢出 | C/C++ |
Use after free | 释放后使用 | C/C++ |
Double free | 重复释放 | C/C++ |
Dangling pointer | 悬垂指针 | C/C++ |
Type mismatch | 类型不匹配 | 类型语言 |
Cannot find module | 找不到模块 | JS/TS |
Undefined is not a function | 调用了 undefined | JS |
Connection refused | 连接被拒 | 网络 |
Connection reset | 连接被重置 | 网络 |
Read timeout | 读超时 | I/O |
Permission denied | 权限不足 | OS |
No such file or directory | 文件不存在 | OS |
典型 Stack Trace 拆解
Traceback (most recent call last):
File "app.py", line 42, in <module>
main()
File "app.py", line 28, in main
user = fetch_user(user_id)
File "/lib/api.py", line 156, in fetch_user
return _parse(response.json())
File "/lib/parser.py", line 89, in _parse
return User(**data["user"])
KeyError: 'user'
读法:
- 从最下面看类型:
KeyError: 'user'— 字典里没有 'user' 键。 - 从下往上看调用栈:是在
_parse函数访问data["user"]时报的错。 - 触发点是
app.pyline 42 → main → fetch_user。
"most recent call last" 是 Python 默认顺序——栈底是错误源头,栈顶是入口。Java/Go 默认顺序相反(最新调用在最上)。读栈一定要先确认顺序。
6.7 源码注释:@param / @return / @throws / @deprecated / @since
大多数语言有自己的 doc comment 风格,但标签语义高度一致:
| 标签 | 含义 | 示例 |
|---|---|---|
@param | 参数说明 | @param id The user ID |
@returns / @return | 返回值 | @returns The user object |
@throws / @raises | 可能抛出的异常 | @throws NotFoundError if user missing |
@deprecated | 已废弃 | @deprecated Use newApi() instead |
@since | 引入版本 | @since 2.4.0 |
@see | 参考 | @see RelatedClass |
@example | 用法示例 | 跟着代码块 |
@todo | 待办 | @todo handle empty case |
@override | 覆盖父类 | Java/TS |
@inheritDoc | 继承父注释 | Java |
@author | 作者 | 逐渐被 git blame 替代 |
@version | 版本 | 同上 |
@link | 跨链接 | {@link OtherClass} |
@internal | 内部 API | 不建议外部用 |
@beta | 实验性 | API 可能变 |
JSDoc 实例
/**
* Fetches a user by their ID, optionally including related orders.
*
* @param id - The user's unique identifier (UUID v4).
* @param options - Optional fetch options.
* @param options.includeOrders - If true, also fetches orders. Defaults to false.
* @returns A promise that resolves to the user object.
* @throws {NotFoundError} If no user with the given ID exists.
* @throws {NetworkError} If the underlying HTTP call fails.
* @example
* const user = await fetchUser('abc-123', { includeOrders: true });
* @since 2.4.0
* @see {@link User}
*/
async function fetchUser(id, options = {}) { ... }
Python docstring(Google 风格)
def fetch_user(id: str, include_orders: bool = False) -> User:
"""Fetches a user by their ID, optionally including related orders.
Args:
id: The user's unique identifier (UUID v4).
include_orders: If True, also fetches orders. Defaults to False.
Returns:
The user object.
Raises:
NotFoundError: If no user with the given ID exists.
NetworkError: If the underlying HTTP call fails.
Example:
>>> user = fetch_user('abc-123', include_orders=True)
.. versionadded:: 2.4.0
"""
6.8 man page 阅读
UNIX man page 有固定结构,每节都是缩写:
$ man grep
NAME # 命令名 + 一句话功能
grep, egrep, fgrep - print lines matching a pattern
SYNOPSIS # 用法语法(最重要)
grep [OPTIONS] PATTERN [FILE...]
DESCRIPTION # 详细行为
grep searches the named input FILEs for lines matching ...
OPTIONS # 所有 flag
-i, --ignore-case
Ignore case distinctions ...
EXAMPLES # 例子
grep -i 'error' app.log
EXIT STATUS # 退出码
0 if any line was selected, 1 otherwise.
SEE ALSO # 相关命令
awk(1), sed(1), regex(7)
BUGS # 已知问题
AUTHOR
COPYRIGHT
SYNOPSIS 的语法符号:
[ ]:可选...:可重复|:或UPPERCASE:占位(用户提供值)lowercase:字面量(直接输入)
SEE ALSO 后的数字 (1) (7) 是 man 区段:
- 1 — 用户命令(grep, ls, cat)
- 2 — 系统调用(open, read)
- 3 — 库函数(printf, malloc)
- 5 — 文件格式(passwd, fstab)
- 7 — 杂项(regex, signal)
- 8 — 系统管理(mount, useradd)
6.9 阅读训练建议
- 每周读一篇 RFC——从你日常用的协议开始(HTTP、OAuth、JSON)。
- 每周读一份 release notes——选你项目里依赖最重的库(React、Postgres、Kubernetes)。
- 每周读一个 stack trace——刻意拿别人 issue 里的 trace 练读栈。
- 每月读一篇论文——用三遍法。
- 遇到不认识的术语,立即查
https://www.computerhope.com/jargon.htm或维基百科英文版。
读得多,写就好。技术文档阅读是程序员英语中"性价比最高"的训练——它直接构成你日常工作输入,每天都做。
6.10 本章小结
- 五类文档结构差异大:RFC 逐字 / API 查阅 / man page 节段 / 论文三遍 / 源码顺读。
- RFC 的 BCP 14 关键词(MUST/SHOULD/MAY)有法律级语义。
- API 文档先看 example,关注 required/optional/deprecated/idempotent/rate limit。
- 论文三遍法:5-10 分钟 → 1 小时 → 4-5 小时。
- Stack trace:栈底是源头,栈顶是入口(Python)/ 反之(Java/Go)。
- doc comment 标签:
@param/@returns/@throws/@deprecated/@since/@see/@example。 - man page 五节:NAME / SYNOPSIS / DESCRIPTION / OPTIONS / EXAMPLES。
下一章我们换到"输出"端——技术写作。