《人月神话》笔记:Brooks 用 OS/360 的学费换来的软件工程第一性原理
- 约 22 分钟读完 - 全文 8402 字《人月神话》笔记:Brooks 用 OS/360 的学费换来的软件工程第一性原理
目标读者:带过项目、估过排期、经历过"老板说加人就能赶上"的工程师和工程管理者。 参考书籍:Frederick P. Brooks Jr.《人月神话》(The Mythical Man-Month,1975 年初版,1995 年 20 周年纪念版),含 1986 年论文《没有银弹》(No Silver Bullet)。 阅读目标:不是复述一本 50 年前的书,而是把 Brooks 用 IBM OS/360 项目的巨额学费换来的几条"软件工程第一性原理"蒸馏成今天还能直接用的判断准则。
一、焦油坑:这本书从哪里长出来的
书的第一章叫「焦油坑」(The Tar Pit),Brooks 用了一个古生物学意象:拉布雷亚沥青坑里,猛犸、剑齿虎、恐龙——越是强壮的野兽,挣扎得越猛烈,陷得越深。大型系统编程就是这样一个焦油坑:没有哪支队伍特别笨,但大家都在里面挣扎,而且越挣扎陷得越深。
这句话不是文学修辞,是作者的身份声明。Brooks 是 IBM System/360 大型机项目的经理,随后又是其操作系统 OS/360 的项目经理——这是 1960 年代人类历史上最大的软件项目之一,几千人年、超支数倍、进度失控、bug 成山。1964 年 IBM 老板小沃森问他项目为什么管成这样,他答不上来;几个月后他离开 IBM 去北卡大学建计算机系,把这次失败翻来覆去想了十年,1975 年写出这本书。
所以读这本书的正确姿势是:这不是一个管理学教授在总结别人的案例,是一个搞砸过史上最大软件项目的人在写尸检报告。 书里每一条论断背后,都是 OS/360 真金白银的教训。这也是为什么这本书快 50 年了还不过时——硬件换了五代,语言换了几轮,但"人怎么组织起来写大软件"这个问题的底层结构,几乎没变。
全书论点可以用一句话串起来:
软件项目的失败,绝大多数不是技术失败,而是对"编程这项活动的本质"估计错误的失败——错估了沟通成本、错估了复杂度的来源、错估了设计与实现的相对价值。
二、人月神话:人月是不可互换的
书名即论点。人月(man-month)——用人乘以月来度量工作量——是一个神话,因为它暗含一个错误前提:人和月可以互换。 10 个人干 1 个月,和 1 个人干 10 个月,不是一回事。
Brooks 的论证是一个漂亮的分类学,按任务的可分解性拆开:
- 完全可分解、无需沟通的任务:比如收麦子、筛数据。这类任务人月确实可互换,人加倍时间减半。可惜软件里几乎没有这种任务。
- 可分解但需要沟通的任务:大部分编码工作属于此类。增加人手,沟通成本随之而来,收益开始打折。
- 可分解但需要复杂沟通与再培训的任务:沟通成本开始吞噬新增人手带来的产能。
- 完全不可分解、有严格次序依赖的任务:比如调试(本质上是顺序的),比如生孩子——九个月,几个母亲也压缩不了。软件里的系统设计和集成调试大量属于此类。
flowchart TD
T["软件任务"] --> Q{"能否分解为<br/>无需沟通的子任务?"}
Q -->|"能(极少: 收麦子型)"| A["人月近似可互换<br/>人加倍, 工期减半"]
Q -->|"不能(绝大多数)"| Q2{"主要成本是什么?"}
Q2 -->|"沟通与协调"| B["加人收益递减<br/>沟通路径数 = n乘n减1再除2"]
Q2 -->|"严格次序依赖<br/>设计、调试、集成"| C["加人完全无效<br/>九个月生不出孩子"]
style C fill:#ffcccc
style A fill:#e8f5e9
沟通成本那条值得算一笔小账:n 个人两两沟通,路径数是 n(n-1)/2。3 个人是 3 条,7 个人是 21 条,10 个人是 45 条。人数翻倍,沟通路径数大约翻两番。 如果每次协作都要开会、对齐、等回复,人越多,每个人写代码的时间占比越低。这就是为什么 Brooks 说"用人月作为度量,等于默认了一个只在收麦子时成立的假设"。
这条原理的一个直接推论,常常被忽略:进度落后的项目,往往不是人太少,而是人太多——沟通结构已经把产能吃掉了,这时候减人反而可能提速。
三、Brooks 定律:向延期的项目加人,只会让它更晚
这是全书最出名的一句话,1975 年提出,后来被叫成 Brooks 定律(Brooks’s Law):
Adding manpower to a late software project makes it later.(向一个已经延期的软件项目增加人手,只会让它更晚。)
为什么"加人赶工"这个管理者最直觉的动作是错的?Brooks 拆了三层成本:
- 培训成本:新人不能立刻干活。他们要先学项目的目标、架构、既有代码、开发流程——而教他们的人,正是团队里本来在干活的老手。老手的时间被培训占用,团队短期产能不升反降。
- 沟通成本:就是上一节的 n(n-1)/2。加人后,任务要重新划分、接口要重新对齐,原本两个人口头约定的事,现在要写文档、开会。
- 任务重划分成本:很多任务被打断重拆时,边界上的工作要重做;有些任务根本拆不动(次序依赖的部分),能拆出去的部分往往是最不需要人的部分。
flowchart LR
subgraph 加人前
A1["团队产能 100%<br/>全部用于推进项目"]
end
subgraph 加人后短期
B1["老手产能下降<br/>抽时间培训新人"] --> B3["净产能低于加人前"]
B2["新人产能为负<br/>提问、犯错、需要返工"] --> B3
B4["沟通路径数平方增长<br/>对齐成本吞噬产出"] --> B3
end
subgraph 加人后长期
C1["若项目不取消<br/>数月后产能才可能恢复<br/>但死线已过"]
end
A1 -.->|"管理者直觉: 产能应线性上升"| B1
B3 --> C1
style B3 fill:#ffcccc
书里还有一个配套观察,杀伤力同样大:项目是怎样延期一年的?一天一天延的。(How does a project get to be a year late? One day at a time.)大灾难不是突然降临的,是每天落后一点点、每次例会都"下周能追上"累积出来的。所以 Brooks 主张里程碑必须具体、锋利、公开——“编码完成 90%“不是里程碑,是遮羞布;“模块通过全部单元测试并合入主库"才是。
对今天的映射几乎不用翻译:每个 deadline 前两周"借调支援"的场景,都是 Brooks 定律的现场重演。正确的动作恰恰相反——砍掉 20% 的范围,比增加 20% 的人有效得多。
四、概念完整性与外科手术队伍
4.1 最重要的系统属性不是功能,是概念完整性
Brooks 认为,一个系统给用户呈现的东西里,概念完整性(conceptual integrity)是最重要的品质——系统各处必须体现同一套设计哲学,一致、连贯、正交。用户学透三个概念就能推测出三十个行为的系统,远好过每个功能都自说自话的系统。
但概念完整性有一个组织上的代价:它无法由委员会设计出来。 民主设计出来的系统,是每个聪明人都塞进了自己最爱的特性的系统——功能很多,灵魂没有。所以 Brooks 给了一个政治不正确但极其诚实的结论:
概念完整性要求设计出自一个人,或极少数同心同德的人。为了完整性,必须接受贵族专制(aristocracy),放弃民主。
这不等于独裁者包揽一切。Brooks 的关键区分是:体系结构(architecture)与实现(implementation)分离。架构师定义"系统对用户是什么样”——接口、语义、概念模型;大量实现者在架构约束下尽情发挥创造力。OS/360 的教训是:架构师也必须克制,架构文档里不该规定任何"实现细节”,否则就是把实现者的创造力抢走、把架构变成瓶颈。
Unix 是这条原则最著名的正面样本(Brooks 自己也拿它举例):一切皆文件、程序是过滤器、文本流为接口——概念少到极致,组合力大到极致。
4.2 外科手术队伍:小团队怎么做大事
如果人少才有一致性,人少又怎么完成大项目?Brooks 的回答是全书我最喜欢的组织设计:外科手术队伍(surgical team)——不是"人人都是全才"的平等团队,而是像一台外科手术那样,一个主刀,其余所有人都是为了让主刀的每一分钟都高效而存在。
10 人编制大致是:
- 外科医生(首席程序员):亲手定义功能与性能规格,亲手写核心代码,对系统负全责。
- 副手(copilot):能替代外科医生做任何事,是他的讨论对象、保险丝和备份,但不抢方向盘。
- 管理员:处理钱、人、场地、设备这些非技术事务——外科医生不该为报销分心。
- 编辑/秘书:外科医生口述或手写,编辑负责把文档变成清晰、统一、可发布的正式文档。
- 程序职员:维护所有代码版本、运行记录、测试数据——机器时间时代的"版本与构建管家”。
- 工具师:为团队打造专用工具、脚本、测试设施。
- 测试员:根据规格写测试用例,并且从规格里找矛盾——他是架构师的第一批批评者。
- 语言专家:精通语言犄角旮旯的顾问,帮团队写出既优雅又高效的代码。
flowchart TD
S["外科医生 首席程序员<br/>设计 + 核心代码 + 负全责"]
C["副手<br/>讨论对象与备份"]
AD["管理员<br/>钱、人、设备"]
ED["编辑<br/>文档产出与统一"]
CL["程序职员<br/>版本与运行记录"]
TL["工具师<br/>内部工具与设施"]
TE["测试员<br/>用例设计与规格挑刺"]
LX["语言专家<br/>语言技艺顾问"]
C --> S
AD --> S
ED --> S
CL --> S
TL --> S
TE --> S
LX --> S
style S fill:#fff3cd
注意这个结构的颠覆点:其他人不是外科医生的下属执行者,而是他的支撑系统。 今天回头看,这是"10x 工程师团队"最早的严肃版本——结论不是"找 10 个 10x",而是"让那个 10x 的人 100% 的时间都在做只有他能做的事"。大项目怎么办?分成若干段,每段一个外科手术队伍,段与段之间用架构对齐——又回到概念完整性。
五、第二系统效应:你最危险的作品是第二个
全书最精妙的心理学洞察之一:第二系统效应(second-system effect)。
一个人在设计他的第二个系统时,会把它做成最危险的系统——因为他会把第一个系统里没用上的所有想法,全都塞进去。
机制是这样的:设计第一个系统时,人是谨慎的、不自信的,处处收敛;那些"如果再来一次我一定要加"的念头,被一条条记在心里的清单上。设计第二个系统时,自信来了,约束松了,那张清单被整体倒出来——加上第一版遗留功能的修饰欲,结果是功能膨胀、概念混杂、复杂度失控。
Brooks 的自白是:OS/360 就是大量设计者的"第二系统"(多数人的第一系统是 1410、7090 系列),所以它的链接器、它的各种设施,都堆满了"这次终于可以做了"的东西。而他给架构师的建议只有一句:为每个功能问一句"它值它占用的那份复杂度预算吗";并且始终意识到自己在设计第几个系统——第三个系统的设计师,往往才第一次有真正的克制能力。
工程映射:每个"重写 2.0"项目都是第二系统效应的高危现场。旧系统的痛点清单天然会被翻译成新系统的功能清单,而旧系统"为什么不支持 X"的答案(往往是成本,不是疏忽)在重写时被遗忘。重写立项评审时,把"砍掉的功能清单"和"新增的功能清单"摆在一起看,能救命。
六、计划抛弃原型:第一个版本注定要扔
原话极不客气:
Plan to throw one away; you will, anyhow.(计划抛弃一个吧;反正你一定会抛弃的。)
意思是:你做的第一个版本,无论多用心,都是"试验品"——只有做完它,你才真正理解需求、理解约束、理解用户真正要什么。管理层如果不"计划"抛弃它,它就会被当作产品硬撑下去,背着一个为学习而生的架构进入维护地狱。
这句话常被误读为"随便写一版就行"。Brooks 的本意严格得多:抛弃是计划内的,所以要为"抛弃"设计——原型和生产系统用不同的人力配比、不同的质量预期、不同的心态;原型的使命是最大化学习,不是最大化寿命。后来的演进还有一条:唯一比"计划抛弃"更贵的,是假装不用抛弃。
这条思想后来开枝散叶:快速原型、MVP、以及 Brooks 自己在《没有银弹》里提出的增量式构建(grow, not build)——软件不该是"建造"出来的,该是"生长"出来的:先让一个能跑的最小骨架活着,然后每加一个功能都保持系统可运行。1995 年纪念版里他承认,当年"抛弃一个"的说法被他自己修正为更平滑的增量演化,但内核没变:不要指望第一枪就命中,把迭代当成常态写进计划。
七、文档与工作手册:被遗忘的主角
这本书有个今天读来格外超前的观点:项目经理最重要的日常工作是文档,不是代码。 Brooks 花了整整一章讲「项目工作手册」(project workbook):
- 它是什么:项目所有正式文档的集合——目标、规格、进度、接口定义、会议纪要、变更记录。它不是档案柜,是项目的活的中枢。
- 为什么必须有:第一,写作强制清晰——“写在纸上的决策,模糊性会自己暴露”,很多争吵在落成文字那一刻就解决了;第二,文档是沟通结构的载体,几百人的项目里,工作手册是唯一能让"每个人看到同一本事实"的装置。
- 怎么维护:所有变更都要进手册,手册必须人人可得、持续更新(OS/360 时代用缩微胶片分发,他特意讨论了每日更新机制——放今天就是 wiki/文档站)。
配套还有一条 OS/360 的组织创新:让文档成为规格的唯一权威形态。架构师写正式的外部规格说明,实现中出现歧义时,由架构师裁决并把裁决写回规格——规格永远是最新事实,不是"最初的美好愿望"。
今天的映射一目了然:ADR(架构决策记录)、design doc 评审、“接口以文档为准而非以聊天为准”,全是工作手册的现代转世。Brooks 在 1975 年就说清楚了我们 2020 年代还在学的事:异步的、成文的沟通,是大团队唯一可扩展的沟通。
八、没有银弹:本质复杂度与偶然复杂度
1986 年,Brooks 发表了那篇比书本身更著名的论文:「没有银弹——软件工程中本质与偶然的问题」(No Silver Bullet: Essence and Accidents of Software Engineering),1995 年纪念版收入书中。
核心论断:没有任何一项技术或管理进步,能在十年内让软件生产率提高一个数量级。 因为软件的困难要分两类:
- 本质复杂度(essential):问题域本身固有的复杂度——概念结构必须精确、一致、完整;软件是"纯粹的思想制品",它的复杂度不会因为换工具而消失。就像银弹能杀狼人,但软件工程里没有狼人——没有一个叫"技术"的妖怪一枪打死就天下太平。
- 偶然复杂度(accidental):我们制造过程附带的复杂度——机器慢、语言啰嗦、工具难用、环境配置地狱。这部分是可以消灭的,而且历史上已经消灭了大部分:高级语言干掉了汇编的偶然复杂度,分时系统干掉了批处理的排队等待,统一硬件平台干掉了移植地狱。
Brooks 的关键预测逻辑是:到 1986 年,偶然复杂度已经被压缩到不是主要矛盾了——剩下的硬骨头几乎全是本质复杂度,而本质复杂度不响应任何"银弹"。
那怎么办?论文给出了四条"有希望的铜弹",条条在后来兑现:
- 买,别造(buy vs. build):能买现成软件就别自己写——自己写的那部分才承载本质复杂度。
- 需求精炼与快速原型:最难的本质问题是"搞清楚到底要造什么",用原型和用户一起把需求逼出来。
- 增量式生长(grow, not build):系统永远保持可运行,小步叠加。
- 培养伟大的设计师:软件生产率的最大方差来自人——顶尖设计师和普通设计师的差距是数量级的,把培养设计师当成组织的核心投资。
1986 年之后的四十年基本在给这篇论文做注脚:面向对象、组件化、开源生态、云、低代码,每一波都消灭了新的偶然复杂度,每一波之后项目照样的难——因为难的那部分从来不在工具里,在"我们要造的东西本身"里。
九、20 周年纪念版:Brooks 的自我检讨
1995 年纪念版最珍贵的部分,是 Brooks 回头看自己二十年前的论断,一条条打分:
- 仍然坚信的:概念完整性是系统最重要的品质;人月不可互换;加人让延期项目更晚;工作手册必不可少;第二系统效应真实存在。
- 修正的:「计划抛弃一个」太粗暴,更准确的表述是增量演化(grow);结构化编程、面向对象属于消灭偶然复杂度,不是银弹——这点他赌对了。
- 认错的:他当年推崇"信息隐藏到团队之间也互相保密"的做法,后来承认过度了——Parnas 的信息隐藏原则适用于模块接口,不该用来隔离团队之间的知识。
- 被时代证明最对的:对"伟大设计师"的押注。20 年后他更确信:软件质量的天花板由少数顶尖设计者决定,组织的头等大事是发现他们、培养他们、别用流程磨平他们。
这种"作者亲自给旧书做 code review"的结构,本身就是对全书精神的践行:把二十年前的决策放到今天的光下重新评审,而不是假装当年的自己永远正确。
十、落地实践:我自己在用的四条
这本书不是读完就完的,我把其中几条固化成了自己带项目时的检查动作:
- 报排期时先分类任务。任何估算之前,先问"这块工作能不能无沟通地并行拆开"。拆不动的部分(联调、设计、疑难 bug),单独列出来按顺序排,并且明确告诉需求方:这部分加人不解决问题,加人只会更慢。把 Brooks 定律提前说出来,比延期之后再解释有效得多。
- 里程碑只写"可验证的事"。排期表里禁止出现"开发完成 80%“这类状态词,全部换成"接口联调通过"“性能压测达标"这种第三方可验证的硬节点。项目是一天一天延期的,锋利的里程碑是让"每天的小落后"无处藏身。
- 重写项目先审"砍掉清单”。任何重构、2.0 立项,评审材料里必须有两栏:新系统不做什么、为什么不做。没有砍掉清单的重写方案,默认是第二系统效应发作,打回。
- 护住团队里的"外科医生”。识别出那个承担核心设计的人,然后系统性地替他挡事:杂会替他推掉、文档有人帮他整理、工具不顺有人帮他修。他的每一分钟专注时间,就是整个团队的产能上限。
四条背后其实是同一个原则,也是这本书教我的最重要的一件事:软件工程里大多数"管理动作"的反面才是对的——加人不如减人,催进度不如砍范围,民主设计不如贵族专制,憋大招不如小步生长。 Brooks 在五十年前就把这些"反直觉"写成了定理,我们要做的只是别再交一遍学费。
十一、带走的清单
如果只能记住几件事,记这些:
- 人月不可互换。报工期前先问:这个任务属于"收麦子型"还是"生孩子型"?后者加人无用。
- Brooks 定律:延期的项目加人只会更晚。赶工的正确动作是砍范围、保核心,不是借调支援。
- 里程碑要锋利:“完成 90%“不是进度,是幻觉;只有"可验证、不可含糊"的节点才是进度。
- 概念完整性 > 功能数量。架构出自一人或极少数人;架构师管"系统是什么样”,实现者管"怎么造出来”。
- 警惕第二系统效应:重写立项时,先审"砍掉清单",再审"新增清单"。
- 计划抛弃原型:第一版的使命是学习;要么计划抛弃它,要么被它拖死。
- 文档是项目的中枢:写下来,模糊会自己暴露;规格是唯一权威,裁决要写回规格。
- 没有银弹:工具的进步只消灭偶然复杂度;本质复杂度只能靠更好的需求(原型)、更好的生长方式(增量)、更好的人(设计师)来对付。
- 投资顶尖设计师:人员方差是软件生产率里最大的方差,这件事 1975 年成立,今天更成立。
参考资料
- Frederick P. Brooks Jr., The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition, Addison-Wesley, 1995(含《没有银弹》全文及作者 20 年回顾)。
- Frederick P. Brooks Jr., “No Silver Bullet: Essence and Accidents of Software Engineering”, Computer, 1987(1986 年原始论文)。
- Frederick P. Brooks Jr., The Design of Design, Addison-Wesley, 2010(Brooks 晚年对"设计"本身的系统思考,可视作本书续篇)。