# 第 8 章 · 胸有成竹

> 系统编程到底要多久？工作量是规模的 1.5 次幂，生产率随交互密度与任务复杂度差出十倍，而高级语言能换来 5 倍。

---

LLMS 索引： [llms.txt](/llms.txt)

---

题记两句话放在一起很有意思：普布里乌斯说"实践是最好的老师"，《穷理查年鉴》补上一句——"实践是最好的老师，但智者还能从其他的地方有所收获。"这一章就是作者试图从别人的实践里收获的部分。

## 这一章讲了什么 {#summary}

开篇两个警告，都是针对估算里最常见的偷懒方式。

第一，**不能只估编码再套比率**。编码只占整个问题的六分之一左右，编码估计或比率上的误差，放大到整任务上就是荒谬的结论。

第二，**不能拿小型独立程序的数据外推**。他引 Sackman 等人的报告：规模平均 3200 条指令的程序，单个程序员编码加调试约 178 小时，外推得到每年 35800 条语句；而规模只有一半的程序，花费时间大约只有前者的四分之一，推出来的生产率接近每年 80000 行。"计划、编制文档、测试、系统集成和培训的时间必须被考虑在内"，所以这种外推毫无意义——他用了一个很妙的类比："就好像把 100 米短跑记录外推，得出人类可以在 3 分钟之内跑完 1 英里一样。"

把这两条警告说清楚之后，他给出第一条实证规律：**工作量是程序规模的幂函数**。图 8-1 引的是 Nanus 和 Farr 在 System Development 公司的研究，指数约为 1.5：

```
工作量 = 常数 × 指令数量^1.5
```

Weinwurm 在 SDC 的另一项研究给出接近 1.5 的指数。这条规律意味着规模翻倍时工作量增长到约 2.8 倍——**和"人月可以按规模线性摊"的直觉直接冲突**。

接下来五组数据从不同角度逼近真实生产率。

**Portman 的数据**解释了一类系统性偏差。他发现自己的队伍落后进度约一半，每项工作实际耗时约为估计的两倍；而那些估计是很有经验的团队用 PERT 图对人小时细分到数百个子任务做出来的。他要求团队记录时间日志，答案立刻出现：**队伍只用了 50% 的工作周做实际的编程和调试**，其余时间花在机器当机、高优先级的琐碎工作、会议、文字工作、公司业务、疾病和事假上。也就是说，估算对"每个人年里有技术工作时间"这件事做出了不现实的假设。

**Aron 的数据**按程序员之间的交互密度分类，给出三个量级差别：

| 交互程度 | 生产率（指令/人年） |
| --- | --- |
| 非常少的交互 | 10000 |
| 少量的交互 | 5000 |
| 较多的交互 | 1500 |

这些数字只含设计与编程，不含支持和系统测试；作者说把它们除以 2 以计入系统测试，结果与 Harr 的数据非常接近。

**Harr 的数据**来自贝尔电话实验室电子交换系统，四个程序——两个基本控制程序、两个基本语言翻译程序。生产率的单位是"经调试的指令/人年"，已包含编程、构件测试和系统测试。结果分成鲜明两档：**控制程序约 600 指令/人年，语言翻译程序约 2200**。四个程序规模相近，差别只在工作组大小、时间长短和模块个数上。作者在这里表现得很克制：因果无法确定——"是控制程序确实更复杂，所以需要更多人？还是因为被分派了过多的人，所以需要更多模块和更多人月？没有人可以确定。"但他强调数据反映的是真实状况，因此 Harr 的贡献是实实在在的。

**OS/360 的数据**给出同一量级的独立佐证：控制程序组约 600–800 经调试指令/人年，语言翻译组 2000–3000。作者由此提炼出一条粗略的换算原则——**编译器的复杂度是批处理程序的 3 倍，操作系统的复杂度是编译器的 3 倍**。

