我认为Selin 是十分正确的——我低估了软件包客户化的程度和它的重要性。- 128 ------------------------ Page 141-----------------------面向对象编程——这颗铜质子弹可以吗?本章一开始的描述提醒我们,当很多零件需要装配,而且每个零件可能很复杂时,如果它们的接口设计得很流畅,大量丰富的结构就能快速地组合在一起。使用更大的零件来构建。面向对象编程的第一个特征是,它强制的模块化和清晰的接口。其次,它强调了封装,即外界无法看到组件的内部结构;它还强调了继承和层次化类结构以及虚函数。面向对象还强调了强抽象数据类型化,它确保某种特定的数据类型只能由它自身的相应函数来操作。现在,无需使用整个Smalltalk 或者C++的软件包,就可以获得这些特点中的任意一个——其中一些甚至出现在面向对象技术之前。面向对象方法吸引人的地方类似于复合维他命药丸:一次性(即编程人员的培训)得到所有的好处。面向对象是一种非常有前途的概念。面向对象技术为什么发展缓慢?《没有银弹》后的九年中,对面向对象技术的期望稳步增长。为什么增长如此缓慢?理论过多。James Coggins,已经在The C++ Report做了四年 “The best of ng.c++”专栏的作者,他提出了这样的解释:问题是O-O 程序员经历了很多错综复杂混乱的应用,他们所关注的是低层次,而不是高层次的抽象。例如,他们开发了很多象链表或集合这样的类,而不是用户接口、射线束模型或者有限元素模型。不幸的是,C++中帮助程序员避免错误的强类型检查,使得从小型事21物中构建大型物体非常困难 。他回归到基本的软件问题,主张一种解决软件不能满足要求的方法,即通过客户的参与和协作来提高脑力劳动的规模。他赞同自顶向下的设计:如果我们设计大粒度的类,关注用户已经接触的概念,则在进行设计的时候,他们能够理解设计并提出问题,并且可以帮助设计测试用例。我的眼科客户并不关心堆栈,他们关心描述眼角膜形状的勒让德多项式。在这方面,小规模的封装带来的好处比较少。David Parnas 的论文是面向对象概念的起源之一,他用不同的观点看这个问题。他写信给我:答案很简单。因为[O-O]和各种复杂语言的联系已经很紧密。人们并没有被告诉O-O是一种设计的方法,并向他们讲授设计方法和原理,大家只是被告知O-O是一种特殊工具。而- 129 ------------------------ Page 142-----------------------我们可以用任何工具写出优质或低劣的代码。除非我们给人们讲解如何设计,否则语言所起的作用非常小。结果是人们使用这种语言做出不好的设计,没有从中获得什么价值。而一旦获得的价值少,它就不会流行。资金的先行投入,收益的后期获得。面向对象技术包含了很多方法学上的进步。面向对象技术的前期投入很多——主要是培训程序员用很新的方法思考,同时还要把函数打造成通用的类。我认为它的好处是客观实在的,并非仅仅是推测。面向对象应用在整个开发周期中,但是真正的获益只有在后续开发、扩展和维护活动中才能体现出来。Coggin 说:“面向对象技术不会加快首次或第二次的开发,产品族中第五个项目的开发才会异乎寻常的迅速。22”为了预期中的,但是有些不确定的收益,冒着风险投入金钱是投资人每天在做的事情。不过,在很多软件公司中,这需要真正的管理勇气,一种比技术竞争力或者优秀管理能力更少有的精神。我认为极度的前期投入和收益的推后是使O-O 技术应用迟缓的最大原因。即使如此,在很多机构中,C++仍毫无疑问地取代了C。重用的情况怎样?解决软件构建根本困难的最佳方法是不进行任何开发。软件包只是达到上述目标的方法之一,另外的方法是程序重用。实际上,类的容易重用和通过继承方便地定制是面向对象技术最吸引人的地方。事情常常就是这样。当某人在新的做事方法上取得了一些经验,新模式就不再象一开始那么简单。当然,程序员经常重用他们自己的手头工作。Jone 提到:大多数有丰富经验的程序员拥有自己的私人开发库,可以使他们使用大约30%的重用代码来开发软件。公司级别的重用能提供 70%的重用代码量,它需要特殊的开发库和管理支持。公司级别的重用代码也意味着需要对项目中的变更进行统计和度量,从而提高重用的23可信程度 。W.Huang 建议用责任专家的矩阵管理来组织软件工厂,从而培养重用自身代码的日常工24作习惯 。- 130 ------------------------ Page 143-----------------------JPL 的Van Snyder 向我指出,数学软件领域有着软件重用的长期传统:我们推测重用的障碍不在生产者一边,而在消费者一边。如果一个软件工程师,潜在的标准化软件构件消费者,觉得寻找能满足他需要的构件,进行验证,比自行编写的代价更加昂贵时,重复的构件就会产生。注意我们上面提到的 “觉得”。它和重新开发的真正投入无关。数学软件上重用成功的原因有两个:(1)它很晦涩难懂,每行代码需要大量高智商的输入;(2)存在丰富的标准术语,也就是用数学来描述每个构件的功能。因此,重新开发数学软件构件的成本很高,而查找现有构件功能的成本很低。数学软件界存在一些长期的传统——例如,专业期刊和算法搜集,用适度成本提供算法,出于商业考虑开发的高质量算法(尽管成本有些高,但依旧适度)等——使查找和发现满足某人需要的构件比其他很多领域要容易。其他领域中,有时甚至不可能简洁地提出明确的要求。这些因素合在一起,使数学软件的重用比重新开发更有吸引力。同样的原因,在很多其他领域中也可以发现相同的重用现象,如那些为核反应、天气模型、海洋模型开发软件的代码编制工作。这些领域都是在相同的课本和标准概念下逐步地发展起来的。现在公司级别的重用情况如何?存在着大量的研究。美国国内的实践相对较少,有报25道声称国外重用较多 。Jones 报告,在他公司的客户中,所有拥有5000 名以上程序员的机构都进行正式的重用研究,而500 名以下程序员的组织,只有不到10%着手重用研究26。报告指出,最具有重用潜质的企业中,重用性研究(而非部署)“是活跃和积极的,即使没有完全成功。”Ed Yourdon报告,有一家马尼拉的软件公司,200 名程序员中有50 名从事供其他人使用的重用模块的开发,“我所见到的个案非常少——是由于机构上因素而进行重用研究,而不是技术上的原因”。DeMarco 告诉我,大众市场软件包提供了数据库系统等通用功能,充分地减轻了压力,减少了处在重用模块边缘的开发。 “不管怎样,重用的模块一般是一些通用功能。”Parnas 写道:重用是一件说起来容易,做起来难的事情。它同时需要良好的设计和文档。即使我们- 131 ------------------------ Page 144-----------------------看到了并不十分常见的优秀设计,但如果没有好的文档,我们也不会看到能重用的构件。Ken Brooks 关于预测产品通用化的一些困难的评论:“我不断地进行修改,即使在第五次使用我自己的个人用户界面库的时候。”真正的重用似乎才刚刚开始。Jones报告,在开放市场上仅有少量的重用代码模块,它们的价格在常规开发成本的1%~20%27。DeMacro 说:对整个重用现象,我变得有些气馁。对于重用,现有理论几乎是整体缺乏。时间证明了使模块能够重用的成本非常高。Yourdon 估计了这个高昂的费用:“一个良好的经验法则是可重用的构件的工作量是‘一次性’构件的两倍。28”在第一章的讨论中,我观察到了真正产品化构件所需的成本。因此,我对工作量比率的估计是三倍。显然,我们正在看到很多重用的形式和变化,但离我们所期望的还远,还有很多需要学习的地方。学习大量的词汇——对软件重用的一个可预见,但还没有被预言的问题思索的层次越高,所需要处理的基本思考要素也就越多。因此,编程语言比机器语言更加复杂,而自然语言的复杂程度更高。高级语言有更广泛的词汇量、更复杂的语法以及更加丰富的语义。作为一个科目,我们并没有就程序重用的实际情况,仔细考虑它蕴涵的意义。为了提高质量和生产率,我们需要通过经过调试的大型要素来构建系统,在编程语言中,这些函数的级别远远高于语句。所以,无论采用对象类库还是函数库的方式,我们必须面对我们编程词汇规模彻底扩大的事实。对于重用,词汇学习并不是思维障碍中的一小部分。现在人们拥有成员超过3000个的类库。很多对象需要10到20个参数和可选变量的说明。如果想获得所有潜在的重用,任何使用类库编程的人员必须学习其成员的语法(外部接口)和语义(详细的功能行为)。这项工作并不是没有希望的。一般人日常使用的词汇超过10,000个,受过教育的人远- 132 ------------------------ Page 145-----------------------多于这个数目。另外,我们在自然而然地学习着语法和非常微妙的语义。我们可以正确地区分巨大、大、辽阔、大量和庞大。人们不会说:庞大的沙漠或者辽阔的大象。对软件重用问题,我们需要研究适当的学问,了解人们如何拥有语言。一些经验教训是显而易见的:人们在上下文中学习,所以我们需要出版一些复合产品的例子,而不仅仅是零部件的库。人们只会记忆背诵单词。语法和语义是在上下文中,通过使用逐渐地学习。人们根据语义上的分类对词汇组合规则进行分组,而不是通过比较对象子集。子弹的本质——形势没有发生改变现在,我们回到基本问题。复杂性是我们这个行业的属性,而且复杂性是我们主要的限制。R.L.Glass 在1988年的文字精确地总结了我在1995年的看法:又怎么样呢?Parnas和Brooks不是已经告诉我们了吗?软件开发是一件棘手的事情,前方并不会有魔术般的解决方案。现在是从业者研究和分析革命性进展的时刻,而不是等待或希望它的出现。软件领域中的一些人发现这是一幅使人泄气的图画。他们是那些依然认为突破近在眼前的人们。但是我们中的一些——那些非常固执,以致于可以认为是现实主义者的人——把它看成是清新的空气。我们终于可以将焦点集中在更加可行的事情上,而不是空中的馅饼。现在,29有可能,我们可以在软件生产率上取得逐步的进展,而不是等待不大可能到来的突破 。- 133 ------------------------ Page 146-----------------------《人月神话》的观点:是或非?(Propositionsof the Mythical Man-Month: True orFalse ?)我们理解的也好,不理解的也好,描述都应该简短精练。塞缪尔·巴特勒,讽刺诗For brevity is very good, where we are, or are not understood.SAMUEL BUTLER Hudibras现在我们对软件工程的了解比1975 年要多得多。那么在1975 年版本的人月神话中,哪些观点得到了数据和经验的支持?哪些观点被证明是不正确的?又有哪些观点随着世界的变化,显得陈旧过时呢?为了帮助判断,我将1975年书籍中的论断毫无更改地抽取出来,以摘要的形式列举在下面——它们是当年我认为将会是正确的:客观事实和经验中推广的法则。(你也许会问,“如果这些就是那本书讲的所有东西,为什么要花177页的篇幅来论述?”)方括号中的评论是新增内容。所有这些观点都是可操作验证的,我将它们表达成刻板的形式是希望能引起读者的思考、判断和讨论。第1 章焦油坑1.1 编程系统产品(Programming Systems Product)开发的工作量是供个人使用的、独立开发的构件程序的九倍。我估计软件构件产品化引起了3倍工作量,将软件构件整合成完整系统所需要的设计、集成和测试又强加了3倍的工作量,这些高成本的构件在根本上是相互独立的。1.2 编程行业“满足我们内心深处的创造渴望和愉悦所有人的共有情感”,提供了五种- 134 ------------------------ Page 147-----------------------乐趣:创建事物的快乐开发对其他人有用的东西的乐趣将可以活动、相互啮合的零部件组装成类似迷宫的东西,这个过程所体现出令人神魂颠倒的魅力面对不重复的任务,不间断学习的乐趣工作在如此易于驾驭的介质上的乐趣——纯粹的思维活动,其存在、移动和运转方式完全不同于实际物体1.3 同样,这个行业具有一些内在固有的苦恼:将做事方式调整到追求完美,是学习编程的最困难部分由其他人来设定目标,并且必须依靠自己无法控制的事物 (特别是程序);权威不等同于责任实际情况看起来要比这一点好一些:真正的权威来自于每次任务的完成任何创造性活动都伴随着枯燥艰苦的劳动,编程也不例外人们通常期望项目在接近结束时,(bug、工作时间)能收敛得快一些,然而软件项目的情况却是越接近完成,收敛得越慢产品在即将完成时总面临着陈旧过时的威胁第2 章人月神话2.1 缺乏合理的时间进度是造成项目滞后的最主要原因,它比其他所有因素加起来影响还大。2.2 良好的烹饪需要时间,某些任务无法在不损害结果的情况下加快速度。2.3 所有的编程人员都是乐观主义者:“一切都将运作良好”。2.4 由于编程人员通过纯粹的思维活动来开发,所以我们期待在实现过程中不会碰到困- 135 ------------------------ Page 148-----------------------难。2.5 但是,我们的构思是有缺陷的,因此总会有bug。2.6 我们围绕成本核算的估计技术,混淆了工作量和项目进展。人月是危险和带有欺骗性的神话,因为它暗示人员数量和时间是可以相互替换的。2.7 在若干人员中分解任务会引发额外的沟通工作量——培训和相互沟通。2.8 关于进度安排,我的经验是为1/3计划、1/6编码、1/4构件测试以及1/4 系统测试。2.9 作为一个学科,我们缺乏数据估计。2.10 因为我们对自己的估计技术不确定,所以在管理和客户的压力下,我们常常缺乏坚持的勇气。2.11 Brook 法则:向进度落后的项目中增加人手,只会使进度更加落后。2.12 向软件项目中增派人手从三个方面增加了项目必要的总体工作量:任务重新分配本身和所造成的工作中断;培训新人员;额外的相互沟通。