Adams Wang为《人月神话》中译本译者。
(《人月神话》第二版法文译本封面,点缀用,和本文内容无关)
关于《人月神话》一书,已经有了许多评论和讨论。可能,作者本身的经历——“被认为是‘IBM 360系统之父’,他担任了360系统的项目经理,以及360操作系统项目设计阶段的经理。”——已经是最好的评论。
许多朋友认为现在的软件工程数据比较理论化,可操作性不高,往往只能了解一些理念。在面对具体项目的时候,还是有些迷茫。而在整个翻译的过程中,Brooks的观点以及治学态度经常令人叹为观止。这里,就自己的一些体会和实践同大家探讨。
“焦油坑(The Tar Pit)”一章中,对编程系统产品的观点“编程系统产品(Programming Systems Product)。和以上的所有的情况都不同的是,它的成本高达九倍。然而,只有它才是真正有用的产品,是大多数系统开发的目标。”很有意义,至少在面对现在许多老板们对管理的观点“现实世界中的管理就是在更大程度上以人员的生命为代价,让他们更努力、更长时间地工作。经理们总是不停地吹嘘他们的人员的加班时数和能从这些人身上榨取更多时间的小把戏。”(《人件》,即将由清华大学出版社出版,译者为UMLChina翻译组方春旭、叶向群)面前聪明的工作。这种情况下,开发产品的质量一定会下降,甚至惨不忍睹,因为开发人员唯一能控制的是质量,当他们不得不牺牲质量,痛苦面对自己的工作,践踏工作的乐趣时,可以想象项目成本会大量地增加,并且项目的发布往往伴随着一大批程序员的倒下。
团队组建
“人月神话(The Mythical Man-Month)”提出了这样的论断,(盲目地)“向进度落后的项目中增加人手,只会使进度更加落后。”这中间还涉及到如何组建你的开发团队,或者面向一个软件开发任务时,如何规划开发计划、划分任务项、分配资源。紧接着,在“外科手术队伍(The Surgical Team)”中,Brooks提出了用外科医生+副手来组织团队,保证设计思路的完整性。其中,还提到了采用“语言专家”来帮助疑难问题的解决;安排工具维护人员,也就是现在意义上的系统管理员来保证系统开发、管理环境的有效运行;而其他人来解决一些文件管理等工作。
在一个小型的C++项目操作中,对上述方法的实践中
*由PM和结构师一用一备来分析需求、进行框架设计,确保整个项目的概念完整性。分析设计的产出物达到框架示意代码的级别,这部分框架代码主要是帮助团队对项目开发的理解,不存在于正式的代码中;
*安排开发人员负责配置管理。这里的配置管理不仅仅局限于文档、软件产物的管理,而是在使用框架驱动的迭代开发时,需要对框架和各个组件不断地进行编译、整合、检查记录Bug。这位开发人员往往是团队中的主程序员(Chief Programmer),对各种开发方法、方法学有着一定的经验;
*安排人员对工具进行预研,如了解STL类库等。该角色具体的人员在不同的阶段会进行调整。因为,他/她需要对语言、类库、开发技巧进行学习研究,往往会占用大量的工作时间。在实际情况中,前期是有主程序员承担;后期,由PM承担;这样的安排的确能解决产品思路的一致性,在很大程度上提高生产力和产品质量。不过,它要求:
1. PM和结构师有非常良好的沟通,包括分析方法的风格、对开发的理解等,他们之间的不一致直接会导致项目的开发方向;
2. 对分析的结果,进行良好的贯彻。软件行业具有年青、有朝气的特点,同时也有些浮躁。有的开发人员好高骛远,对代码质量重视不够,影响框架的稳定性。
这样安排的风险在于“外科医生”的工作负荷可能过大,尤其在国内的公司中,他们往往同时兼任PM和系统分析的工作。同样,相应的绩效考核机制也不容易具备。
另外一个风险在于“一用一备”的安排,在“为什么巴别塔会失败?(Why Did the Tower of Babel Fail?)”的“大型编程项目的组织架构”中详尽地论述。不过,在国内的开发环境下,似乎很难实行。比较折中的方案,是对某种类型的项目,包括业务类型、开发方法、语言类型,建立开发和管理指南,从而保证概念完整性。在后续所经历的一系列Domino类型的项目开发中,进行了尝试,相应在实践中遇到的问题在于如何贯彻实施。
上述方法潜在的一个声音是“软件重用性”。提到重用性,可能大家脑海里马上想到的是对象、类库等。不错,面向对象的方法、商业组件(类)库的确极大地提高了软件重用性。但对于中小型企业,甚至于一个成熟的开发团队,积累自己大粒度的框架是提高软件生产力的一个重要措施。设计模式中一些模式,如Visitor、Observe本身就可以作为软件框架来使用。以设计模式为基础,根据开发类型积累特定业务领域的框架是完全可行的最佳实践。而Brooks一再强调“概念完整性(Concept Integrity)”,以及在“外科手术队伍”中推荐由外科医生来负责系统的开发,保证了产生的系统是少数人思维的结果,它们往往简捷、纯粹,没有众多人的影响,经过了项目的洗礼之后,往往能成为重用的框架。相反,在分析设计阶段,安排许多开发人员来共同开发,尽管同样完成了项目,但会相应导致“画蛇添足(The Second-System Effect)”特征——“它极富有创造性,极端复杂,非常高效。但不知为什么,同时也感觉到粗糙、浪费、不优雅,以及让人觉得必定存在某种更好的方法”,而重用的框架往往是捕捉到了问题的根本,用简单优美的方案,解决80%的问题。
贯彻实施
Brooks在“贵族专制、民主政治和系统设计(Aristocracy, Democracy, and System Design)”一章中,一针见血地指出了成功软件具有高度的概念一致性。“结构师难道不是新贵?……至于贵族专制统治的问题,必须回答“是”或者“否”。就必须只能存在少数的结构师而言,答案是肯定的……”,《人月》中的体系结构更加类似于现在的需求概念,而非现在所意义的体系结构。不过,在具体的实践中,需求和体系结构依然应该由少数的人来承担。这样的观点可能会引起争议,但就个人观点而言,软件行业实际上是“精英行业”。高素质、具有丰富经验的需求分析人员、结构师往往是软件企业的核心骨干人员,相应的一般编程人员相对的流动性会大一些。
从个人发展的角度,安安静静地作为一个螺丝钉仿佛不是这个时代精神。这个问题同企业与人之间的关系一样,很难一言以蔽之。就具体的项目操作,理想情况是程序员较少地参加前期分析工作,由有经验的同仁来负责,给出具有框架代码程度的需求和框架产物。
在较早的项目中,有的一般编程人员不安于编码实现,过早接触于一些PM性质工作,以及项目压力等其他因素,造成了代码质量不高,使得框架的重用程度降低。而在另外公司的一个项目中,由于企业的文化,同事们严格按照分工进行开发,提高了质量。后者看似少了机会,但从长远的角度看,大家对设计的了解更加透彻,对流程的理解更加深刻,为以后的发展打下了基础。
同样在这一章节中,Brooks提出了“在等待时,实现人员应该做什么?”的问题。他认为“首先,必须设定良好定义的时间和空间目标,……同时,在物理实现的级别,也有很多可以着手的工作。”实际项目中,早期的投入往往人员较少,一般15人月左右的项目,初期就2~3人,这其中包括了需求分析、设计人员,以及主程序员。主程序员会对系统有初步的了解,对系统开发采用的技术、工具、开发技巧进行研究,同时同PM一同负责搭建软件工程环境和软件开发的环境。这样的安排,出现的一个问题是编程人员与分析设计人员的沟通。它需要大家通畅、自由的交流,经可能对开发达成共识,减少信息的丢失。
项目交流的方法,Brooks就OS360开发经验,在“贯彻执行(Passing the Word)”一章中,进行了具体的讲解。如,会议与大会、多重实现、电话日志等。就小型项目而言,如果不考虑异地开发的情况,较正式的组内会议可以安排在一周一次,即周例会的形式。另外,在里程碑之处安排评审会议,以对开发的进展、对需求的实现以及项目计划进行调整和修正。而对于异地开发,或者用户不在本地的情形,则建议采用电话会议等形式,效果虽然不如本地开发好,不过有聊胜于无。
“为什么巴别塔会失败?(Why Did the Tower of Babel Fail?)”又对软件开发中的交流问题进行了强调,指出了文档是沟通的一种重要方式。后续的“提纲挈领(The Documentary Hypothesis)”则用类比的方式阐述了如何定义软件项目的文档集合,“另外一面(The other face)”讨论了程序文档的一些形式。这些观点对实际工作也具有指导意义,相应的Rational Suite中Requisite Pro工具使用参考中,推荐了软件项目的参考文档集合。在C++和Domino若干项目的实践中,发现最小的文档集合包括需求文档(Software Requirement Specification)、项目计划(Software Development Plan)、框架设计、设计元素说明。其中,项目计划不仅仅是进度,而是从软件的配置管理、生命周期、资源分配、风险分析、培训等方面进行描述,这部分的内容往往不局限于单个项目,而是在同一种类型的项目中具有共性。因此,可以在不同项目中共享。
总而言之,Brooks对文档的建议是“项目经理聪明的做法都是:立刻正式生成若干文档作为自己的数据基础,哪怕这些迷你文档非常简单。接着,……”以及“如果一开始就认识到它们的普遍性和重要性,那么就可以将文档作为工具友好地利用起来,而不会让它成为令人厌烦的繁重任务。通过遵循文档开展工作,项目经理能更清晰和快速地设定自己的方向。”
面向变更的开发
“稳定状态的生产思想特别不适合项目工作。我们倾向于忘记这一点:项目的全部目的就是让自己死亡。项目生命中的唯一稳定状态是死后僵硬……”(《人件》);
“软件开发是减少混乱度(减少熵)的过程,所以它本身是处于亚稳态的。软件维护是提高混乱度(增加熵)的过程,即使是最熟练的软件维护工作,也只是放缓了系统退化到非稳态的进程。”——“未雨绸缪(Plan to Throw One Away)”
软件开发本身就是一个具有无序趋势的活动。当人们四处游走,寻找一个类似于计算机硬件那样流水线化的方式方法时,可能应该静静思考一下,这本身就是与开发内在发展规律相悖。并且,软件开发是人类的思维创造活动,同诗歌、乐曲一样,好像人类历史上还没有什么为上述创造进行流水线化的尝试。
据我看来,软件工程首先是一种缓慢的艺术。在这中间,筹划、交流、冥想以及迭代占有很大比重,同样(如果不是更重要的),错位、反复甚至离题也应据有一席之地。即便强调工程的可控性,也难以排除这些必要的环节(记得法式餐馆的例子?)。我们所能做的,是给它们足够的时间和容忍(你知道我不是指纵容延期)。
从软件开发产物的角度而言,CMM规范2级中的配置管理一般包括四个活动:配置标识、版本控制、变更控制和度量。配置标识和版本控制都是为了给变更提供一个稳定的承载基础。而Brooks对360机器开发的进行了描述“在System/360工程模型中,在一大堆常规的黄颜色电线中,常常可以不经意地看到紫色的电线束。……这些更改过的接线使用紫色电线,看上去就像伸着一个受了伤的大拇指。”体现了配置管理的雏形,进一步提出了在软件项目中“……软件开发也需要用到“紫色线束”的手法。对于最后成为产品的程序代码,它更迫切地需要进行严密控制和深层次的关注。……而且需要文档化。”——“整体部分(The Whole and the Parts)”
在CMM试点项目以及后来的项目实践中,为项目的文档产出物进行标识是比较容易实现的。Internet上有大量的资料和模板可供参考。版本控制可以使用VSS或者Open Source的CVS,而CMM规范中反复出现的“基线 (baseline)”概念,在配置管理实践的初期或者小规模的项目中,并不是强制性的。当配置标识和版本控制实践到一定的程度之后,再推广基线和变更控制,就相对容易得多。
即对于某种类型的项目,可以采用制定配置标识规范、识别文档类型、确定该类项目的目录结构、建立版本控制机制来进行初期的实践,具有一定的成熟度之后,再实施变更管理。变更使用“阶段(量子)化、定期变更…… 量子(阶段)化变更方法非常优美地容纳了紫色线束技术:直到下一次系统构件的定期发布之前,都一直使用快速补丁;而在当前的发布中,把已经通过测试并进行了文档化的修补措施整合到系统平台。”这种方法能在一定程度上缓解项目压力、变更和质量之间的矛盾。
迭代开发
Brooks在“20年后的人月神话(The Mythical Man-Month after 20 Years)”明确提出了迭代开发的概念“增量开发模型更佳——渐进地精化”。这种开发方法对项目产生的激励作用是不可估量的,作者在北卡罗来纳大学时, “我常常会被屏幕上第一幅图案、第一个可运行的系统对团队士气产生的鼓舞效果而感到震惊。”而在C++的现实项目中,在极大的压力下,当第一个可执行的原型出现在开发人员面前时,长期的疲惫、沮丧一扫而空。从而,为继续开发提供了动力。这里,长时间高负荷工作并不是被提倡的,但增量开发是软件开发动力学的一种重要手段。
迭代开发可以用“外科手术队伍”、OO及设计模式的实现来实践。面向对象框架的分析设计思想,并不一定非要用面向对象的语言实现。它的一个重要特点,是固化用户要求或者是待开发系统中相对稳定的部分,以牺牲模型某个维度的代价来得到较稳定的模型。然后,在该框架的基础上不断地迭代。“外科手术队伍”则由具有丰富经验的“外科医生”操刀,来主持需求分析和建立迭代框架。少数的人能确保框架不带有过多不必要的非结构性的功能特色,从而保证框架的简捷和良好的扩充性。
迭代开发本身是对变更这个“怪物”的一剂良药,不同迭代周期能较好地容纳阶段(量子)化的变更。在变更的同时,始终有可运行的系统供调试、测试,从而确保项目的质量——质量决定成本,“远远超过最终用户需求的质量是一种取得更高生产力的手段。”(《人件》,即将由清华大学出版社出版,译者为UMLChina翻译组方春旭、叶向群)。
同样,Brooks在“未雨绸缪(Plan to Throw One Away)”中提出了抛弃型原型的概念,并在“《人月神话》的观点:是或非?(Propositions of the Mythical Man-Month: True or False?)”中强调“因此,为舍弃而计划,无论如何,你一定要这样做。”迭代开发是容纳原型,包括抛弃型和非抛弃型。而且,它是一个很好说服管理层和用户的途径——因为,不同的迭代周期和任务本来就在计划之中。在C++的项目中,对于没有坚持在框架设计完成之后,抛弃框架代码原型,至今还有些遗憾,相应所付出的代价就是产品质量和开发人员对该项目信心的丧失。
另外一个提高项目产品质量的方法,Brooks在“整体部分(The Whole and the Parts)”的“系统集成调试”中给出了专家意见,“使用经过调试的构件单元”、“搭建充分的测试平台”、“一次添加一个构件”和“阶段(量子)化、定期变更”。这在目前的实践中依然有指导意义。现在的软件测试水平相信业界人士都非常清楚:很少有规范化的测试;白盒测试基本不做;项目压力过大,不断压缩测试时间……。因此,仔细的系统集成测试非常有必要, 能够做到《人月神话》中,OS360的系统测试一半已经非常不错了。
项目计划
项目计划的重要性相信每个人都了然于胸。Brooks在“祸起萧墙(Hatching a Catastrophe)”一文中提及了项目计划/跟踪。另外,在其他的许多章节中,阐述了计划文档化的重要性。这里,项目计划不仅仅指的是项目进度,采用Microsoft Project所画出的仅仅是项目的进度。
在具体的实践中,项目计划可以从以下若干方面考虑:
*项目描述:包括项目定义、名称、背景、目标与范围、交付物和验收标准等;
*项目组织结构:定义项目人员组成。注:这部分内容会根据项目的实施不断调整;
*软件生命周期:依照项目特点决定合适的周期。并不是所有的项目都适用与迭代周期,也不是瀑布模型就一无是处,甚至有的项目需要瀑布模型作为主干,在某个阶段加入迭代特性。
*项目管理:包括客户管理、进度管理、成本管理、风险管理、培训管理等;
*配置管理:定义项目目录结构、产物标识方法、版本控制等;
项目计划必须根据用户、项目特点仔细地考虑,它可能是寥寥数语,但是它的作用不在需求规格说明之下。项目计划和需求规格说明是项目文档集合中最基本的强制性文档。
软件开发中,理论与实践是个亘古不变的话题。我们很有幸诞生在一个信息共享的时代,能够接触到前人睿智的思想。“这个神奇的时代远远没有结束,它依然在飞速发展。更多的乐趣,尽在将来。”——Brooks。