扩大软件开发的规模
从目前的情况来看,软件开发的速度缓慢、代价高昂而又极易出错,常常会生产出存在大量缺陷的产品,在可用性、可靠性、性能、安全以及其他服务质量方面造成严重的问题。
根据 Standish Group [Sta94] 的统计,美国公司每年投资约 175,000 个软件开发项目,投资额约为 2,500 亿美元。这些项目中只有 16% 能够在预算内按计划完成。另有 31% 的项目主要由于质量问题而被取消,经济损失约为 810 亿美元。另外 53% 的项目平均超出预算 189%,经济损失约为 590 亿美元。完成的项目平均只实现了原来规划的功能的 42%。
这些数字客观地印证了我们根据经验所做出的判断,那就是软件开发是一项劳动密集型的产业,它创造每一美元的价值所消耗的人力资本超过了我们对于一个现代化行业的期望值。
当然,除了这些缺点以外,软件开发的成果显然为消费者带来了巨大的价值,正如需求增长的长期趋势所表明的那样。但这并不意味着消费者已经非常满意,不管是对我们提供的软件,还是对我们提供软件的方式。这只是说明他们确实看好软件的前景,愿意承担巨大的风险和损失,以此来获得软件所带来的好处。然而,正如软件开发的外包越来越受欢迎所表明的,这种情况显然不是最好的,因为它似乎不能推动软件行业在软件开发方法和实践方面作出重大的改变。
在过去十年中,生产率只获得了有限的提高,最重要的原因可能是采用了字节编码的语言、模式和灵活的方法。除了这些进步,我们开发软件的方法与十年前没有什么不同。我们的方法和实践实际上没有太大的改变,相应的成本和风险同样也没有太大的改变。
然而,这种情况就要被改变。据预测,全球对软件的总体需求将在下一个十年中以数量级的速度增长,这是由于受到全球经济中的新生力量(例如中国的崛起)的推动,以及由于新的应用类型(例如商业集成和医学信息科学)和新的平台技术(例如 Web 服务、移动设备和智能产品)而使软件在社会基础结构中的作用日益加大。
如果软件开发能力没有相应的增长,那么十年后势必出现总体软件开发能力大大低于总体需求的局面。当然,如果市场力量能够自由运作,这种情况不会真正出现,因为受到启发的软件提供商将出于个人利益而提供足够多的软件来满足这种需求。
再次面对新的挑战
那么,怎样才能提供足够多的软件开发能力呢?不用太多的分析就可以看出,必须对软件开发的方法和实践进行显著的改变。
因为行业的生产能力取决于合格开发人员的数量以及开发人员的工作效率,因此提高行业生产能力的方法是,或者继续采用现有的方法和实践而投入更多的开发人员,或者保持相当数量的开发人员而采用不同的方法和实践。
尽管过去十年间培育起来的学徒制似乎已经成功地增加了合格开发人员的数量并提高了开发人员的平均水平,但至少有两个理由可以说明学徒制不大可能使软件行业的生产能力满足预期的需求水平:
• |
经验告诉我们,没有什么比拥有一些杰出的程序员更重要。杰出开发人员比蹩脚开发人员的工作效率高一千倍,但蹩脚开发人员的数量也几乎是杰出开发人员的一千倍 [Boe81]。
|
• |
Brooks [Bro95] 指出,增加项目人数最终会导致边际收入减少。通过招募和培训新开发人员而获得的生产能力将逐渐下降。
|
因此解决问题的出路应是改变我们的方法和实践。我们必须通过各种途径提高开发人员的工作效率。
提高抽象水平
在历史上,模式的转变曾经成功地提高了开发人员的抽象水平,为在平台和语言中获得知识并重复利用知识提供了强大的概念。例如,在平台方面,我们从批处理开始,经历了终端/主机、客户机/服务器、个人计算、多层系统和企业应用集成,再到异步、松散耦合的服务。在语言方面,我们从数字编码语言开始,经历了汇编语言、结构化语言和面向对象的语言,再到字节编码的语言和模式,这可以看作是基于语言的抽象。Smith 和 Stotts 对此进步作了意味深长的总结 [SS02]:
编程的历史是在体系结构抽象方面的一种锻炼。在每个时代,语言设计人员通过总结上一代的经验教训创造出结构,然后体系结构设计师使用这些结构创造出更复杂,更强大的抽象。
他们还指出,新的抽象一般先出现在平台上,然后移植到语言中。我们现在的情况是,基于语言的抽象已远远落后基于平台的抽象。换句话说,现在是工具远远落后于平台。我们现在正在使用最新的平台技术(例如,通过采用配乐法编写服务,我们现在能够使位于这个星球上任何位置的多个企业间的进程自动化),但我们仍然在手动编写每个应用程序,好象这是首选的方法一样。我们从小的具体概念(例如循环、字符串和整数)入手来创造大的抽象概念(例如保险索赔和证券交易)。我们勤勤恳恳一丝不苟地工作,将上百万小的相关源代码片段和资源组合在一起,形成巨大而复杂的结构。如果半导体行业也采用类似的做法,他们需要用手焊接晶体管来建立起支持这些应用程序的巨大而复杂的处理器。相反,他们通过组装称为特定用途集成电路 (ASIC) 的预定义组件,使用如图 2 所示的工具来完成实现。
图 2:基于 ASIC 的设计工具7
难道我们不能采用类似的方式来实现软件开发的自动化吗?当然能,而且实际上我们已经在这样做。例如,数据库管理系统通过 SQL 实现数据访问自动化,提供了诸如数据集成和独立性等优点,使数据驱动的应用程序更易于创建和维护。与此类似,Widget 框架和 WYSIWYG 编辑器使得创建和维护图形用户界面更容易,提供了诸如设备独立性和可视化组装等优点。仔细分析这些做法,我们可以发现一个反复出现的模式。
• |
在给定问题领域开发出大量系统之后,我们为该领域确定一组可以重复利用的抽象,然后我们制订一组模式,规定如何使用这些抽象。
|
• |
然后我们开发一个运行时(例如框架或服务器),将这些抽象和模式代码化。这样,我们可以通过对运行时所定义的组件实例化、调整、配置和组装,从而在该领域中创建系统。
|
• |
然后我们定义一种语言并创建支持该语言的工具(例如编辑器、编译器和调试器),使组装过程自动化。这样可以帮助我们对不断变化的要求做出快速响应,因为部分实现已经完成,而且可以轻松地加以修改。
|
这就是 Roberts 和 Johnson [RJ96] 所描述的著名的“语言框架”模式。一个框架可以按数量级降低开发一个应用程序的成本,但只使用一个框架则很困难。一个框架定义一种具有某种典型体系结构的产品(例如应用程序或子系统),这些产品可以通过各种方式进行完善和专门化的处理,以满足不同的要求。将每种产品的要求映射到框架中绝不是一个小问题,通常需要借助于体系结构设计师或高级开发人员的专业技能。通过使用语言表达式捕获各种要求,然后生成框架完成代码,基于语言的工具可以自动完成此过程。
软件能够实现产业化吗?
人们对软件与实物之间的类比进行过热烈的讨论。这些产业化模式能够应用于软件行业吗?难道软件行业没有因其产品性质的不同而比其他行业特殊吗?Peter Wegner 对它们之间的异同总结如下 [Weg78]:
软件产品在某些方面与传统工程学科中的有形产品(如桥梁、建筑物和计算机)存在相似之处。但也存在某些重要的区别,使得软件开发与众不同。由于软件是逻辑概念而非实物,因此其成本集中在开发过程中而不是生产过程中。又因为软件不会磨损,因此其可靠性取决于逻辑质量(如正确性和稳健性)而非物理质量(如硬度和韧性)。
有些讨论将实物的生产与软件的开发比作“苹果与桔子”。理清这些困扰的关键是理解生产和开发之间的不同,以及规模经济与范围经济的不同。
为了获得投资回报,必须尽最大可能重复利用那些可重复利用的组件而不仅仅是收回开发成本,无论是直接通过降低成本,还是间接通过降低风险、缩短进入市场的时间或改进质量来实现。从投资角度讲,可重复利用的组件属于金融资产。由于为使组件可重复利用而耗费的成本通常非常高,很难达到可获利的重复利用程度,因此需要有一种系统的方法来实现重复利用。这通常包括确定一个要开发多个系统的领域,找出该领域中重现出现的问题,开发出一套解决该问题的集成生产资产,然后将这些资产应用到在该领域中开发系统的过程中。
规模经济与范围经济
系统性重复利用可以同时产生规模经济和范围经济的效应。这两种效应在其他行业广为人知。尽管二者都是通过集中而非单独生产多个产品来减少时间和降低成本并提高产品质量,但二者在产生这些优点的方式上却存在着不同。
当集中而非单独生产一个设计的多个相同实例时,就产生了规模经济,如图 3 所示。规模经济可能出现在生产机器螺钉等产品时,在这种生产过程中,可以使用机床等生产资产生产出多个相同的产品实例。工程师通过一种资源密集的过程(称为开发)完成设计与最初的实例(称为原型)。然后通过另一个由机器和/或低成本劳动力完成的过程(称为生产)创造出更多实例(称为复制品),以满足市场需要。
图 3:规模经济
范围经济通过集中而非单独生产多个相似但不同的设计和原型而实现,如图 4 所示。例如在汽车制造业,多个相似但不同的汽车设计通常是通过组合子部件(如底盘、车体、内部装饰及传动装置)的现有设计来开发的,而不同的款式或型号通常是通过改变现有设计中的某些功能(如发动机和装饰水平)来产生的。换言之,可以使用相同的方法、工艺、工具和材料设计出多个相似但不相同的产品,并制作出相似但不相同的原型。商业建筑同样如此,很少看到多座桥梁或多幢摩天大楼采用同一种设计。但商业建筑领域存在一个有趣的现象,即每个成功的设计通常只会产生一两个实例,因而规模经济几乎从未真正实现过。在汽车制造业,通常会从成功的设计产生出许多不同的实例,通过复制每个原型,范围经济与规模经济形成互补,如图 4 所示。
图 4:范围经济
当然,软件无论与汽车制造还是与商业建筑之间都存在重要区别,但它们常常有着相似的地方。
• |
在诸如用户桌面产品之类的市场中,操作系统和工作效率应用程序等产品通过复制形成批量生产,软件行业呈现出规模经济的特点,如同在汽车制造业中一样。
|
• |
而在诸如企业用户产品之类的市场中,为获得竞争优势而开发的商业应用程序很少能够进行批量生产,软件仅呈现出范围经济的特点,如同在商业建筑领域中一样。
|
现在我们可以清楚地看到苹果与桔子之间的区别了。将实物行业的生产与软件开发进行比较未免有些天真。不管是软件还是实物,在任何类型的开发中寻求规模经济效果都是没有意义的。但是,我们却可以期待软件开发的产业化能够带来范围经济的效果。
产业化会带来什么样的结果?
假设可以在软件行业实现产业化,那么结果将会是什么样子呢?当然,在事情发生之前我们不可能确切地知道。但是,我们可以根据软件行业的发展道路以及其他行业产业化后的情形作出合理的推测。显然,软件开发永远不会简单到懒人们所希望的那种纯机械化的程度。相反,满足全球需求的关键是不要再把杰出开发人员的时间浪费在机械琐碎的任务上。我们必须尽一切努力更好地利用这些稀有资源,不要再让他们把时间花费在手动构造因为下一个主要平台版本的出现或者市场条件的变化而致使行业需求改变进而导致短短几个月或几年内就需要维护甚至替换掉的最终产品上。
实现此目的的方法之一就是为开发人员提供各种途经,使他们能够将自己的知识转化成可供他人重复利用的资产。这个目标是否遥遥无期?有些模式已经表现出重复利用知识的有效性,尽管利用程度不高。下一步是使用语言、框架和工具自动生成模式化的应用程序,从而实现从编程到自动化的飞越。
半导体开发为软件开发实现产业化后的情形提供了预演。这并不是说软件组件很快就能象 ASIC 那样易于组装,ASIC 是经过封装和接口技术领域二十年的创新和标准化而开发出来的产品。但另一方面,软件开发可能用不了 20 年。软件开发的优势在于只需要处理比特,而半导体行业还需要承担组件实现所需的物理材料工程的额外负担。与此同时,比特所固有的短寿特性也为诸如数字知识产权保护等带来了难题,正如我们在电影和音乐行业所看到的那样。