跳转到主要内容

第 6 章 · 贯彻执行

结构师的决策如何让一千个人听到、理解并照做:手册、形式化定义、周例会、多重实现、电话日志与产品测试。

题记引的是杜鲁门论总统权力:“他只是坐在那里,嘴里说’做这个!做那个!‘当然,什么都不会发生,光说不做是没有用的。”

这一章讲了什么

问题很具体:假设项目经理已经有了行事的规范、经验丰富的结构师和一批实现人员,他如何确保每个人听到、理解并实现结构师的决策?一千人开发的系统,十个结构师的小组怎么保住概念完整性?这一章给的是 System/360 硬件设计中摸索出来的六件工具。

手册是基础。它是产品的外部规格说明,描述并规定用户可见的每一个细节,也是结构师的主要工作产物。但仅有文档不够——规格会被反复修改,所以修改必须阶段化,进度表上要有带日期的版本。手册要写全所有用户可见的界面,同时避免描述用户看不见的东西,因为那是实现人员的创造空间;结构师可以为自己描述的特性建议一种实现方法,但不能试图支配实现过程。风格上要求清晰、完整、准确,每条说明重复所有基本要素并彼此一致——“这往往使手册读起来枯燥乏味,但是精确比生动更加重要”。一个惊人的细节:System/360 的 Principles of Operation 文字上的一致性只来自两名作者(Gerry Blaauw 和 Andris Padegs),想法是大约十个人的,但转写成书面规格必须由一两个人完成。作者特别称赞 Blaauw 写的那份兼容性附录,因为它不只定义了规定什么,还定义了未规定什么

形式化定义是第二种工具。人类语言不精确,形式化标记精确且倾向完整,“差异越明显,填补得越快”,代价是不易理解;记叙性文字能表达原则、层次、实例、异常,最重要的是能解释原因。所以他的结论是两者并用,但必须明确以谁为标准:Algol 68 以形式化定义为准,PL/I 以记叙性文字为准,System/360 也是记叙性为准、形式化作为派生论述。他还专门警告,形式化定义几乎总会滑向描述某个设计实现——而实现规定了太多东西。

这条警告接着被推到一个更尖锐的形态:把实现本身当定义。做法是"新机器与原有机器一致",遇到手册模糊处就"问一问机器"——写段程序测出行为,新机器照此运行。优点是所有问题都能靠试验得到迅速而精确的答案,从不需要争辩;缺点压过了优点:实现会过度规定外部功能。他举的例子很妙——在 System/360 上模拟 IBM 1401 时,有 30 个被认为无效操作的副作用被广泛使用,最终成了定义的一部分;而这类"粗糙"的功能在别的实现里往往低效或代价高昂(比如乘法运算后把垃圾留在被乘数寄存器,一旦成为定义的一部分,就会阻止某些快速乘法算法)。用实现当标准,还必须禁止对实现的任何修改。

直接整合是给软件结构师的一种更可爱的方法:为模块间接口设计声明(参数或共享存储器),要求实现在编译期包含这些声明——PL/I 的宏或 %INCLUDE 就是这种机制。接口只通过符号名称引用,于是修改声明时只需增删变量、重新编译,使用方程序不必改动。

会议分成两级。周例会是每周半天,所有结构师、硬软件实现人员代表和市场计划人员参加,由首席系统结构师主持:建议书通常会前以书面形式分发,会上重点在创新而不只是结论,小组先设法找出各种解法,再把少数方案交给结构师写成正式的变更建议;随后对建议做决策,往返几轮,正面与负面意见都被完整描述。达成共识最好,达不成由首席结构师决定。作者列了这套机制有效的五个原因:同一个小组每周交流、不需要额外培训;成员都与产品相关、没人扮演"顾问"、每个人都承担义务;问题出现时同时在界线内外找方案;正式书面建议强制了决策、避免了草稿纪要的不一致;以及明确授予首席结构师决策权,避免妥协和拖延。

年度大会则是给"堆积起来的小事"准备的:一些决定没贯彻好,一些小事情没被真正接受,有些决定引来新问题,而周例会又不愿重新翻案,于是不满慢慢堆积。大会在手册冻结前夕开,持续两周(作者说若由他重排会改成每半年一次),出席者包括体系结构小组、编程与实现人员代表、编程经理、市场和实现人员,由项目经理主持,议程约 200 条。通过出色的计算机化文本编辑,每天早晨与会者在座位上拿到已更新的手册,记录前一天的决议。作者称它为"收获的节日":不仅解决决策问题,还让决策更容易被接受——每个人都在倾听、参与,对复杂约束之间的相互关系理解更透彻。

