《人月神话》读书笔记(下):沟通、变化与没有银弹

软件的根本困难在概念不在实现,工具和 AI 能削平次要任务,却削不平"想清楚要造什么"——所以没有银弹,能做的是沟通、拥抱变化和拆解。

发布日期
主题
读书笔记 · 软件工程 · 项目管理 · 人月神话
阅读时间
9 分钟

上篇讲了大型软件为什么难、人该怎么组织。这篇接着讲怎么把事情做成:从沟通开始,经过度量、拥抱变化、集成测试、进度管理,最后落到那句最有名的判断——没有银弹。

正文是布鲁克斯的观点,引用块里是我自己的批注。

为什么巴比伦塔会失败

沟通。

巴比伦塔的条件好得几乎无可挑剔:目标清晰,人力充足,材料丰富,没有时间限制,技术也过关——锥形结构本身稳定,砖石工艺研究得很深。可它还是塌了。

上帝做的事只有一件:让人们的语言产生混淆,彼此听不懂。项目就此失败。缺的不是资源,是交流,以及交流的结果——组织。现实里也一样,左手不知道右手在做什么,就会酿成进度灾难。团队之间要用一切能用的渠道沟通,正式的会议和非正式的闲聊都算。

文档化是必须的,而且要结构化——有了结构,后面写的东西才知道该放进哪一节;写完还要确保它送到每一个需要的人手里。

胸有成竹

实践是最好的老师,但如果不能从中学习,再多的实践也没用。

胸有成竹的前提是度量,度量人效,这就是研发效能的课题。

关于工作量,有研究得出一个悲惨的结论:工作量大致是规模的幂函数,指数约 1.5。也就是说,规模每涨一点,工作量是幂级往上翻的。

预留 buffer 同样依赖靠谱的估计。常见的错误估计,像是把百米短跑的成绩线性外推,得出”人能在 3 分钟跑完 1 英里”。正确的做法是先通过实践拿到真实数据,再据此推未来。至于效率,越上层的软件越复杂,但抽象层次越高、生产率也越高——用合适的高级语言,编程效率能翻好几倍。

削足适履

把十块钱的东西装进五块钱的盒子里。

这一章原意是讲内存受限时怎么编程:控制模块规模、高内聚低耦合、用更好的算法、拿空间换时间。但书成于四十年前,那会儿内存金贵,如今空间早就没那么稀缺了。

那这章今天还有什么用?我觉得意义变了——现在受限的不是内存,是人力和时间。同样要”削足适履”:拆分模块之后,砍掉没那么必要的部分,把省下的时间还给核心功能。

提纲挈领

文档化的重要性。

文档的跟踪维护,本身就是项目监督和预警的机制。它还用来同步信息——小团队里,可能只有两成时间在用自己的脑子获取外部信息,其余大半都花在沟通上:倾听、报告、讲授、讨论。所以文档要少、要精,需要提纲挈领。

未雨绸缪

不变只是愿望,变化才是永恒。

化学工程师早就明白,实验室里跑通的反应不能直接搬到工厂一步实现,因为真实环境充满变数,中间需要一个”实验性工厂”。

软件里也有这么一层。从灰度到全量、上线后回归的整套流程,就是把 demo 一步步逼近产品的”实验性工厂”。

变化是与生俱来的,与其做假设,不如提前为它准备:评估功能优先级,写代码时留口子,设计数据表时留宽余量。交付的从来不只是产品,而是用户的满意程度。

为变更做准备,落到具体就是几件事:细致的模块化、可扩展的函数、精确的接口设计、完备的文档,以及最关键的一条——把变更阶段化,用版本号和分支管起来。组织也要能跟着变:每个人的活儿要多样、可扩展,管理和技术人才最好具备互换性,这要求管理者持续投入在人的培养上。

IBM 的管理线与技术线双通道晋升路径
图 1:管理与技术双通道,让人才在两条路径间保有互换的余地,组织才扛得住变化。

还有一条反直觉的规律:前进两步,后退一步。上线新功能会带进新 bug,多数在两个月内被消化,但很久之后又会冒出来,缺陷修复本身还有两到五成概率引入新的 bug。所以每次修完,都得把先前所有测试用例重跑一遍,否则系统会以更隐蔽的方式坏掉。开发是在减熵,维护是在增熵——再熟练的维护,也只是放缓系统滑向混乱的速度。

干将莫邪

工欲善其事,必先利其器。

关于工具支撑,在今天有成熟工程体系的团队里其实感触不深,因为版本管理、多环境、回滚这些早已是标配。

但工具提效值得多想一层。我曾经想过把一个基本只做取数的后端做成配置化,用算子直接拼出结果,这会是件很锋利的工具。最后没做,我觉得反而对——那个阶段后端代码不多、轮子也齐了,开发不费人力,关键还是看性价比。工具好不好,不看它多聪明,看它省不省得下真金白银的人力。

整体部分

化整为零。

怎么开发、测试一个能跑的系统,再把测过的构件拼成可依赖的整体?先从”怎么让 bug 无处藏身”说起。

第一是防范式的定义。产品概念要完整,各方都得正确接收到,功能描述必须精确、规范。

数据口径对不齐,往往就坏在这里——没人说清一个指标到底什么意义、用哪张表的哪些字段怎么算,bug 就这么长出来了。

第二是测试规格说明。写代码前,需求文档就该先交给测试检查完整性和明确性。

测试不只是写用例,更是帮所有人理清概念。上面那个口径问题,如果每个指标上线时测试都卡一句”这个指标必须等于那个指标,否则不许上线”,就能挡住。

第三是自顶向下设计,逐步细化,细节处先用桩顶着。之后对每个构成单元做测试,达到合格率,再进系统集成调试。

