# 第 5 章 画蛇添足(The Second-System Effect)
聚沙成塔,集腋成裘。
——奥维德
Adde parvum parvo magnus acervus erit.
[Add little to little and there will be a big pile.]
——OVID
如果将制订功能规格说明的责任从开发快速、成本低廉的产品的责任中分离出来,那么有什么样的准则和机制来约束结构师的创造性热情呢?
基本回答是结构师和建筑人员之间彻底、仔细和谐的交流。另外,还有很多值得关注的、更细致的答案。
# 结构师的交互准则和机制
建筑行业的结构设计师使用估算技术来编制预算,该估算技术会由后续的承包商报价来验证和修正。承包商的报价总会超过预算。接下来,设计师会重新改进他的预算或修订设计,调整到下一期工程。他也可能会向承包商建议,使用更加便宜的方法来实现设计。
类似的过程也支配着计算机系统和计算机编程系统的结构师。相比之下,他有能在设计早期从承包商处得到报价的优势,几乎是只要他询问,就能得到答案。他的不利之处常常是只有一个承包商,后者可以增高或降低前者的估计,来反映对设计的好恶。实际情况中,尽早交流和持续沟通能使结构师有较好的成本意识,以及使开发人员获得对设计的信心,并且不会混淆各自的责任分工。
面对估算过高的难题,结构师有两个选择:削减设计或者建议成本更低的实现方法——挑战估算的结果。后者是固有的主观感性反应。此时,结构师是在向开发人员的做事方式提出挑战。想要成功,结构师必须
- 牢记是开发人员承担创造性和发明性的实现责任,所以结构师只能建议,而不能支配;
- 时刻准备着为所指定的说明建议一种实现的方法,同样准备接受其他任何能达到目标的方法;
- 对上述的建议保持低调和平静;
- 准备放弃坚持所作的改进建议;
一般开发人员会反对体系结构上的修改建议。通常他是对的——当正在实现产品时,某些特性的修改会造成意料不到的成本开销。
# 自律——开发第二个系统所带来的后果
在开发第一个系统时,结构师倾向于精炼和简洁。他知道自己对正在进行的任务不够了解,所以他会谨慎仔细地工作。
在设计第一个项目时,他会面对不断产生的装饰和润色功能。这些功能都被搁置在一边,作为"下一个"项目的内容。第一个项目迟早会结束,而此时的结构师,对这类系统充满了十足的信心,熟练掌握了相应的知识,并且时刻准备开发第二个系统。
第二个系统是设计师们所设计的最危险的系统。而当他着手第三个或第四个系统时,先前的经验会相互验证,得到此类系统通用特性的判断,而且系统之间的差异会帮助他识别出经验中不够通用的部分。
一种普遍倾向是过分地设计第二个系统,向系统添加很多修饰功能和想法,它们曾在第一个系统中被小心谨慎地推迟了。结果如同 Ovid 所述,是一个"大馅饼"。例如,后来被嵌入到 7090 的 IBM 709 系统,709 是对非常成功和简洁的 704 系统进行升级的二次开发项目。709 的操作集合被设计得如此丰富和充沛,以至于只有一半操作被常规使用。
让我们来看看更严重的例子——Stretch 计算机的结构(architecture)、设计实现(implementation)、甚至物理实现(realization),它是很多人被压抑创造力的宣泄出口。如果 Strachey 在评审时所述:
对于 Stretch 系统,我的印象是从某种角度而言,它是一个产品线的终结。如同早期的计算机程序一样,它极富有创造性,极端复杂,非常高效。但不知为什么,同时也感觉到粗糙、浪费、不优雅,以及让人觉得必定存在某种更好的方法。
操作系统 360 对于大多数设计者来说,是第二个系统。它的设计小组成员来自 1410-7010 磁盘操作系统、Stretch 操作系统、Mercury 实时系统项目和 7090 的 IBSYS。几乎没有人有两个以上早期操作系统的经验。因此,OS/360 是典型的第二次开发(second-system effect)的例子,是软件行业的 Stretch 系统。Strachey 的赞誉和批评可以毫无更改地应用在其中。
例如,OS/360 开发了 26 字节的常驻日期翻转例程来正确地处理闰年的 12 月 31 日的问题,其实它完全可以留给操作员来完成。
开发第二个系统所引起的后果(second-system effect)与纯粹的功能修饰和增强明显不同,也就是说存在对某些技术进行细化、精炼的趋势。由于基本系统设想发生了变化,这些技术已经显得落后。OS/360 中有很多这样的例子。
例如,链接编辑器的设计,它用来对分别编译后的程序进行装载,解决它们之间的交叉引用。除了这些基本的功能,它还支持程序的覆盖(overlay)。这是所有实现的覆盖服务程序中最好的一种。它允许链接时在外部完成覆盖结构,而无需在源代码中进行设计。它还允许在运行时刻改变覆盖,而不必重新编译。它配备了丰富的实用选项和各种功能。某种意义上,它是若干年静态覆盖技术开发的顶峰。
然而,它同时也是最后和最优秀的恐龙,因为它属于一个基本运行方式为多道程序,以动态内核分配为基础的系统,这直接与静态覆盖的概念相冲突。如果我们把投入在覆盖管理上的工作量,用在提高动态内核分配和动态交叉引用的性能上,那么系统将会运行得多么好啊!
另外,链接编辑器需要如此大的空间,而且它本身就包含了很多链接库,以至于即使在不使用覆盖管理功能,仅仅使用链接功能的时候,它也比绝大多数系统的编译程序还要慢。具有讽刺意味的是,链接程序的目的是为了避免重新编译。这种情况就像一个挺着大肚子的节食者一样,直到系统的思想已经十分优越时,才开始对原有技术进行细化和精炼。
TESTRAN 调试程序是这个趋势的另一个例子。它在批调试程序中是出类拔萃的,配备了真正优雅的快照和内存信息转储功能。它使用了控制段的概念和卓越的生成技术,从而不需要重新编译或解释,就能实现选择性跟踪和快照。这种 709 共享操作系统中魔术般的概念得到了广泛的使用。
但同时,整个无需重编译的批调试概念变得落伍了。使用语言解释器和增量编译器的交互式计算系统,向它提出了最根本的挑战。即使是在批处理系统中,快速编译/慢速执行编译器的出现,也使源代码级别调试和快照技术成为优先选择的技术。如果在构建和优化交互式和快速编译程序之前,就已经着手 TESTRAN 的开发,那么系统将是多么的优秀啊!
还有另外一个例子是调度程序。OS/360 的调度程序是非常杰出的,它提供了管理固定批作业的杰出功能。从真正意义上讲,该调度程序是作为 1410-7010 磁盘操作系统后续的二次系统,经过了精炼、改进和增强。它是除了输入-输出以外的非多道程序批处理系统,是一种主要用于商业应用的系统。但是,它对 OS/360 的远程任务项、多道程序、永久驻留交互式子系统,几乎完全没有影响和帮助。实际上,OS/360 调度程序的设计使它们变得更加困难。
结构师如何避免画蛇添足——开发第二个系统所引起的后果(second-system effect)?是的,他无法跳过二次系统。但他可以有意识关注那些系统的特殊危险,运用特别的自我约束准则,来避免那些功能上的修饰;根据系统基本理念及目的变更,舍弃一些功能。
一个可以开阔结构师眼界的准则是为每个小功能分配一个值:每次改进,功能 x 不超过 m 字节的内存和 n 微秒。这些值会在一开始作为决策的向导,在物理实现期间充当指南和对所有人的警示。
项目经理如何避免画蛇添足(second-system effect)?他必须坚持至少拥有两个系统以上开发经验结构师的决定。同时,保持对特殊诱惑的警觉,他可以不断提出正确的问题,确保原则上的概念和目标在详细设计中得到完整的体现。