最后是 **Corbato 的数据**，也是全章唯一让人振奋的一处。MIT 的 MULTICS（约 100–200 万条指令）报告显示平均生产率为 1200 行经调试的 PL/I 语句/人年。换算时要注意单位差异：**每个语句对应手写代码的 3–5 条指令**，于是得到两条结论：

- 对常用编程语句而言，**生产率似乎是固定的**（这个数字已经包含了注释与可能的错误在内）；
- 使用适当的高级语言，**编程生产率可以提高 5 倍**。

## 我的判断 {#reading}

- 这一章性质上是一份数据综述，而不是论证。放在第 7 章之后是有意的：先把"交流与组织"讲透，再谈"要多长时间"，顺序上先讲清楚会决定工作量的因素，再谈量化，避免把估算做成纯数字游戏。
- 1.5 次幂这条规律是本章最重要的结论，也是最容易被今天的人忽略的。它给出的是**非线性**：规模翻倍、工作量约 2.8 倍。作者没有解释指数为什么是 1.5，我读到这里的理解是，它把接口、集成与测试随规模增长的速度一并吞进去了——这也解释了为什么它和"复杂度三级跳"（批处理 → 编译器 → 操作系统）的量级判断是自洽的。
- Portman 的数据今天依然成立，而且很反直觉：**估算错一倍，往往不是估错任务，而是估错了可用时间**。一半的工作周被非技术事务吃掉，这种偏差在任何按"人年"排的计划里都会隐身。
- Harr 数据里那个因果不确定，我认为是作者全书最诚实的一段：同一份数据既支持"复杂任务需要更多人"，也支持"派了太多人导致模块变多"，他明确说没人能确定。可贵的不是数据，而是他没有借数据去证明自己的观点。
- Corbato 的"高级语言提高 5 倍"这条结论要小心。它是 1970 年代从汇编到 PL/I 的跨越，今天已经不存在同等量级的代差；把它当成"换更高级的语言就能再提 5 倍"来用，是误读。真正仍然有效的是前半句：**对常用语句而言生产率是固定的**——也就是说，逐行写的效率很难提高，要提高只能改变"要写多少行"。
- 我对"编译器 = 3 倍批处理，操作系统 = 3 倍编译器"这条保持怀疑：它更像经验秩序而非测量结论，而且三级跳的边界在任何时代都是主观的。但它作为一种**迅速对齐预期的手段**仍然有用，前提是不要把它当精确系数。

## 和我手上的工作有什么关系 {#relevance}

- 我自己最容易犯的错正是本章开头警告的第一条：按"写代码的时间"推算整件事的周期，却漏掉设计、文档、测试、集成与学习成本。按这里的比例，编码只占六分之一——这与我实测的体验接近，只是我以前没有把它写下来当预算依据。
- Portman 的 50% 对我尤其有用。它给了"为什么感觉没做什么事情一天就过去了"一个量化解释，也提示我在排期时应该按**可用技术时间的比例**打折，而不是按日历时间乘人数。
- 1.5 次幂这条，我打算把它用成一个预警指标：当项目规模翻倍时，如果计划只涨了一倍工作量，就该怀疑接口与集成成本被漏算了。对个人项目也一样——加一个栏目、加一门语言，代价不是线性的。
- "生产率是固定的，要提高就得减少要写的行数"这条结论，直接支持了我现在的工作方式：与其纠结手写的效率，不如把机械的部分交给脚本、模板与 Agent（`bin/build.sh`、archetypes、批量 OCR 都是我实践这条的产物）。
- Aron 那三档交互密度给了我一个判断工具：同一件事，在"低交互"和"高交互"之间的生产率能差 6 倍以上。所以当我觉得某个任务特别慢时，先问的不是"我是不是变笨了"，而是"这件事的交互密度是不是被低估了"。

## 一句话记住 {#takeaway}

工作量随规模按 1.5 次幂增长，生产率随交互密度与任务复杂度相差近十倍，而一半的工作周会被非技术事务吃掉——估算时必须把这三件事一起算进去。