祸起萧墙

不积跬步,无以至千里。

一个基本事实:一天天慢慢落后,比一次重大灾难更难防。

大多数人用里程碑来对抗慢性拖延。但里程碑一旦没有如实反映损失的时间、变成自欺,就会反过来碾碎团队士气。里程碑必须具体、特定、可度量、能清晰定义。

用好项目管理工具来盯这些节点,比嘴上说”快了快了”可靠得多。

还有一种更隐蔽的失控,叫”毛毯之下”。项目负责人遇到问题时,倾向于不上报:老板已经够忙,自己加加班也能补上,何必去麻烦他?于是污垢全被扫进毛毯底下。老板想拿到真相很难,因为负责人和老板的利益此刻是冲突的——一旦汇报,老板可能插手,反而降低负责人的威信、打乱别的计划。

把毛毯掀开有两个办法:一是减少这种角色冲突,鼓励状态共享,老板别对下属能自己解决的问题过度反应,也别在看报告时当场就作安排;二是干脆猛地掀开地毯——把项目状态可视化,定期评审加站会。

另外一面

这一章还是在讲文档,以及怎么写。对软件产品来说,程序给用户看的那一面,和给机器执行的那一面同样重要。哪怕是完全自用的程序,描述性文字也不能省,因为它们终会被用户和作者一起遗忘。文档能在整个生命周期里,帮程序员对抗懒惰和进度压力;但要让人真心对待文档,很难。为了好维护,最好把文档并进源码,而不是另存一份。

落到代码规范就很具体:复杂函数要给输入、输出和每个参数含义的注释,还要配一个简单的验证测试。文档离代码越近,越不容易烂掉。

没有银弹

没有任何技术或管理上的进展,能够独立地许诺在十年内使生产率、可靠性或简洁性获得数量级的进步。

这是全书最有名的判断,论证其实很干净。软件的根本任务,是打造由抽象实体构成的复杂概念结构;次要任务,是把这些实体用编程语言写出来、映射成机器能跑的东西。这些年生产率的巨大进步,几乎都来自攻克次要任务。可只要次要任务没占到全部工作的九成,哪怕把它压到零,也换不来数量级的提升。

软件工程归根到底是业务活动:理解实体、构造实体。真正吃时间的是创造性思考,技术实现占比很小。所以没有银弹。

软件项目有”人狼”的特性——看着简单明了的东西,可能变成拖期、超支、缺陷成堆的怪物。于是人人都在找银弹,找那颗能让软件成本像硬件一样雪崩下降的子弹。布鲁克斯当年就问过:AI 会是银弹吗?他的答案是否定的。

但在今天大模型能力涌现的背景下,“打造抽象实体构成的复杂概念结构”这件事,确实有一部分开始能交给 AI 了。这是书里那个否定判断,四十年后第一次被松动的地方。

他当时最看好的是快速原型:先搭起能跑的骨架,不管无效输入和清理,再增量生长。以及最朴素的一条——培养杰出人才。

和优秀的人,做有挑战的事。前提是”和优秀的人”。

再论没有银弹

那些想看到完美方案的人,其实在心底里就认为它以前不存在,以后也不会出现。

后来很多人声称找到了银弹、生产率提高十倍。布鲁克斯的回应是:没有创造性的活儿,才可能被提速。写增删改查已经没什么创造性,写代码只会越来越容易,可创造性思维只会越来越难。

写增删改查固然简单,但写出好的业务代码、给用户真正好的体验,扪心自问,简单吗?

把程序员的核心能力摊开看,技术域和业务域是两条腿:

阶段技术域业务域
开发前基于业务背景挑合适的技术选型了解业务背景与客户诉求
开发中代码是否清晰、设计是否合理,测试与质量业务是否变更,开发是否偏离业务
开发后维护、排查、优化,技术指标监控是否解决了业务问题、收益能否量化

真有工具能让生产率涨十倍、排期缩十倍吗?显然不能。人是有惰性也保守的,就算工具真能提效,排期也不会被压到那么短。

固有的概念复杂性才是根本。它是层次化的,也是最严重的内在困难——软件没有类似物理定律那样的规律性原理可依,只能靠层次化、增量化去应对。作者也列了几颗”铜子弹”:用建模降低思考难度,用质量控制带动效率,还有面向对象。面向对象为什么有用?因为设计大粒度的类,关注的是用户已经接触的概念,很贴业务实体。但他也提醒:面向对象不会加快头一两次开发,要到一个产品族的第五个项目才异乎寻常地快。

子弹再多,本质没变:软件开发是创造性的脑力活,不是重复性的体力活。我们要思考,要对用户和业务负责,而不是照抄一个现成系统。

20 年后再看

纪念版里,布鲁克斯把视野又抬高了一层。第一,概念完整性依然是核心,而且人月神话谈的早已不只是软件,而是任何团队如何协作创造事物——都要沟通、协调、管理、对齐概念。第二,他警告一种新的诱惑:为大型用户群做产品时,PM 会忍不住不停加边界功能。功能初期很诱人,性能代价要到系统测试才暴露;功能越堆越多,手册越来越厚,易用性以你察觉不到的方式一点点流失。

对抗它的办法,是先把用户群定义清楚:他们是谁,真正需要什么,又以为自己需要什么,各自出现的频率有多高。为这些属性明确地记下猜测——哪怕猜错了,清晰的错误也远比模糊不清有用。

全书最后落回一句话:软件的根本困难在概念,不在实现。工具、流程、AI 能削平次要任务,却削不平”想清楚要造什么”这件事。所以没有银弹——能做的,是拆解、沟通、拥抱变化,和优秀的人一起做有挑战的事。