跳转到主要内容

第 1 章 · 焦油坑

大型项目的失败很少由某个单一问题造成,而是问题互相纠缠;而"程序"和"能交付的产品"之间隔着大约 9 倍的工作量。

开篇是一句荷兰谚语:“前车之覆,后车之鉴。” 接着是全书最出名的一个画面——史前巨兽陷在焦油坑里,挣扎得越猛烈,焦油纠缠得越紧,没有哪种猛兽有足够的力气或技巧挣脱,最后都沉到坑底。作者说,过去几十年的大型系统开发就是这样一个焦油坑。

这一章讲了什么

作者先用比喻立论:大型项目的困难不是由某个单独的问题造成的,每个问题单看都能解决,但当它们相互纠缠、累积在一起时,团队的行动就越来越慢。局中人往往对麻烦的程度感到惊讶,也很难看清问题的本质。他的态度是——想解决问题,先了解问题,于是这一章去认识"系统开发这个职业"本身。

第一件事是把"程序"和"产品"分开。图 1-1 画了一条演进路径,两条边界各自加价:

形态要求成本
程序 Program作者能在自己平台的自己环境里跑起来基准
编程产品 Programming Product任何人都能运行、测试、修复、扩展:风格通用化、输入范围适用、详尽的测试用例库、完备文档至少 3 倍
编程系统构件 Programming System按精确定义的接口编制,符合内存、IO、机时等资源限制,并与其他构件以各种组合测试过至少 3 倍
编程系统产品 Programming Systems Product同时满足以上两者约 9 倍

右下角那个 9 倍的形态,“才是真正有用的产品,是大多数系统开发的目标”。

第二件事是职业的两面。作者列了五条乐趣:创造的纯粹快乐;做出的东西对他人有用;把相互啮合的部件组装起来、看它们按预期运转的魅力;因为工作非重复而持续学习;以及在极其易于驾驭的介质上工作——“程序员,就像诗人一样,几乎仅仅在单纯的思考中工作”。

接着是五条苦恼:追求完美(“咒语"里错一个字符、一个停顿,魔术就不出现);目标、资源和信息都由他人设定,个人的权威和他所承担的责任不相配;必须依赖别人的程序,而那些程序往往设计不合理、实现拙劣、发布不完整或文档极差;概念设计有趣,但找琐碎的 bug 是重复劳动,而且调试往往是线性收敛、甚至二次方复杂度的,导致"寻找最后一个错误比第一个错误将花费更多的时间”;最后是产品刚完成就已显陈旧。

章末收束:这就是编程,一个许多人痛苦挣扎的焦油坑,也是一种乐趣与苦恼共存的创造性活动。对许多人而言快乐远大于苦恼,而本书后面各章要做的,是为通过这个焦油坑"搭建一些桥梁"。

我的判断

  • 9 倍这个数字是这一章我最实用的一条收获,它把"写产品和写程序不是一回事"从模糊的直觉变成了可讨论的量级。但它是经验数据,书里没有给出测量方式,所以我的态度是:方向可信,倍数别当真理。它最大的价值不在精确,而在于提醒你那些"非功能"工作(测试用例库、文档、接口规范、组合测试)本身就是主体工作量,不是收尾的装饰。
  • “挣扎得越猛,陷得越深"这个比喻容易被读成宿命论,好在作者自己在章末就拆掉了它——后面各章是"搭桥”。所以焦油坑不是物理定律,而是对蛮力的警告:越是想靠加人和加班硬顶,越容易被缠住。
  • 两组各五条的乐趣与苦恼里,最过时的是最后那条苦恼。1975 年的替代方案还在"构思和安排"阶段,如今技术栈的迭代周期以月计,产品完成即过时的压力其实是被放大了而不是减弱了。
  • 我保留怀疑的是"权威与责任不相配"这一条的推论。作者把它归为编程固有的苦恼,但在别的工程领域同样普遍,所以它更像是组织问题,而不是软件特有的属性——把它当作职业宿命,容易放弃本可以争取的授权。
  • 最认同的一句是"如果我们想解决问题,就必须试图先去了解问题"。它看起来像废话,但对照第 2 章那个著名的加人推演,就知道作者是真的按这句话在做:先把问题算清楚,再谈解决方案。

和我手上的工作有什么关系

  • 9 倍成本这条可以直接对应到我自己的项目:能跑的 demo 和能交付的东西之间,差距往往不在代码量,而在测试用例、文档、接口约束和组合测试。看过这一章之后,我在排期时会把这些显式写出来,而不是默认它们"顺手就做完了"。
  • “权威与责任不相配"精准描述了我见过的一类摩擦:底层驱动工程师对稳定性负责,却决定不了硬件选型和上层调度策略,出问题时责任在他、权限却不在他手上。
  • 依赖他人程序这条在嵌入式里尤其真实:拿到一份没有文档、没有测试用例的 SDK 或第三方库,研究与修改它的时间常常超过自己实现。反过来推给自己的要求就很清楚——我交付的东西至少要让人不用问我就能用起来。

一句话记住

没有哪个单独的问题会让项目失败,但所有问题会一起把你按进焦油坑;而"程序"和"能交付的产品"之间,隔着大约 9 倍的工作量。