第二个系统是设计师们所设计的最危险的系统。而当他着手第三个或第四个系统时,先前的经验会相互验证,得到此类系统通用特性的判断,而且系统之间的差异会帮助他识别出经验中不够通用的部分。
一种普遍倾向是过分地设计第二个系统,向系统添加很多修饰功能和想法,它们曾在第一个系统中被小心谨慎地推迟了。结果如同Ovid所述,是一个“大馅饼”。例如,后来被嵌入到7090的IBM 709系统,709是对非常成功和简洁的704系统进行升级的二次开发项目。709的操作集合被设计得如此丰富和充沛,以至于只有一半操作被常规使用。
让我们来看看更严重的例子——Stretch计算机的结构(architecture)、设计实现(implementation)、甚至物理实现(realization),它是很多人被压抑创造力的宣泄出口。如果Strachey在评审时所述:
对于Stretch系统,我的印象是从某种角度而言,它是一个产品线的终结。如同早期的计算机程序一样,它极富有创造性,极端复杂,非常高效。但不知为什么,同时也感觉到粗糙、浪费、不优雅,以及让人觉得必定存在某种更好的方法1。
操作系统360对于大多数设计者来说,是第二个系统。它的设计小组成员来自1410-7010磁盘操作系统、Stretch操作系统、Mercury实时系统项目和7090的IBSYS。几乎没有人有两个以上早期操作系统的经验2。因此,OS/360是典型的第二次开发(second-system effect)的例子,是软件行业的Stretch系统。Strachey的赞誉和批评可以毫无更改地应用在其中。
例如,OS/360开发了26字节的常驻日期翻转例程来正确地处理闰年的12月31日的问题,其实它完全可以留给操作员来完成。
开发第二个系统所引起的后果(second-system effect)与纯粹的功能修饰和增强明显不同,也就是说存在对某些技术进行细化、精炼的趋势。由于基本系统设想发生了变化,这些技术已经显得落后。OS/360中有很多这样的例子。
例如,链接编辑器的设计,它用来对分别编译后的程序进行装载,解决它们之间的交叉引用。除了这些基本的功能,它还支持程序的覆盖(overlay)。这是所有实现的覆盖服务程序中最好的一种。它允许链接时在外部完成覆盖结构,而无需在源代码中进行设计。它还允许在运行时刻改变覆盖,而不必重新编译。它配备了丰富的实用选项和各种功能。某种意义上,它是若干年静态覆盖技术开发的顶峰。
然而,它同时也是最后和最优秀的恐龙,因为它属于一个基本运行方式为多道程序,以动态内核分配为基础的系统,这直接与静态覆盖的概念相冲突。如果我们把投入在覆盖管理上的工作量,用在提高动态内核分配和动态交叉引用的性能上,那么系统将会运行得多么好啊!
另外,链接编辑器需要如此大的空间,而且它本身就包含了很多链接库,以至于即使在不使用覆盖管理功能,仅仅使用链接功能的时候,它也比绝大多数系统的编译程序还要慢。具有讽刺意味的是,链接程序的目的是为了避免重新编译。这种情况就像一个挺着大肚子的节食者一样,直到系统的思想已经十分优越时,才开始对原有技术进行细化和精炼。
TESTRAN调试程序是这个趋势的另一个例子。它在批调试程序中是出类拔萃的,配备了真正优雅的快照和内存信息转储功能。它使用了控制段的概念和卓越的生成技术,从而不需
要重新编译或解释,就能实现选择性跟踪和快照。这种709共享操作系统3中魔术般的概念得到了广泛的使用。
但同时,整个无需重编译的批调试概念变得落伍了。使用语言解释器和增量编译器的交互式计算系统,向它提出了最根本的挑战。即使是在批处理系统中,快速编译/慢速执行编译器的出现,也使源代码级别调试和快照技术成为优先选择的技术。如果在构建和优化交互式和快速编译程序之前,就已经着手TESTRAN的开发,那么系统将是多么的优秀啊!
还有另外一个例子是调度程序。OS/360的调度程序是非常杰出的,它提供了管理固定批作业的杰出功能。从真正意义上讲,该调度程序是作为1410-7010磁盘操作系统后续的二次系统,经过了精炼、改进和增强。它是除了输入-输出以外的非多道程序批处理系统,是一种主要用于商业应用的系统。但是,它对OS/360的远程任务项、多道程序、永久驻留交互式子系统,几乎完全没有影响和帮助。实际上,OS/360调度程序的设计使它们变得更加困难。
结构师如何避免画蛇添足——开发第二个系统所引起的后果(second-system effect)?是的,他无法跳过二次系统。但他可以有意识关注那些系统的特殊危险,运用特别的自我约束准则,来避免那些功能上的修饰;根据系统基本理念及目的变更,舍弃一些功能。
一个可以开阔结构师眼界的准则是为每个小功能分配一个值:每次改进,功能x不超过m字节的内存和n微秒。这些值会在一开始作为决策的向导,在物理实现期间充当指南和对所有人的警示。
项目经理如何避免画蛇添足(second-system effect)?他必须坚持至少拥有两个系统以上开发经验结构师的决定。同时,保持对特殊诱惑的警觉,他可以不断提出正确的问题,确保原则上的概念和目标在详细设计中得到完整的体现。
贯彻执行(Passing the Word)
他只是坐在那里,嘴里说:“做这个!做那个!”当然,什么都不会发生,光说不做是没有用的。
- 哈里·杜鲁门,关于总统的权力1
He'll sit here and he'll say, "Do this! Do that!" And nothing will happen.
- HARRY S. TRUMAN, ON PRESIDENTIAL POWER1
假设一个项目经理已经拥有行事规范的结构师和许多编程实现人员,那么他如何确保每个人听从、理解并实现结构师的决策?对于一个由1000人开发的系统,一个10个结构师的小组如何保持系统概念上的完整性?在System/360硬件设计工作中,我们摸索出来一套实现上述目标的方法,它们对于软件项目同样适用。
文档化的规格说明——手册
手册、或者书面规格说明,是一个非常必要的工具,尽管光有文档是不够的。手册是产品的外部规格说明,它描述和规定了用户所见的每一个细节;同样的,它也是结构师主要的工作产物。
随着用户和实现人员反馈的增加,规格说明中难以使用和难以构建实现的地方不断被指出,规格说明也不断地被重复准备和修改。然而对实现人员而言,修改的阶段化是很重要的——在进度表上应该有带日期的版本信息。
手册不但要描述包括所有界面在内的用户可见的一切,它同时还要避免描述用户看不见的事物。后者是编程实现人员的工作范畴,而实现人员的设计和创造是不应该被限制的。体系结构设计人员必须为自己描述的任何特性准备一种实现方法,但是他不应该试图支配具体的实现过程。
规格说明的风格必须清晰、完整和准确。用户常常会单独提到某个定义,所以每条说明都必须重复所有的基本要素,所以所有文字都要相互一致。这往往使手册读起来枯燥乏味,但是精确比生动更加重要。
System/360 Principles of Operation的一致完整性来自仅有两名作者的事实:Gerry Blaauw和Andris Padegs。思路是大约十个人的想法,但如果想保持文字和产品之间的一致性,则必须由一个或两个人来完成将其结论转换成书面规格说明的工作。而且,将定义书写成文字,必须对很多原先并不是非常重要的问题进行判断,并得出结论。例如,System/360需要决定在每次操作后,如何设置返回的条件码。其实,对于在整个设计中,保证这些看似琐碎的问题处理原则上的一致性,决不是一件无关紧要的事情。
我想我所见过的最好的一份手册是System360 Principles of Operation的附录。它精确仔细地规定了System/360兼容性的限制。它定义了兼容性,描述了将达到的目标,列举了很多外部显示的各个部分:源于某个模型与其他模型差异,带来变化的部分和保持不变的部分;或者是某个给定模型的拷贝不同于其他拷贝的地方;甚至是工程上的变更引起拷贝自身上的差异。而这正是一个规格说明作者所应该追求的精确程度,他必须在仔细定义规定什么的同时,定义未规定什么。
形式化定义
英语或者其他任何的人类语言,从根本上说,都不是一种能精确表达上述定义的手段。因此,手册的作者必须注意自己的思路和语言,达到所需要的精确程度。一种颇具吸引力的作法是对上述定义使用形式化标记方法。毕竟,精确度是我们需要的东西,这也正是形式化标记方法存在的理由和原因。
让我们来看一看形式化定义的优点和缺点。如文中所示,形式化定义是精确的,它们倾向于更加完整;差异得更加明显,可以更快地完成。但是形式化定义的缺点是不易理解。记叙性文字则可以显示结构性的原则,描述阶段上或层次上的结构,以及提供例子。它可以很容易地表达异常和强调对比的关系,最重要的是,它可以解释原因。在表达的精确和简明性上,目前所提出的形式化定义,具有了令人惊异的效果,增强了我们进行准确表达的信心。但是,它还需要记叙性文字的辅助,才能使内容易于领会和讲授。出于这些原因,我想将来的规格说明同时包括形式化和记叙性定义两种方式。
一句古老的格言警告说:“决不要携带两个时钟出海,带一个或三个。”同样的原则也适用于形式化和记叙性定义。如果同时具有两种方式,则必须以一种作为标准,另一种作为辅助描述,并照此明确地进行划分。它们都可以作为表达的标准,例如,Algol 68采用形式化定义作为标准,记叙性文字作为辅助。PL/I使用记叙性定义作为主要方式,形式化定义用作辅助表述。System/360也将记叙性文字用作标准,以及形式化定义用作派生的论述。
很多工具可以用于形式化定义,例如巴科斯范式在语言定义中很常用,它在书本中有详细的描述2。PL/I的形式化定义使用了抽象语法的新概念,该概念有很确切的解释3。Iverson的APL曾用来描述机器,突出的应用是IBM 70904和System/3605。
Bell和Newell建议了能同时描述配置和机器结构的新标注方法,并且在许多机型的应用上得以体现,如DEC PDP-86、70908、System/360。
在规定系统外部功能的同时,几乎所有的形式化定义均会用来描述和表达硬件系统或软件系统的某个设计实现。语法和规则的表达可以不需要具体的设计实现,但是特定的语义和意义通常会通过一段实现该功能的程序来定义。理所当然,这是一种实现,不过它过多地限定了体系结构。所以必须特别指出形式化定义仅仅用于外部功能,说明它们是什么。
如同前面所示,形式化定义可以是一种设计实现。反之,设计实现也可以作为一种形式化定义的方法。当制造第一批兼容性的计算机时,我们使用的正是上述技术:新的机器同原有的机器一致。如果手册有一些模糊的地方?“问一问机器!”——设计一段程序来得到其行为,新机器必须按照上述结果运行。
硬件或软件系统的仿真装置,可以按照相同的方式完整运用。它是一种实现,可以运行。因此,所有定义的问题可以通过测试来解决。
使用实现来作为一种定义的方式有一些优点。首先,所有问题可以通过试验清晰地得到答案,从来不需要争辩和商讨,回答是快捷迅速的。通过定义得出的答案,总是同所要求的一样精确和正确。但是,相对于这些优点的,是一系列可怕的缺点。实现可能更加过度地规定了外部功能。例如,无效的语法通常会产生某些结果。在拥有错误控制的系统中,它通常仅仅导致某种“无效”的指示,而不会产生其他的东西。在无错误控制的系统中,会产生各种副作用,它们可能被程序员所使用。例如,当我们着手在System/360上模拟IBM 1401时,有30个不同的“古玩”——被认为是无效操作的副作用——得到广泛的应用,并被认为是定义的一部分。作为一种定义,实现体现了过多的内容:它不但描述了系统必须做什么,
同时还声明了自己到底做了些什么。
因此,当尖锐的问题被提及时,实现有时会给出未在计划中的意外答案;这些答案中,真正的定义常常是粗糙的,因为它们从来没有被仔细考虑过。这些粗糙的功能在其他的设计实现中,往往是低效或者代价高昂的。例如,一些机器在乘法运算之后,将某些运算的垃圾遗留在被乘数寄存器中。该功能确切的特性,即保存运算垃圾,成为了真正定义的一部分。然而,重复该细节可能会阻止某些快速乘法算法的使用。
最后,关于实际使用标准是形式化描述还是叙述性文字这一点而言,使用实现作为形式化定义特别容易引起混淆,特别是在程序化的仿真中。另外,当实现充当标准时,还必须防止对实现的任何修改。
直接整合
对软件系统的体系结构师而言,存在一种更加可爱的方法来分发和强制定义。对于建立模块间接口语法,而非语义时,它特别有用。这项技术是设计被传递参数和共享存储器的声明,并要求编程实现在编译时的一些操作(PL/I的宏或%INCLUDE)来包含这些声明。另外,如果整个接口仅仅通过符号名称进行引用,那么需要修改声明的时候,可以通过增加或插入新变量,或者重新编译受影响的程序。这种方法不需要修改程序内容。
会议和大会
无需多说,会议是必要的。然而,数百人在场的大型磋商会议往往需要大规模和非常正式地召集。因此,我们把会议分成两个级别:周例会和年度大会——这实际上是一种非常有效的方式。
周例会是每周半天的会议,由所有的结构师,加上硬件和软件实现人员代表和市场计划人员参与,由首席系统结构师主持。
会议中,任何人可以提出问题和修改意见,但是建议书通常是以书面形式,在会议之前分发。新问题通常会被讨论一些时间。重点是创新,而不仅仅是结论。该小组试图发现解决问题的新方法,然后少数解决方案会被传递给一个和几个结构师,详细地记录到书面的变更建议说明书中。
接着会对详细的变更建议做出决策。这会经历几个反复过程,实现人员和用户会仔细地进行考虑,正面和负面的意见都会被很好地描述。如果达成了共识,非常好;如果没有,则由首席结构师来决定。这需要花费时间,最终所发布的结论是正式和果断的。
周例会的决策会给出迅捷的结论,允许工作继续进行。如果任何人对结果过于不高兴,可以立刻诉诸于项目经理,但是这种情况非常少见。
这种会议的卓有成效是由于:
1. 数月内,相同小组——结构师、用户和实现人员——每周交流一次。因此,大家对项目相关的内容比较了解,不需要安排额外时间对人员进行培训。
2. 上述小组十分睿智和敏锐,深刻理解所面对的问题,并且与产品密切相关。没有人是“顾问”的角色,每个人都要承担义务。
3. 当问题出现时,在界线的内部和外部同时寻求解决方案。
4. 正式的书面建议集中了注意力,强制了决策的制订,避免了会议草稿纪要方式的不一致。
5. 清晰地授予首席结构师决策的权力,避免了妥协和拖延。
随着时间的推移,一些决定没有很好地贯彻,一些小事情并没有被某个参与者真正地接受,其他决定造成了未曾遇到的问题。对于这些问题,有时周例会没有重新考虑,慢慢地,很多小要求、公开问题或者不愉快会堆积起来。为解决这些堆积起来的问题,我们会举行年度大会,典型的年度大会会持续两周。(如果由我重新安排,我会每六个月举行一次。)
这些会议在手册冻结的前夕召开。出席人员不仅仅包括体系结构小组和编程人员、实现人员的结构代表,同时包括编程经理、市场和实现人员,由System/360的项目经理主持。议程典型地包括大约200个条目,大多数条目的规模很小,它们列举在会议室周围的图表上,每个不同的声音都有机会得到表达。然后,会制订出决策,加上出色的计算机化文本编辑工作(许多优秀员工的卓越的工作成果)。每天早晨,会议参与人员会在座位上发现更新了的手册说明,记录了前一天的各项决定。
这些“收获的节日”不仅可以解决决策上的问题,而且使决策更容易被接受。每个人都在倾听,每个人都在参与,每个人对复杂约束和决策之间的相互关系有了更透彻的理解。
多重实现
System/360的结构师具有两个空前有利的条件:充足的工作时间,拥有与实现人员相同的策略影响力。充足时间来自新技术的开发日程;而多重实现的同时开发带来了策略上的平等性。不同实现之间严格要求相互兼容,这种必要性是强制规格说明的最佳代言人。
在大多数计算机项目中,机器和手册之间往往会在某一天出现不一致,人们通常会忽略手册。因为与机器相比,手册更容易改动,并且成本更低。然而,当存在多重实现时,情况就不是这样。这时,如实地遵从手册更新机器所造成的延迟和成本的消耗,比根据机器调整手册要低。
在定义某编程语言的时候,上述概念可以卓有成效地得到应用。可以肯定的是,迟早会有很多编译器或解释器被推出,以满足各种各样的目标。如果起初至少有两种以上的实现,那么定义会更加整洁和规范。
电话日志
随着实现的推进,无论规格说明已经多么精确,还是会出现无数结构理解和解释方面的问题。显然有很多问题需要文字澄清和解释,还有一些仅仅是因为理解不当。
显然,对于存有疑问的实现人员,应鼓励他们打电话询问相应的结构师,而不是一边自行猜测一边工作,这是一项很基本的措施。他们还需要认识到的是,上述问题的答案必须是可以告知每个人的权威性结论。
一种有用的机制是由结构师保存电话日志。日志中,他记录了每一个问题和相应的回答。每周,对若干结构师的日志进行合并,重新整理,并发布给用户和实现人员。这种机制很不正式,但非常快捷和易于理解。
产品测试
项目经理最好的朋友就是他每天要面对的敌人——独立的产品测试机构/小组。该小组根据规格说明检查机器和程序,充当麻烦的代言人,查明每一个可能的缺陷和相互矛盾的地方。每个开发机构都需要这样一个独立的技术监督部门,来保证其公正性。
在最后的分析中,用户是独立的监督人员。在残酷的现实使用环境中,每个细微缺陷都将无从遁形。产品-测试小组则是顾客的代理人,专门寻找缺陷。不时地,细心的产品测试人员总会发现一些没有贯彻执行、设计决策没有正确理解或准确实现的地方。出于这方面的原因,设立测试小组是使设计决策得以贯彻执行的必要手段,同样也是需要尽早着手,与设计同时实施的重要环节。
为什么巴比伦塔会失败?(Why Did the Tower of Babel Fail?)
现在整个大地都采用一种语言,只包括为数不多的单词。在一次从东方往西方迁徙的过程中,人们发现了苏美尔地区,并在那里定居下来。接着他们奔走相告说:“来,让我们制造砖块,并把它们烧好。”于是,他们用砖块代替石头,用沥青代替灰泥(建造房屋)。然后,他们又说:“来,让我们建造一座带有高塔的城市,这个塔将高达云宵,也将让我们声名远扬,同时,有了这个城市,我们就可以聚居在这里,再也不会分散在广阔的大地上了。”于是上帝决定下来看看人们建造的城市和高塔,看了以后,他说:“他们只是一个种族,使用一种的语言,如果他们一开始就能建造城市和高塔,那以后就没有什么难得倒他们了。来,让我们下去,在他们的语言里制造些混淆,让他们相互之间不能听懂。”这样,上帝把人们分散到世界各地,于是他们不得不停止建造那座城市。(创世纪,11:1-8)
Now the whole earth used only one language, with few words. On the occasion of a migration from the east, men discovered a plain in the land of Shinar, and settled there. Then they said to one another, "Come, let us make bricks, burning them well." So they used bricks for stone, and bitumen for mortar. Then they said, "Come, let us build ourselves a city with a tower whose top shall reach the heavens (thus making a name for ourselves), so that we may not be scattered all over the earth." Then the Lord came down to look at the city and tower which human beings had built. The Lord said, "They are just one people and they all have the same language. If this is what they can do as a beginning, then nothing that they resolve to do will be impossible for them. Come, let us go down, and there make such a babble of their language that they will not understand one another's speech." Thus the Lord dispersed them from there all over the earth, so that they had to stop building the city. (Book of Genesis, 11:1-8).
巴比伦塔的管理教训
据《创世纪》记载,巴比伦塔是人类继诺亚方舟之后的第二大工程壮举,但巴比伦塔同时也是第一个彻底失败的工程。
这个故事在很多方面和不同层次都是非常深刻和富有教育意义的。让我们将它仅仅作为纯粹的工程项目,来看看有什么值得学习的教训。这个项目到底有多好的先决条件?他们是否有:
1. 清晰的目标?是的,尽管幼稚得近乎不可能。而且,项目早在遇到这个基本的限制之前,就已经失败了。
2. 人力?非常充足。
3. 材料?在美索不达米亚有着丰富的泥土和柏油沥青。
4. 足够的时间?没有任何时间限制的迹象。
5. 足够的技术?是的,金字塔、锥形的结构本身就是稳定的,可以很好分散压力负载。对砖石建筑技术,人们有过深刻的研究。同样,项目远在达到技术限制之间,就已经失败了。
那么,既然他们具备了所有的这些条件,为什么项目还会失败呢?他们还缺乏些什么?两个方面——交流,以及交流的结果——组织。他们无法相互交谈,从而无法合作。当合作无法进行时,工作陷入了停顿。通过史书的字里行间,我们推测交流的缺乏导致了争辩、沮丧和群体猜忌。很快,部落开始分裂——大家选择了孤立,而不是互相争吵。
大型编程项目中的交流
现在,其实也是这样的情况。因为左手不知道右手在做什么,所以进度灾难、功能的不合理和系统缺陷纷纷出现。随着工作的进行,许多小组慢慢地修改自己程序的功能、规模和速度,他们明确或者隐含地更改了一些有效输入和输出结果用法上的约定。
例如,程序覆盖(program-overlay)功能的实现者遇到了问题,并且统计报告显示了应用程序很少使用该功能。基于这些考虑,他降低了覆盖功能的速度。与此同时,整个开发队伍中,其他同事正在设计监控程序。监控程序在很大程度上依赖于覆盖功能,它在速度上的变化成为了主要的规格说明变更。因此需要从系统角度来考虑和衡量该变化,以及公开、
广泛地发布变更结果。
那么,团队如何进行相互之间的交流沟通呢?通过所有可能的途径。
非正式途径
清晰定义小组内部的相互关系和充分利用电话,能鼓励大量的电话沟通,从而达到对所书写文档的共同理解。
会议
常规项目会议。会议中,团队一个接一个地进行简要的技术陈述。这种方式非常有用,能澄清成百上千的细小误解。
工作手册。
在项目的开始阶段,应该准备正式的项目工作手册。理所应当,我们专门用一节来讨论它。
项目工作手册
是什么。项目工作手册不是独立的一篇文档,它是对项目必须产出的一系列文档进行组织的一种结构。
项目所有的文档都必须是该结构的一部分。这包括目的、外部规格说明、接口说明、技术标准、内部说明和管理备忘录。
为什么。技术说明几乎是必不可少的。如果某人就硬件和软件的某部分,去查看一系列相关的用户手册。他发现的不仅仅是思路,而且还有能追溯到最早备忘录的许多文字和章节,这些备忘录对产品提出建议或者解释设计。对于技术作者而言,文章的剪裁粘贴与钢笔一样有用。
基于上述理由,再加上“未来产品”的质量手册将诞生于“今天产品” 的备忘录,所以正确的文档结构非常重要。事先将项目工作手册设计好,能保证文档的结构本身是规范的,而不是杂乱无章的。另外,有了文档结构,后来书写的文字就可以放置在合适的章节中。
使用项目手册的第二个原因是控制信息发布。控制信息发布并不是为了限制信息,而
是确保信息能到达所有需要它的人的手中。
项目手册的第一步是对所有的备忘录编号,从而每个工作人员可以通过标题列表来检索是否有他所需要的信息。还有一种更好的组织方法,就是使用树状的索引结构。而且如果需要的话,可以使用树结构中的子树来维护发布列表。
处理机制。同许多其它的软件管理问题一样,随着项目规模的扩大,技术备忘录的问题以非线性趋势增长。10人的项目,文档仅仅通过简单的编号就可以了。100人的项目,若干个线性索引常常可以满足要求。1000人的项目,人员无可避免地散布在多个地点,对结构化工作手册的需要和手册规模上的要求都紧迫了许多。那么,用什么样的机制来处理呢?
我认为OS/360项目做得非常好。O.S.Locken强烈要求制订结构良好的工作手册,他本人在他的前一个项目1410-7010操作系统中,看到了工作手册的效果。
我们很快决定了每一个编程人员应该了解所有的材料,即在每间办公室中应保留一份工作手册的拷贝。
工作手册的实时更新是非常关键的。工作手册必须是最新的,如果每次变更都要重新打印所有的文档,实际上这很难做到。不过,如果采用活页夹的方式,则仅需更换变更页。我们当时拥有计算机编辑系统,它对实时维护有不可思议的帮助。编辑、排版、打印的工作直接在计算机和打印机上完成,周转时间少于一天。但即便如此,所有接收的人员还是会面临消化理解的问题。当他第一次收到更改页时,他需要知道,“修改了什么?”迟些时候,当他就问题进行咨询时,他需要知道,“现在的定义是什么?”。
理解的问题可以通过持续的文档维护来解决。文档变更的强调有若干个步骤。首先,必须在页面上标记发生改变的文本,例如,使用页边上的竖线标记每行变化的文字。第二,分发的变更页附带独立的总结性文字,对变更的重要性以及批注进行记录。
这种机制在我们项目中碰到别的问题之前,稳定运行了六个月。工作手册大约厚达1.5米!如果将我们在曼哈顿Time-Life大厦办公室里所使用的100份手册叠在一起,它们比这座大厦还要高。另外,每天分发的变更页大约5厘米,归入档案的页数大概有150页。日常工作手册的维护工作占据了每个工作日的大量时间。
这个时候,我们换用了微缩胶片,在为每个办公室配备了微缩胶片阅读机之后,节约了大量金钱,工作手册的体积减少了18倍。更重要的是,对数百页更新工作的帮助——微
缩胶片大量地减轻了归档问题。
微缩胶片有它的缺点。从管理的角度而言,笨拙的文字归档工作确保了所有变更会被阅读,这正是工作手册要达到的目的。微缩胶片使工作手册的维护工作变得过于简单,除非列举变化的文字说明和变更胶片一起分发。
另外,微缩胶片不容易被读者强调、标记和批注。对作者来说,采用文档方式与读者沟通更加有效;对读者来说,文档更加容易使用。
总之,我觉得微缩胶片是非常好的一种方法。对于大型项目,我建议把它作为文字工作手册的补充。
现在如何入手?在当今很多可以应用的技术中,我认为一种选择是采用可以直接访问的文件。在文件中,记录修订日期记录和标记变更标识条。每个用户可以从一个显示终端(打印机太慢了)来查阅。每日维护的变更小结以“后进先出”的方式保存,在一个固定的地方提供访问。编程人员可能会每天阅读,但如果错过了一天,他只需在第二天多花一些时间。在他查看小结的同时,他可以停下来,去查询变更的文字。
注意工作手册本身没有发生变化。它还是所有项目文档的集合,根据某种经过细致考虑的规则组织在一起。唯一发生改变的地方是分发机制和查询方法。斯坦福研究机构的D.C.Engelbart和同事开发了一套系统,并用它在ARPA网络项目中建立和维护文档。
卡内基-梅隆大学的D.L.Parnas提出了更彻底的解决方法1。他认为,编程人员仅了解自己负责的部分,而不是整个系统的开发细节时,工作效率最高。这种方法的先决条件是精确和完整地定义所有接口。这的确是一个彻底的解决方法。如果能处理得好,的确是能解决很多“灾难”。一个好的信息系统不但能暴露接口错误,还能有助于改正错误。
大型编程项目的组织架构
如果项目有n个工作人员,则有(n2 - n)/ 2个相互交流的接口,有将近2n个必须合作的潜在团队。团队组织的目的是减少不必要交流和合作的数量,因此良好的团队组织是解决上述交流问题的关键措施。
减少交流的方法是人力划分(division of labor)和限定职责范围(specialization of function)。当使用人力划分和职责限定时,树状管理结构所映出对详细交流的需要会相
应减少。
事实上,树状组织架构是作为权力和责任的结构出现。其基本原理——管理角色的非重复性——导致了管理结构是树状的。但是交流的结构并未限制得如此严格,树状结构几乎不能用来描述交流沟通,因为交流是通过网状结构进行的。在很多工程活动领域,树状模拟结构不能很精确地用于描述一般团队、特别工作组、委员会,甚至是矩阵结构组织。
让我们考虑一下树状编程队伍,以及要使它行之有效,每棵子树所必须具备的基本要素。它们是:
1. 任务(a mission)
2. 产品负责人(a producer)
3. 技术主管和结构师(a technical director or architect)
4. 进度(a schedule)
5. 人力的划分(a division of labor)
6. 各部分之间的接口定义(interface definitions among the parts)
所有这些是非常明显和约定俗成的,除了产品负责人和技术主管之间有一些区别。我们先分析一下两个角色,然后再考虑它们之间的关系。
产品负责人的角色是什么?他组建团队,划分工作及制订进度表。他要求,并一直要求必要的资源。这意味着他主要的工作是与团队外部,向上和水平地沟通。他建立团队内部的沟通和报告方式。最后,他确保进度目标的实现,根据环境的变化调整资源和团队的构架。
那么技术主管的角色是什么?他对设计进行构思,识别系统的子部分,指明从外部看上去的样子,勾画它的内部结构。他提供整个设计的一致性和概念完整性;他控制系统的复杂程度。当某个技术问题出现时,他提供问题的解决方案,或者根据需要调整系统设计。用Al Capp所喜欢的一句谚语,他是“攻坚小组中的独行侠”(inside-man at the skunk works.)。他的沟通交流在团队中是首要的。他的工作几乎完全是技术性的。
现在可以看到,这两种角色所需要的技能是非常不同的。这些技能可以按不同的方式进行组合。产品负责人和技术主管所拥有的特殊技能可以用不同方式组合,组合结果控制和支配了他们之间的关系。团队的搭建必须根据参与的人员来组织,而不是将人员纯粹地按照
理论进行安排。
存在三种可能的关系,它们都在实践中得到了成功的应用。
产品负责人和技术主管是同一个人。这种方式非常容易应用在很小型的队伍中,可能是三个或六个开发人员。在大型的项目中则不容易得到应用。原因有两个:第一,同时具有管理技能和技术技能的人很难找到。思考者很少,实干家更少,思考者-实干家太少了。
第二,大型项目中,每个角色都必须全职工作,甚至还要加班。对负责人来说,很难在承担全部管理责任的同时,还能抽出时间进行技术工作。对技术主管来说,很难在保证设计的概念完整性,没有任何妥协的前提下,担任管理工作。
产品负责人作为总指挥,技术主管充当其左右手。这种方法有一些困难。很难在技术主管不参与任何管理工作的同时,建立在技术决策上的权威。
显然,产品负责人必须预先声明技术主管的技术权威,在即将出现的绝大部分测试用例中,他必须支持后者的技术决定。要达到这一点,产品责任人和技术主管必须在基本的技术理论上具有相似观点;他们必须在主要的技术问题出现之前,私下讨论它们;产品责任人必须对技术主管的技术才能表现出尊重。
另外,还有一些技巧。例如,产品责任人可以通过一些微妙状态特征暗示来(如,办公室的大小、地毯、装修、复印机等等)体现技术主管的威信,尽管决策权力的源泉来自管理。
这种组合可以使工作很有效。不幸的是它很少被应用。不过,它至少有一个好处,即项目经理可以使用并不很擅长管理的技术天才来完成工作。
技术主管作为总指挥,产品负责人充当其左右手。Robert Heinlein在《出售月球的人》(“The Man Who Sold the Moon“)中,用一幅场景描述了这样的安排:
Coster低下头,双手捂着脸,接着,抬起头。“我知道。我了解需要做什么——但每次我试图解决技术问题时,总有些该死的笨蛋要我做一些关于卡车、或者电话、以及其他一些讨厌的事情。我很抱歉。Harriman先生,我原以为我可以处理好。”
Harriman非常温和的说:“Bob,别让这些事烦你。近来好像睡眠不大好,是吗?告诉你吧。我将在你的位子上干几天,为你搭建一个免于这些事情干扰的环境。我需要你的大脑
工作在反向量、燃油效率和压力设计上,而不是卡车的合同。”Harriman走到门边,扫了一圈,点了一个可能是、也可能不是办公室主要职员的工作人员。“嘿,你!过来一下。”
那个人看上去有些惊慌,站了起来,走到门边说道,“什么事?”
“把角落上的那个桌子和上面所有的东西搬到本层楼的一个空的办公室去,马上。”
他监督着Coster和他的桌子移到另一个办公室,看了看,发现新办公室的电话没有接上。接着,想了一下,搬了一个长沙发过来。“今晚我们将安装一个投影仪、绘图仪、书架和其他一些东西,”他告诉Coster。“把你工程所需要的东西列一个表。”他回到了原来的总工程师办公室,愉快地想了想如何进行工作组织,以及是否有什么不妥。
过了四个小时,他带Berkeley进来,与Coster会面。这位总工程师正在他的桌子上睡觉,头枕在臂弯里。Harriman慢慢地退出去,但Coster醒了过来。“喔,对不起,”他有点不好意思地说,“我肯定是打了个瞌睡。”
“这就是我给你带来长沙发的原因,”Harriman说道。“它更加舒适。Bob,来见一下Jock Berkeley。他是你的新奴隶,你仍是总工程师,毫无疑问的老板。Jock是其他一切的主管。从现在起,你不需要担心其他的任何问题,除了建造登月飞船的一些细节问题。”