面向对象编程。软件专业的一些学生坚持面向对象编程是当今若干新潮技术中最富有希望的3。我也是其中之一。达特茅斯的Mark Sherman提出,必须仔细地区别两个不同的概
念:抽象数据类型和层次化类型,后者也被称为类(class)。抽象数据类型的概念是指对象类型应该通过一个名称、一系列合适的值和操作来定义,而不是理应被隐藏的存储结构。抽象数据类型的例子是Ada包(以及私有类型)和Modula的模块。
层次化类型,如Simula-67的类,是允许定义可以被后续子类型精化的通用接口。这两个概念是互不相干的——可以只有层次化,没有数据隐藏;也可能是只有数据隐藏,而没有层次化。两种概念都体现了软件开发领域的进步。
它们的出现都消除了开发过程中的非本质困难,允许设计人员表达自己设计的内在特性,而不需要表达大量句法上的内容,这些内容并没有添加什么新的信息。对于抽象数据类型和层次化类型,它们都是解决了高级别的次要困难和允许采用较高层次的表现形式来表达设计。
不过,这些提高仅仅能消除所有设计表达上的次要困难。软件的内在问题是设计的复杂度,上述方法并没有对它有任何的促进。除非我们现在的编程语言中,不必要的低层次类型说明占据了软件产品设计90%,面向对象编程才能带来数量级上的提高。对面向对象编程这颗“银弹”,我深表怀疑。
人工智能。很多人期望人工智能上的进展可以给软件生产率和质量带来数量级上的增长4,但我不这样认为。追究其原因,我们必须剖析“人工智能”意味着什么,以及它如何应用。
Parnas澄清了术语上的混乱:
现在有两种差异非常大的AI定义被广泛使用。AI-1:使用计算机来解决以前只能通过人类智慧解决的问题。AI-2:使用启发式和基于规则的特定编程技术。在这种方法中,对人类专家进行研究,判断他们解决方法的启发性思维或者经验法则 。程序被设计成以人类解决问题的方式来运作。
第一种定义的意义容易发生变化 今天可能适合AI-1定义的程序,一旦我们了解了它的运行方式,理解了问题,就不再认为它是人工智能 不幸的是,我无法识别这个领域的特定知识体系 绝大多数工作是针对问题域的,我们需要一些抽象或者创造性来解决上述问题5。
我完全同意这种批评意见。语音识别技术与图象识别技术的共同点非常少,它们与专
家系统中应用的技术不同。例如,我觉得很难去发现图象识别技术能给编程开发实践带来什么样的差异。同样,语音识别也差不多——软件开发上的困难是决定说什么,而不是如何说。表达的简化仅仅能提供少量的促进作用。
至于AI-2专家系统技术,应该用专门的章节来讨论。
专家系统。人工智能领域最先进的、被最大范围使用的部分,是开发专家系统的技术。很多软件科学家正非常努力地工作着,想把这种技术应用在软件的开发环境中5。那么它的概念是什么,前景如何?
专家系统是包含归纳推论引擎和规则基础的程序,它接收输入数据和假设条件,通过从基础规则推导逻辑结果,提出结论和建议,向用户展示前因后果,并解释最终的结果。推论引擎除了处理推理逻辑以外,通常还包括复杂逻辑或者概率数据和规则。
对于解决相同的问题,这种系统明显比传统的程序算法要先进很多。
推导引擎技术的开发独立于应用程序,因此可以用于多个用户。在该引擎上花费较大的工作是很合理的。实际上,这种引擎技术非常先进。
基于应用的、可变更的部分,在基础规则中以一种统一的风格编码,并且为规则基础的开发、更改、测试和文档化提供了若干工具。这实际上对一些应用程序本身的复杂度进行了系统化。
Edward Feigenbaum指出这种系统的能力不是来自某种前所未有的推导机制,而是来自非常丰富的知识积累基础,所以更加精确地反映了现实世界。我认为这种技术提供的最重要进步是具体应用的复杂性与程序本身相分离。
如何把它应用在软件开发工作中?可以通过很多途径:建议接口规则、制订测试策略、记录各种bug产生的频率、提供优化建议等等。
例如,考虑一个虚构的测试顾问系统。在最根本的级别,诊断专家系统和飞行员的检查列表很相似,对可能难以寻找的原因提供基本的建议。建立基础规则时,可以依据更多的复杂问题征兆报告,从而使这些建议更加精确。可以想象,该调试辅助程序起初提供的是一般化建议,随着基础规则包括越来越多的系统结构信息时,它产生的推测和推荐的测试也越来越准确。该类型的专家系统可能与传统系统彻底分离,系统中的规则基础可能与相应的软件产品具有相同的层次模块化结构,因此当产品模块化修改时,诊断规则也能相应地进行模
块化修改。
产生诊断规则也是在为模块和系统编制测试用例集时必须完成的任务。如果它以一种适当通用的方式来完成,对规则采用一致的结构,拥有一个良好可用的推测引擎,那么事实上它就可以减少测试用例设计的总体工作量,以及帮助整个软件生命周期的维护、修改和测试。同样,我们可以推测其他的顾问专家系统——可能是它们中的某一些,或者是较简单的系统——能够用在软件开发的其他部分。
在较早实现的用于软件开发的专家顾问系统中,存在着很多困难。在我们假设的例子中,一个关键的问题是寻找一种方法,能从软件结构的技术说明中,自动或者半自动地产生诊断规则。另外,更加重要也是更加困难的任务是:寻觅能够清晰表达、深刻理解为什么的分析专家;开发有效的技术——抽取专家们所了解的知识,把它们精炼成基础规则。这项工作的工作量是知识获取工作量的两倍。构建专家系统的必要前提条件是拥有专家。
专家系统最强有力的贡献是给缺乏经验的开发人员提供服务,用最优秀开发者的经验和知识积累为他们提供了指导。这是非常大的贡献。最优秀和一般的软件工程实践之间的差距是非常大的,可能比其他工程领域中的差距都要大,一种传播优秀实践的工具特别重要。
“自动”编程。近四十年中,人们一直在预言和编写有关“自动编程”的文字,从问题的一段陈述说明自动产生解决问题的程序。现在,仍有一些人期望这样的技术能够成为下一个突破点7。
Parnas暗示这是一个用于魔咒的术语,声称它本身是语义不完整的。
一句话,自动编程总是成为一种热情,使用现在并不可用的更高级语言编程的热情8。
他指出,大多数情况下所给出的技术说明本质上是问题的解决方法,而不是问题自身。
可以找到一些例外情况。例如,数据发生器的开发技术就非常实用,并经常地用于排序程序中。系统评估若干参数,从问题解决方案库中进行选择,生成合适的程序。
这样的应用具有非常良好的特性:
问题通过相对较少的参数迅速地描述出特征。
存在很多已知的解决方案,提供了可供选择的库。
在给定问题参数的前提下,大量广泛的分析为选择具体的解决技术提供了清晰的规
则。
具有上述简洁属性的系统是一个例外,很难看到该方法能普及到更广泛的寻常软件系统,甚至难以想象这种突破如何能够进行推广。
图形化编程。在软件工程的博士论文中,一个很受欢迎的主题是图形化和可视化编程,计算机图形在软件设计上的应用9。这种方法的推测部分来自VLSI芯片设计的类比,计算机图形化在设计中扮演了高生产力的角色。部分源于——人们将流程图作为一种理想的设计介质,并为绘制它们提供了很多功能强大的实用程序——这证实了图形化的可行性。
不过,上述方法中至今还没有出现任何令人信服和激动的进步。我确信将来也不会出现。
首先,如同我先前所提出的,流程图是一种非常差劲软件结构表达方法10。实际上,它最好被视为是冯.诺依曼、戈尔德斯廷和勃克斯试图为他们所设计的计算机提供的一种当时迫切需要的高级控制语言。如今的流程图已经变得复杂,一张图有若干页,有很多连接结点。这种表现形式实在令人同情。流程图已经成为完全不必要的设计工具——程序员在开发之后,而不是之前绘制描述程序的流程图。
其次,现在的屏幕非常小,像素级别,无法同时表现软件图形的所有正式、详细的范围和细节。现在所谓 “类似桌面”的工作站实际上像是“飞机坐舱座椅”。飞机上,任何坐在两个肥胖乘客之间,反复挪动一大兜文件的人会意识到这中间的差别——每次只能看到很少的内容。真正的桌面提供了很多文件的总览,让大家可以随意地使用它们。此外,当人们的创造力一阵阵地涌现时,开发人员大多数都会舍弃工作台,使用空间更为广阔的地板。要使我们面对的工作空间满足软件开发工作的需要,硬件技术必须进一步发展。
更加基本的是,如同我们上面所争论的,软件非常难以可视化。即使用图形表达出了流程图、变量范围嵌套情况、变量交叉引用、数据流、层次化数据结构等等,也只是表达了某个方面,就像盲人摸象一样。如果我们把很多相关的视图叠加在所产生的图形上,那么很难再抽取出全局的总体视图。对VLSI芯片设计方法的类推是一种误导——芯片设计是对两维对象的层次设计,它的几何特性反映了它的本质特性,而软件系统不是这样。
程序验证。现代编程的许多工作是测试和修复bug。是否有可能出现银弹,能够在系统设计级别、源代码级别消除bug呢?是否可以在大量工作被投入到实现和测试之前,通过采
用证实设计正确性的“深奥”策略,彻底提高软件的生产率和产品的可靠性?
我并不认为在这里能找到魔法。程序验证的确是很先进的概念,它对安全操作系统内核等这类应用是非常重要的。不过,这项技术并不能保证节约劳动力。验证要求如此多的工作量,以致于只有少量的程序能够得到验证。
程序验证不意味着零缺陷的程序。这里并没有什么魔术,数学验证仍然可能是有错误的。因此,尽管验证可能减少程序测试的工作量,但却不能省略程序测试。
更严肃地说,完美的程序验证只能建立满足技术说明的程序。这时,软件工作中最困难的部分已经接近完成,形成了完整和一致的说明。开发程序的一些必要工作实际上已经变成对技术规格说明进行测试。
环境和工具。向更好的编程开发环境开发中投入,我们可以期待得到多少回报呢?人们的本能反应是首先着手解决高回报的问题:层次化文件系统,统一文件格式以获得一致的编程接口和通用工具等。特定语言的智能化编辑器在现实中还没有得到广泛应用,不过它们最有希望实现的是消除语法错误和简单的语义错误。
开发环境上,现在已经实现的最大成果可能是集成数据库的使用,用来跟踪大量的开发细节,供每个程序员精确地查阅信息,以及在整个团队协作开发中保持最新的状态。
显然,这样的工作是非常有价值的,它能带来软件生产率和可靠性上的一些提高。但是,由于它自身的特性,目前它的回报很有限。
工作站。随着工作站的处理能力和内存容量的稳固和快速提高,我们能期望在软件领域取得多大的收获呢?现在的运算速度已经可以完全满足程序编制和文档书写的需要。编译还需要一些提高,不过一旦机器运算速度提高十倍,那么程序开发人员的思考活动将成为日常工作的主要活动。实际上,这已经是现在的情况。
我们当然欢迎更加强大的工作站,但是不能期望有魔术般的提高。
针对概念上根本问题的颇具前途的方法
虽然现在软件上没有技术上的突破能够预示我们可以取得像在硬件领域上一样的进展,但在现实的软件领域中,既有大量优秀的工作,也有不引人注意的平稳进步。
所有针对软件开发过程中次要困难的技术工作基本上能表达成以下的生产率公式:
任务时间 = Σ(频率)i×(时间)i
如果和我所认为的一样,工作的创造性部分占据了大部分时间,那么那些仅仅是表达概念的活动并不能在很大程度上影响生产率。
因此,我们必须考虑那些解决软件上必要困难的活动——即,准确地表达复杂概念结构。幸运的是,其中的一些非常有希望。
购买和自行开发。构建软件最可能的彻底解决方案是不开发任何软件。
情况每一天都有些好转,越来越多的软件提供商,为各种眼花缭乱的应用程序提供了质量更好、数量更多的软件产品。当我们的软件工程师正忙于生产方法学时,个人计算机的惊天动地的变化为软件创造了广阔的市场。每个报摊上都有大量的月刊,根据机器的类型,刊登着从几美元到几百美元的各种产品的广告和评论。更多专业厂商为工作站和UNIX市场提供了很多非常有竞争力的产品,甚至很多工具软件和开发环境软件都可以随时购买使用。对于独立的软件模块市场,我已在其他的地方提出一些建议。
以上提到的任何软件,购买都要比重新开发要低廉一些。即使支付100,000美元,购买的软件也仅仅是一个人年的成本。而且软件是立即可用的!至少对于现有的产品、对于那些专注于该领域开发者的成果而言,它们是可以立刻投入使用的。并且,它们往往配备了书写良好的文档,在某种程度上比自行开发的软件维护得更加完备。
我相信,这个大众市场将是软件工程领域意义最深远的开发方向。软件成本一直是开发的成本,而不是复制的成本。所以,即使只在少数使用者之间实现共享,也能在很大程度上减少成本。另一种看法是使用软件系统的n个拷贝,将会使开发人员的生产率有效地提高n倍。这是一个领域和行业范围的提高。
当然,关键的问题还是可用性。是否可以在自己的开发工作中使用商用的软件包?这里,有一个令人吃惊的问题。在1950~1960年期间,一个接一个的研究显示,用户不会在工资系统、物流控制、帐务处理等系统中使用商用软件包。需求往往过于专业,不同情况之间的差别太大。在80年代,我们发现这些软件包的需求大为增加,并得到了大规模的使用。什么导致了这样的变化?
并不是软件包发生了变化。它们可能比以前更加通用和更加客户化一些,但并不太多。
同样,也不是应用发生了变化。即使有,今天的商业和学术上的需要也比20年以前更加不同和复杂。
重大的变化在于计算机硬件/软件成本比率。在1960年,2百万美元机器的购买者觉得他可以为定制的薪资系统支付250,000美元。现在,对50,000美元的办公室机器购买者而言,很难想象能为定制薪资系统再支付费用。因此,他们把上述系统的模块进行调整,添加到可用的软件包中。计算机现在如此的普遍,上述的改编和调整是发展的必然结果。
我的上述观点也存在一些戏剧性的例外——软件包的通用化方面并没有发生什么变化,除了电子表格和简单的数据库系统。这些强大的工具,出现得如此之晚和如此醒目,导致无数应用中的一些并不十分规范。大量的文章、甚至书籍讲述了如何使用电子表格应付很多意想不到的问题。原先作为客户程序,使用Cobol或者报表生成程序编写的大量应用,如今已经被这些工具所取代。
现在很多用户天天操作计算机,使用着各种各样的应用程序,但并不编写代码。事实上,他们中间很多人无法为自己的计算机编写任何程序,不过他们非常熟练地使用计算机来解决新问题。
我认为,对于现在的很多组织机构来说,最有效的软件生产率策略是在生产一线配备很多个人计算机,安装好通用的书写、作图、文件管理和电子表格程序,以及配备能熟练使用它们的人员,并且把这些人员散布到各个岗位。类似的策略——通用的数学和统计软件包,以及一些简单的编程能力,同样地适用于很多实验室的科学工作者。
需求精炼和快速原型。开发软件系统的过程中,最困难的部分是确切地决定搭建什么样的系统。概念性工作中,没有其他任何一个部分比确定详细的技术需求更加困难,详细的需求包括了所有的人机界面、与机器和其他软件系统的接口。需求工作对系统的影响比其他任何一个部分的失误都大,当然纠正需求的困难也比其他任何一个部分要大。
因此,软件开发人员为客户所承担的最重要的职能是不断重复地抽取和细化产品的需求。事实上,客户不知道他们自己需要什么。他们通常不知道哪些问题是必须回答的。并且,连必须确定的问题细节常常根本不予考虑,甚至只是简单地回答——“开发一个类似于我们已有的手工处理过程的新软件系统”——实际上都过于简单。客户决不会仅仅要求这些。复杂的软件系统往往是活动的、变化的系统。活动的动态部分是很难想象的。所以,在计划任何软件活动时,要让客户和设计人员之间进行多次广泛的交流沟通,并将其作为系统定义的
一部分。这是非常必要的。
这里,我将向前多走一步,下一个定论。在尝试和开发一些客户定制的系统之前,即使他们和软件工程师一起工作,想要完整、精确、正确地抽取现代软件产品的需求——这,实际上也是不可能的。
因此,现在的技术中最有希望的,并且解决了软件的根本而非次要问题的技术,是开发作为迭代需求过程的一部分——快速原型化系统的方法和工具。
软件系统的快速原型对重要的系统界面进行模拟,并演示待开发系统的主要功能。原型不必受到相同硬件速度、规模或者成本约束的限制。原型通常展示了应用程序的功能主线,但不处理任何如无效输入、退出清除等异常情况。原型的目的是明确实际的概念结构,从而客户可以测试一致性和可用性。
现在的软件开发流程基于如下的假设——事先明确地阐述系统,为系统开发竞标,实际进行开发,最后安装。我认为这种假设根本上就是不正确的,很多软件问题就来自这种谬误。因此,如果不进行彻底地调整,就无法消除那些软件问题。其中,一种改进是对产品和原型不断往复地开发和规格化。
增量开发——增长,而非搭建系统。我现在还记得在1958年,当听到一个朋友提及搭建(building),而不是编写(writing)系统时,我所感受到的震动。一瞬间,我的整个软件开发流程的视野开阔了。这种暗喻是非常有力和精确的。现在,我们已经理解软件开发是如何类似于其他的建造过程,并开始随意地使用其他的暗喻,如规格说明、构件装备、脚手架(测试平台)(specifications, assembly of components, and scaffolding)。
暗喻“搭建系统”的使用已经有些超出了它的有效期限,是重新换一种表达方式的时候了。如果现在的开发情况和我考虑的一样,那些概念性的结构非常复杂,以致于难以事先精确地说明和零缺陷地开发,那么我们必须采用彻底不同的方法。
让我们转向自然界,研究一下生物的复杂性,而不是人们的僵硬工作。我们会发现它们的复杂程度令我们敬畏。光是大脑本身,就比任何对它的描述都要复杂,比任何的模拟仿真都要强大,它的多样性、自我保护和自我更新能力异常丰富和有力。其中的秘密就是逐步发育成长,而不是一次性搭建。
所以,我们的软件系统也必须如此。很多年前,Harlan Mill建议所有软件系统都应该
以增量的方式开发11。即,首先系统应该能够运行,即使未完成任何有用功能,只能正确调用一系列伪子系统。接着,系统一点一点被充实,子系统轮流被开发,或者是在更低的层次调用程序、模块、子系统的占位符(伪程序)等。
从我在软件工程试验班上开始推动这种方法起,其效果不可思议。在过去几十年中,没有任何方法和技术能如此彻底地改变我自己的实践。这种方法迫切地要求自顶向下设计,因为它本身是一种自顶向下增长的软件。增量化开发使逆向跟踪很方便,并非常容易进行原型开发。每一项新增功能,以及针对更加复杂数据或情况的新模块,从已经规划的系统中有机地增长。
这种开发模式对士气的推动是令人震惊的。当一个可运行系统——即使是非常简单的系统出现时,开发人员的热情就迸发了出来。当一个新图形软件系统的第一副图案出现在屏幕上时,即使是一个简单的长方形,工作的动力也会成倍地增长。在开发过程中的每个阶段,总有可运行的系统。我发现开发团队可以在四个月内,培育(grow)出比搭建(building)复杂得多的系统。
大型项目同样可以得到与我所参与的小型项目相同的好处12。
卓越的设计人员。关键的问题是如何提高软件行业的核心,一如既往的是——人员。
我们可以通过遵循优秀而不是拙劣的实践,来得到良好的设计。优秀的设计是可以传授的。程序员的周围往往是最出色的人员,因此他们可以学习到良好的实践。因此,美国的重大策略是颁布各种优秀的现代实践。新课程、新文献。象软件工程研究所SEI等新机构的出现都是为了把我们的实践从不足提升到更高的水平。其正确性是勿庸置疑的。
不过,我不认为我们可以用相同的方式取得下一次进步。低劣设计和良好设计之间的区别可能在于设计方法中的完善性,而良好设计和卓越设计之间的区别肯定不是如此。卓越设计来自卓越的设计人员。软件开发是一个创造性的过程。完备的方法学可以培养和释放创造性的思维,但它无法孕育或激发创造性的过程。
其中的差异并不小——就象萨列里和莫扎特。一个接一个的研究显示,非常卓越的设计者产生的成果更快、更小、更简单、更优雅,实现的代价更少。卓越和一般之间的差异接近于一个数量级。
简单地回顾一下,尽管很多杰出、实用的软件系统是由很多人共同设计开发,但是那
些激动人心、拥有广大热情爱好者的产品往往是一个或者少数伟大设计师们的思想。考虑一下Unix、APL、Pascal、Modula、Smalltalk的界面、甚至Fortran;与之对应的产品是Cobol、PL/I、Algol、MVS/370和MS/DOS(图6.1)。
YES
NO
Unix
Cobol
APL
PL/I
Pascal
Algol
Modula
MVS/370
Smalltalk
MS-DOS
Fortran
图16.1:激动人心的产品
因此,尽管我强烈地支持现在的技术转移和开发技能的传授,但我认为我们可以着手的最重要工作是寻求培养卓越设计人员的途径。
没有任何软件机构可以忽视这项挑战。尽管公司可能缺少良好的管理人员,但决不会比良好设计人员的需求更加迫切,而卓越的管理人员和设计人员都是非常缺乏的。大多数机构花费了大量的时间和精力来寻找和培养管理人员,但据我所知,它们中间没有任何的一家在寻求和培育杰出的设计人员上投入相同的资源,而产品的技术特色最终依赖于这些设计人员。
我的第一项建议是每个软件机构必须决定和表明,杰出的设计人员和卓越的管理人员一样重要,他们应该得到相同的培养和回报。不仅仅是薪资,还包括各个方面的认可——办公室规模、安排、个人的设备、差旅费用、人员支持等——必须完全一致。
如何培养杰出的设计人员?限于篇幅,不允许进行较长的介绍,但有些步骤是显而易见的。
尽可能早地、有系统地识别顶级的设计人员。最好的通常不是那些最有经验的人员。
为设计人员指派一位职业导师,负责他们技术方面的成长,仔细地为他们规划职业生涯。
为每个方面制订和维护一份职业计划,包括与设计大师的、经过仔细挑选的学习过程、正式的高级教育和以及短期的课程——所有这些都穿插在设计和技术领导能力的培养安排中。
为成长中的设计人员提供相互交流和学习的机会。
再论《没有银弹》 (“No Silver Bullet”Refired)
生死有命,富贵在天
- 威廉三世,奥伦治王子
那些想看到完美方案的人,其实在心底里就认为它们以前不存在,以后也不可能出现。
- 亚历山大·波普,批判散文
Every bullet has its billet.
- WILLIAM III OF ENGLAND, PRINCE OF ORANGE
Whoever thinks a faultless piece to see, thinks what ne’er was, nor e’er shall be.
- ALEXANDER POPE, AN ESSAY ON CRITISIM
人狼和其他恐怖传说
《没有银弹-软件工程中的根本和次要问题》(第16章)最初是在IFIP’86年都柏林大会的约稿,接着在一系列的刊物上发表1。《计算机》杂志上翻印了该文章,封面是一副类似于《伦敦人狼》2影片的恐怖剧照。同时,还有一栏补充报道《杀死人狼》,描述了银弹将要完成的(现代)神话。在出版以前,我并未注意到补充报道和文字,也没有料到一篇严肃的技术性文字会被这样润色。
Computer杂志的编辑们是取得他们想要的效果的专家,不过,似乎有很多人阅读了那篇文章。因此,我为那一章选择了另一幅人狼插图,一幅对这种近乎滑稽物种的古老素描。我希望这副并不刺眼的图案有相同的正面效果。
存在着银弹-就在这里!
《没有银弹》中声称和断定,在近十年内,没有任何单独的软件工程进展可以使软件生产率有数量级的提高(引自1986年的版本)。现在已经是第九个年头,因此也该看看是否这些预言得到了应验。
《人月神话》一文被大量地引用,很少存在异议;相比之下,《没有银弹》却引发了众多的辩论,编辑收到了很多文章和信件,至今还在延续3。他们中的大多数攻击其核心论点和我的观点——没有神话般的解决方案,以及将来也不会有。他们大都同意《没有银弹》一文中的多数观点,但接着断定实际存在着杀死软件怪兽的银弹——由他们所发明的银弹。今天,当我重新阅读一些早期的反馈,我不禁发现在1986年~1987年期间,曾被强烈推崇的秘方并没有出现所声称的戏剧性效果。
在购买计算机软件和硬件时,我喜欢听取那些真正使用过产品并感到满意的用户的推荐。类似的,我很乐意接受银弹已经出现的观点,例如,某个名副其实的中立客户走到面前,并声称,“我使用了这种方法、工具或者产品,它使我的软件生产率提高了十倍。”
很多书信作者进行了若干正确的修订和澄清,其中一些还提供了很有针对性的分析和辩驳,对此我非常感激。本章中,我将同大家分享这些改进,以及对反面意见进行讨论。
含糊的表达将会导致误解
某些作者指出我没有将一些观点表达清楚。
次要(Accident)。在第16章的摘要中,我已经尽我所能地清晰表达了《没有银弹》一文的主要观点。然而,仍有些观点由于术语“accident(偶然)”和“accidental(次要)”而被混淆,这些术语来自亚里斯多德的古老用法4。术语“accidental”,我不是指“偶然发生”,也不是指“不幸的”,而是更接近于“附带的”或者“从属的”。
我并不是贬低软件构建中的次要部分,相反,我认同英国剧作家、侦探小说作者和神学家桃乐丝·赛尔丝看待创造性活动的观点,创造性活动包括(1)概念性结构的形式规格化,(2)使用现实的介质来实现,(3)在实际的使用中,与用户交互5。在软件开发中,我称为“必要(essence)”的部分是构思这些概念上的结构;我称为“次要(accident)”的部分指它的实现过程。
现实问题。对我而言(尽管不是所有人),关键论点的正确与否归结为一个现实问题:整个软件开发工作中的哪些部分与概念性结构的精确和有序表达相关,哪些部分是创造那些结构的思维活动?根据缺陷是概念性的(例如未能识别某些异常),或者是表达上的问题(例如指针错误或者内存分配错误)等,可以将这些缺陷的寻找和修复工作进行相应的划分。
在我看来,开发的次要或者表达部分现在已经下降到整个工作的一半或一半以下。由于这部分是现实的问题,所以原则上可以应用测量技术来研究6。这样,我的观点也可以通过来更科学和更新的估计来纠正。值得注意的是,还没有人公开发表或者写信告诉我,次要部分的任务占据了工作的9/10。
《没有银弹》无可争辩地指出,如果开发的次要部分少于整个工作的9/10,那么即使不占用任何时间(除非出现奇迹),也不会给生产率带来数量级的提高。因此,必须着手解决开发的根本问题。
由于《没有银弹》,Bruce Blum把我的注意力引向Herzberg、Mausner和Sayderman7等人在1959年的研究。他们发现动机因素可以提高生产率。另一方面,环境和次要因素,无论起到多么积极的作用,仍无法提高生产率。但是在产生负面影响时,它们会使生产率降低。《没有银弹》认为很多软件开发过程已经消除了以下负面因素:十分笨拙的机器语言、漫长的批处理周转时间以及无法忍受的内存限制。
因为是根本困难所以没有希望?1990年Brad Cox的一篇非常出色的论文《这就是银弹》(There Is a Silver Bullet),有说服力地指出重用和交互的构件开发是解决软件根本困难的一种方法8。我由衷地表示赞同。
不过,Cox在两点上误解了《没有银弹》。首先,他断定软件困难来自“编程人员缺乏构建当今软件的技术”。而我认为根本困难是固有的概念复杂性,无论是任何时间,使用任何方法设计和实现软件的功能,它都存在。其次,他(以及其他人)阅读《没有银弹》,并认定文中的观点是没有任何处理软件开发中根本困难的希望——这不是我的本意。作为本质上的困难,构思软件概念性的结构本身就有复杂性、一致性、可变性及不可见性的特点。不过实际上,每一种困难产生的麻烦都是可以改善的。
复杂性是层次化的。例如,复杂性是最严重的内在困难,并不是所有的复杂性都是不可避免的。我们的很多软件,但不是全部,来自应用本身随意的复杂特性。来自一家国际管理咨询公司,MYSIGMA Lars Sodahl的Lars Sodahl和合作伙伴曾写道:
就我的经验而言,在系统工作中所遇到的大多数困难是组织结构上的一些失误征兆。试图为这些现实建模,建立同等复杂的程序,实际上是隐藏,而不是解决这些杂乱无章的情况。
Northrop的Steve Lukasik认为即使是组织机构上的复杂性也不是任意的,可能容易受到策略调整的影响。
我曾作为物理学家接受过培训,因此倾向于用更简单的概念来描述“复杂”事物。现在你可能是正确的,我无法断定所有的复杂事物都容易用有序的规律表达 同样的道理,你不能断定它们不能。
昨天的复杂性是今天的规律。分子的无序性启迪了气体动力学理论和热力学的三大定律。现在,软件没有揭示类似的规律性原理,但是解释为什么没有的重担在你的身上。我不是迟钝和好辩的。我相信有一天软件的“复杂性”将以某种更高级的规律性概念来表达(就像物理学家的不变式)。
我并没有着手于Lukasik提倡的更深层次的分析。作为一个学科,我们需要更广泛的信息理论,它能够量化静态结构的信息内容,就像针对交互流的香农信息论一样。这已经超越了我的能力。作为对Lukasik的简单回应,我认为系统复杂性是无数细节的函数,这些细节必须精确而且详细地说明——或者是借助某种通用规则,或者是逐一阐述,但决不仅仅是统计说明。仅靠若干人不相干的工作,是不大可能产生足够的一致性,能用通用规律进行精确描述。
不过,很多复杂性并不完全是因为和外部世界保持一致,而是因为实现的本身,例如数据结构、算法、互联性等。而在更高的级别开发(发展)软件,使用其他人的成果,或者重用自己的程序——都能避免面对整个层次的复杂性。《没有银弹》提出了全力解决复杂性问题的方法,这种方法可以在现实中取得十分乐观的进展。它倡导向软件系统增加必要的复杂性:
层次化,通过分层的模块或者对象。
增量化,从而系统可以持续地运行。
Harel的分析
David Harel,在1992年的论文《批评银弹》(Biting the Silver Bullet)中,对已出版的《没有银弹》进行了很多最仔细的分析。
悲观主义 vs. 乐观主义 vs. 现实主义。Harel同时阅读了《没有银弹》和1984年Parnas的文章《战略防卫系统的软件问题》(Software Aspects of Strategic Defense Systems10),认为它们“太过黯淡”。因此,他试图在论文《走向系统开发的光明未来》(Toward a Brighter Future for System Development)中展现其明亮的一面。Cox同Halel一样认为《没有银弹》一文过于悲观,从而他提出“但是,如果从一个新视点去观察相同的事情,你会得到一个更加乐观的结论”。他们的论调都有些问题。
首先,我的妻子、同事和我的编辑发现我犯乐观主义错误的几率远远大于悲观主义。毕竟,我的从业背景是程序员,乐观主义是这个行业的职业病。
《没有银弹》一文明确地指出“我们看看近十年来的情况,没有银弹的踪迹 怀疑论者并不是悲观主义者 虽然没有通天大道,但是路就在脚下。”它预言了如果1986年的很多创新能持续开拓和发展,那么实际上它们的共同作用能使生产率获得数量级的提高。随着1986~1996十年过去了,这个预言即使说明了什么,那也是过于乐观,而不是过于悲观。
就算《没有银弹》总体看来有些悲观,那么到底存在什么问题?是否爱因斯坦关于任何物体运动的速度无法超过光速的论断过于“黯淡”或者“令人沮丧”呢?那么哥德尔关于某些事物无法计算的结论,又如何呢?《没有银弹》一文认为“软件的特性本身导致了不大可能有任何的银弹”。Tuski在IFIP大会上发表了一篇论文作为出色的回应,文中指出:
在所有被误导的科学探索中,最悲惨的莫过于对一种能够将一般金属变成金子的物质,即点金石的研究。这个由统治者不断地投入金钱,被一代代的研究者不懈追求的、炼金术中至高无上的法宝,是一种从理想化想象和普遍假设中——以为事情会像我们所认为的那样——提取出的精华。它是人类纯粹信仰的体现,人们花费了大量的时间和精力来认可和接受这个无法解决的问题。即使被证明是不存在,那种寻找出路和希望能一劳永逸的愿望,依然十分的强烈。而我们中的绝大多数总是很同情这些明知不可为而为之的人,因此它们总是得以延续。所以,将圆形变方的论文被发表,恢复脱发的洗液被研制和出售,提高软件生产率的方法被提出并成功地推销。
我们太过倾向于遵循我们自己的乐观主义(或者是发掘我们出资人的乐观主义)。我们太喜欢忽视真理的声音,而去听从万灵药贩卖者的诱惑11。
我和Turski都坚持认为这个白日梦限制了向前的发展,浪费了精力。
“消极”主题。Harel认识到《没有银弹》中的消极来自三个主题:
根本和次要问题的清晰划分
独立地评价每个候选银弹
仅仅预言了十年,而不是足够长的时间“出现任何重大的进步。”
第一个主题,它是整篇文章的主要观点。我仍然认为上述划分对于理解为什么软件难以开发是绝对关键的。对于应该做出哪些方面的改进,它也是十分明确的指南。
至于独立地考虑不同的候选银弹,《没有银弹》并非如此。各种各样的技术一个接一个地被提出,每一种都过分宣扬自身的效果。因此,依次独立的评估它们是非常公平的。我持反对态度的并不是这些技术,而是那种它们能起到魔术般作用的观点。Glass、Vessey和Conger在他们1992年的论文中提供了充足的证据,指出对银弹的无谓研究仍未结束12。
关于选择10年还是40年作为预言的期限,选择较短的时间是承认我们并没有足够强的能力可以预见到十年以后的事情。我们中间有谁可以在1975年预见到80年代的微型计算机革命吗?
对于十年的期限,还有其他的一些原因:各种银弹都宣称它们能够立刻取得效果。我回顾了一下,发现没有任何一种银弹声称“向我的秘方投资,在十年后你将获得成功”。另外,硬件的性能/价格比可能每十年就会有成百倍的增长,尽管这种比较不很合适,但是直觉上的确如此。我们确信会在下一个40年中取得稳步的发展。不过,以40年代价取得数量级的进展,很难被认为是不可思议的进步。
想象的试验。Harel建议了一种想象的试验,他假设《没有银弹》是发表在1952年,而不是1986年,不过表达的论断相同。他使用反证法来证明将根本和次要问题分开是不恰当的。
这种观点站不住脚。首先,《没有银弹》一开始就声称,50年代的程序开发中曾占支配地位的次要困难,如今已经不存在了,并且消除这些困难已经产生了提高若干数量级的效果。