# 第 12 章 · 干将莫邪

> 工具应该由项目统一提供而不是各人自备：目标机器、仿真与编译器平台、受控的程序库、文本编辑系统，以及高级语言与交互式编程。

---

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

---

题记是一句谚语："巧匠因为他的工具而出名。"

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

作者先批评一种他称为"经营五金店"的做法：**每个骨干人员都仔细保管自己工作生涯中搜集的一套工具集**，把它们当作个人技能的直观证明——编辑器、排序、内存转储、磁盘空间实用程序各有一套。他说这对软件项目来说是愚蠢的，理由三条：项目的关键问题是沟通，个性化工具**妨碍而非促进沟通**；机器与工作语言一变，工具的生命周期就结束；而开发和维护公共通用工具的效率无疑更高。

但仅有通用工具不够——专业需要和个人偏好同样需要专用工具。所以他在第 3 章的外科手术队伍里为每个团队配了**工具管理人员**：管理通用工具、指导客户和老板怎么用，同时编制老板需要的专用工具。他还特别提醒一个反直觉的组织结论：**把所有分散的工具管理人员集中成一个公共工具小组，效率反而不会更高**——专用工具必须贴着具体团队的需求长出来。

需要项目经理计划组织的工具是一张清单：计算机设施（含硬件与使用安排的策略）、操作系统、语言及明确的使用方针、实用程序、调试辅助程序、测试用例生成工具，以及处理文档的字处理系统。接下来按机器角色分述。

**目标机器**是软件所服务的对象，程序必须在这一类机器上完成最后测试；**辅助机器**则在开发过程中提供服务。为原有机型开发新操作系统时，同一台机器会兼具两种角色。他对目标机器提的要求很具体：速度不必快，但要有若干兆字节主存、百兆字节在线硬盘和终端；字符终端够用，但必须比每秒 15 字符的打字机快；大容量内存能支持功能测试后的覆盖与裁剪，极大提高生产率。此外必须有**调试机器或软件**，让各类程序参数被自动计数与测量——他把内存使用模式称为"非常强大的诊断措施"，能查出不合逻辑的行为或性能意外下降的原因。

机器时间的**进度安排**是这一节最生动的部分。OS/360 开发早期，机器时间极度稀缺：他们按经验提前预订了 System/360 的使用小时数，结果起初机器日复一日空着，突然有一天十六个系统全部上线，资源配给立刻失控——因为"每个人在同一时间开始调试自己的第一个组件"。他们先尝试集中机器与磁带库、组建专业操作团队、把调试任务批处理化，每天跑四次、周转 2.5 小时（实际要求 4 小时），甚至动用一台带终端的 1401 做调度与跟踪。但队伍仍然过度运转，经历几个月"缓慢周转、相互指责和极度痛苦"之后，他们改成**把机器时间切成连续的块**：例如整个十五人的排序小组拿到四到六小时的使用块，自行决定怎么用，即使机器空着别人也不能占用。

结果是：机器利用率可能略降，但**生产率提高了**。理由是"持续的精力集中能减少思考时间"——六小时里连续十次操作，比分散在间隔三小时里的十次操作产出高得多；每次冲刺之后，小组通常还要一两天做文档工作；而三人左右的小组最能有效共享时间块。作者还顺带记下一个跨越三代机器的现象：系统调试总是夜班性质的工作，"技术完全改变了，操作系统出现了，大家喜好的工作方式并没有改变"——因为它生产率最高。

**辅助机器和数据服务**一节列了六类基础设施：

