我认为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-----------------------
《人月神话》的观点:是或非?(Propositions
of the Mythical Man-Month: True or
False ?)
我们理解的也好,不理解的也好,描述都应该简短精练。
塞缪尔·巴特勒,讽刺诗
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 向软件项目中增派人手从三个方面增加了项目必要的总体工作量:任务重新分
配本身和所造成的工作中断;培训新人员;额外的相互沟通。