多重实现是 System/360 结构师独有的优势条件之一。大多数项目里,机器和手册迟早会出现不一致,而人们通常忽略手册——因为改手册比改机器便宜。但当同一份规格被多个独立实现同时遵守时,天平反转了:让机器去符合手册的成本,反而低于让手册去迁就机器。所以多实现之间的兼容性要求,是"强制规格说明的最佳代言人"。同理,定义编程语言时如果起初就有两种以上实现,定义会更整洁规范。

电话日志处理规格说明无法穷尽的解释问题。作者的要求很朴素:鼓励有疑问的实现人员打电话问结构师,而不是一边猜测一边干活;同时答案必须是能告知所有人的权威结论。机制是结构师自己记录每个问题和回答,每周把若干人的日志合并、整理、分发给用户和实现人员——不正式,但快捷易懂。

最后是产品测试。作者的开场句很漂亮:“项目经理最好的朋友就是他每天要面对的对手”——独立的产品测试小组。它按规格说明检查程序,充当麻烦的代言人,专门找出未贯彻执行的地方、被误解的设计决策。每个开发机构都需要这样一个独立的技术监督部门以保证公正,因为最终用户才是那个独立监督者,而测试小组是顾客的代理人。它的结论是:测试小组不只是质量关口,更是让设计决策得以贯彻的必要手段,因此必须尽早着手、与设计同步实施

我的判断

  • 这一章把前四章的抽象论证落地成了机制,我读下来最有价值的一点是:概念完整性不是靠反复宣讲维持的,而是靠结构强制维持的。手册的阶段化版本、形式化与记叙性的主辅分工、多重实现带来的兼容压力、电话日志的单一权威答案,这些全是把"共识"变成"约束"的手段。
  • “定义兼容性时还必须定义未规定什么”,这句话超出了软件范畴。绝大多数接口文档只写"支持什么",读的人无法判断某个边界行为到底是被承诺的还是碰巧的。作者那句话等于要求作者承担消极定义的责任,这是很少见的严格。
  • 我特别认同"把实现当定义"的批评,因为它在今天极其常见:接口行为以现有实现为准,测试用例成为事实上的规范。作者点出了代价——无效操作的副作用会被用户当成契约,而一旦成为契约,某些更好的实现方式就被永久堵死。这是技术债里最难还的一种。
  • 周例会那五条有效原因里,最容易被忽略的是"没有人是顾问的角色,每个人都要承担义务"。参与决策的人与承担后果的人必须是同一批,否则会议就会退化成意见征集。
  • 我对年度大会这种形式持保留:两周、200 条议程、项目经理主持,只在超大项目里成立。但它的内核——给"堆积起来的不满"一个定期清算的场合——非常值得移植到小团队,我自己的做法是把它压缩成定期回顾,只是很容易因为不急而取消。
  • 产品测试被定义为"顾客的代理人",而不是"质量检查员"。这个身份差异很关键:检查员对流程负责,代言人对用户负责,后者才有资格质疑"我们是不是做错了"。

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

  • 这个站点现在的 AGENTS.mddocs/reading-protocol.md 扮演的就是"手册"的角色:把稳定的约定集中在一处,让每次协作不必重新解释。这一章提醒我,手册必须阶段化——所以我把关键决定同时记进 docs/sessions/,让约定能追溯到"哪一天、因为什么"变成这样。
  • “直接整合"这条我有现成对应物:站点用 bin/build.sh 作为唯一构建入口,CI 与 Cloudflare 都调它,改一处即全局生效。这就是接口只通过符号名称引用的效果,避免三份配置各自漂移。
  • 电话日志的现代等价物是会话记录。作者要求结构师把每个问题和回答记下来、每周合并分发;我把 docs/sessions/ 当作这个日志用,它解决的是同一个问题——同一个人重复被问同一件事
  • 多重实现那条给了我一个可执行的启发:同一份内容如果有两个独立消费者,规范就会被逼着变清楚。我的站点每页同时产出 HTML 与 Markdown 供人和 Agent 读取,这个双出口本身就是一种兼容性压力,会不断暴露表述含混的地方。
  • 我最缺的是"顾客的代理人”。目前没有独立测试环节,只有我自己事后复查——按这一章的判据,这意味着很多设计决策是否真的被贯彻执行,其实无人验证。

一句话记住

决策被听见不等于被贯彻;靠手册的统一文字、多重实现的兼容压力、会议上的明确授权、日志里的权威答案,加上一个专找麻烦的测试小组,概念才真的落到产品里。