- **仿真装置**：目标机器是新产品时，逻辑仿真装置能在真机出现之前提供调试平台，而且真机出现之后依然有用。作者强调一句关键话：**可靠并不等于精确**。仿真在某些细节上肯定无法与真机完全一致，但它的实现至少在一段时间里是稳定的，而新硬件不会。硬件故障往往是间歇性的，**不确定性最糟糕，因为它剥夺了开发人员查找 bug 的动力——也许 bug 根本就不存在**。
- **编译器和汇编平台**：编译软件应运行在可靠的辅助平台上，为目标机器产出目标代码，再立刻转到仿真装置上调试；用高级语言时，大量调试工作可以在真机全面测试之前完成。
- **程序库和管理**：OS/360 中做得最成功的一项，由 W. R. Crowley 领导，连接两台 7010 与一个大磁盘数据库。库按访问规则分成几层：**开发库**（playpen）里每位开发人员自由处置自己的程序，因为他是拥有者；准备集成时把拷贝交给**集成经理**放进**系统集成子库**，此后原作者未经批准不得再改；某个版本被广泛使用后提升为**当前版本子库**，原则上不可更改，用于所有新模块的集成与测试。程序目录跟踪每个模块每个版本的状态、用途与变更。作者从中提炼出两个理念——**受控**（拷贝由经理负责，变更需他独立授权）与**让发布的进展正式化，并把开发库与集成、发布正式分离**——并称这是"OS/360 工作中最优秀的成果之一"，因为它其实是管理技术，贝尔实验室、ICL、剑桥大学都独立发展出了类似做法，而且同样适用于文档。
- **编程工具**与**实用程序**：内存转储、源文件编辑、快照跟踪、磁带拷贝、打印与目录管理等等——只要一开始就任命工具操作与维护人员，这些工作可以一次做好并随时待命。
- **文档系统**：最能节省劳动力的工具，是运行在可靠辅助平台上的计算机化文本编辑系统（他点名 J. W. Franklin 设计的那套）。没有它，OS/360 手册的进度会远远落后，而且更晦涩难懂。面对"六英尺厚的手册没用"的批评，他的回应是两条：文档规模虽大，但阅读计划是被仔细安排的，**应把它当图书馆或百科全书，而不是一系列强制阅读的文章**；同时他承认手册有不少地方需要改进，篇幅本可以大幅压缩。
- **性能仿真装置**：最好有一个，并且与逻辑仿真、产品本身使用同一套自上而下的设计方法；要尽可能早开始，并"仔细地听取它们表达的意见"。

最后一节讲当时最重要却未被广泛采用的两种工具：**高级语言**与**交互式编程**。作者的语气很硬——"我确信只有懒散和惰性会妨碍它们的广泛应用，技术上的困难不再成为借口"。

高级语言的价值在于**生产率与调试速度**：bug 更少且更容易查，因为它避免了在错误面前暴露所有级别的工作（不只是语法错误，还有寄存器使用不当这类语义问题），而编译器的诊断机制能帮忙定位。至于当年流行的三条反对意见——做不了我想做的事、目标代码太大、跑得太慢——他逐条回应：功能上的限制已经消失，只需要花时间找出做法；新的优化编译器在空间上已令人满意并会继续改进；速度上，**优化编译器生成的代码比绝大多数程序员手写的效率更高**，真遇到瓶颈，把其中 1%–5% 换成手写代码即可。至于选哪种语言，他认为当时唯一合理的选择是 PL/I。

交互式编程这一节里，他给了一份珍贵的量化证据（来自贝尔实验室 John Harr 的论文）：

| 程序 | 规模（指令） | 方式 | 生产率（指令/人年） |
| --- | --- | --- | --- |
| ESS 代码 | 800000 | 批处理 | 500–1000 |
| 7094 ESS 支持 | 120000 | 批处理 | 2100–3400 |
| 360 ESS 支持 | 32000 | 交互式 | 8000 |
| 360 ESS 支持 | 8300 | 批处理 | 4000 |

结论是：**系统软件开发中，交互式编程的生产率至少是原来的两倍**。理由他也讲清了——调试是系统编程中最慢、最困难的部分，而"漫长的调试周转时间是调试的祸根"。最后他补了一条耦合关系：由于电传打字机和打印机终端无法胜任内存转储式调试，交互式工具的有效使用**需要高级语言配合**——有了高级语言，修改代码和选择性打印结果才变得容易。这两样东西是一对。

## 我的判断 {#reading}

- 这一章表面在列工具清单，核心其实是一条组织主张：**工具是项目的公共资产，不是个人的技能证明**。作者给的三条理由里，第一条最容易被忽略——个性化工具妨碍沟通。工具不统一，本质上就是每个人的输出格式不同，交流成本随即上升。
- 他对工具管理人员"不能集中成公共小组"的判断，与今天很多组织的直觉相反。我认同他的逻辑：**专用工具贴着具体团队的需求，脱离上下文的集中供给会失效**。这和站点里"约定要写在项目内的 AGENTS.md 而不是某个中心文档库"是同一件事。
- "可靠并不等于精确"这句是我这一章最想带走的一句。它把仿真与真实环境的取舍讲透了：在开发阶段，**稳定性比保真度更重要**，因为不确定性会直接杀死排查 bug 的动机。这条今天仍然适用于容器、模拟器、桩件测试。
- 程序库那三层（开发库 → 集成子库 → 当前版本子库）以及"受控"的理念，我认为是本章最实用的部分，而且它没有过时：今天的分支策略、代码所有权、发布冻结，本质都是同一套东西。它比"用什么版本控制工具"重要得多。
- 我对"优化编译器生成的代码比绝大多数程序员手写更高效"这条持保留：它在 1975 年的系统编程语境下成立，但今天手写汇编在热点路径上仍能显著胜出（尤其是嵌入式）。不过我承认他的补充很务实——**先全用高级语言，再把 1%~5% 换成手写**，这个顺序是对的。
- 交互式编程那组数据（2 倍）放到今天看反而更极端：现代开发几乎全在交互式环境里，"批处理"这个名字已经消失。作者在五十年前就把它列为"最重要却未被广泛采用"的工具，这个判断后来被完整验证了。

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

- 我的"工具集"目前散在两处：项目内的 `tools/`（Hugo、Go）与项目外的系统包（pdftoppm、OCR 引擎）。按这一章的标准，这已经算公共工具而非个人工具，但**没有统一的说明**。我打算在 `AGENTS.md` 里补一张工具清单，写清每件工具的用途与安装方式——这正是作者说的"工具管理人员"在单人项目里的最小形态。
- 时间块那条对我有直接价值。我经常把多件事切碎并行处理，结果每件都处在"间隔三小时"的状态。作者的实测结论是**连续集中的六小时远胜分散的六小时**，因为省下的思考时间属于切换成本。我准备把"给一件事分配连续的时间块"当作排期规则。
- "受控"那三层库让我重新看待自己的工作流：我的 `content/` 相当于开发库（自由改），`main` 分支相当于集成子库（推送即对外），而发布出去的版本则是当前版本子库（不可更改）。差距在于我缺少**集成经理**这个角色——目前是我自己既当作者又当集成者，所以作者说的"原作者未经批准不得改动"在我这里形同虚设。至少要给发布加上"发布后改动必须记入会话记录"的约束。
- 高级语言那条结论，与我在嵌入式上的现实有些出入：那里 C 与汇编仍是主流，编译器优化水平参差。但它的方法论仍可借用——**先把热点交给工具，再用实测数据决定哪 1%~5% 值得手写**，而不是凭直觉一开始就手写优化。
- "可靠不等于精确"这条我打算用在测试环境上：与其追求与真机完全一致的模拟平台，不如先保证它稳定可复现；一个稳定但不完美的平台，比一个精确但飘忽的平台更能提高排查效率。

## 一句话记住 {#takeaway}

工具是项目的公共资产而不是个人技能证明：统一提供通用工具、贴着团队需求保留专用工具，并优先保证调试平台的稳定——因为不确定性会直接杀掉排查问题的动力。
