2.2 软件过程模型
软件过程模型,又称为软件生存周期模型,是软件过程的结构框架,它在一定抽象层次上刻画了一类软件过程的共同结构和属性。不同的软件过程模型阐述不同的软件开发思想、步骤以及最佳实践。常见的软件过程模型包括瀑布模型、增量模型和演化模型。
2.2.1 瀑布模型
1970年Royce提出了著名的线性顺序模型,又称瀑布模型(waterfall model)。正如它的名字一样,瀑布模型将软件过程中的各项活动规定为依固定顺序连接的若干阶段工作,形如瀑布流水,最终得到软件产品。这些顺序执行的阶段通常为:需求、设计、实现、测试、交付、运行和维护,如图2-2所示。每个阶段的结束处都设有评审,只有通过评审才能进入后一阶段。前一阶段的中间产品是后一阶段工作的基础。
瀑布模型的优点在于:①它在支持开发结构化软件、控制软件开发复杂度、促进软件开发工程化方面起了显著作用;②它为软件开发维护提供了一种当时较为有效的管理模式,通过开发计划制订、项目估算、阶段评审和文档控制有效地对软件过程进行指导,从而对软件质量起到一定程度的保障作用。但是,瀑布模型的最大问题在于没有在实践中进行验证。一个没有通过验证的模型在大量的实践中会暴露出它的种种不足和问题:
图2-2 瀑布模型
1)不能应对不确定性。用户常常难以清楚地给出所有需求,而瀑布模型却要求如此,它不能接受在许多项目的开始阶段自然存在的不确定性,以及开发过程中的需求变更。
2)错误发现太迟。软件的运行版本一直要等到项目开发晚期才能得到,很多错误直到运行程序时才被发现,造成大量的返工。
3)开发进度缓慢。由于模型的线性顺序,开发者常常被不必要地耽搁,某些项目组成员不得不等待组内其他成员先完成其依赖的任务。
瀑布模型太理想化、太单纯,已不再适合当前充满各种风险的软件开发项目。但我们应该认识到,“线性”是人们最容易掌握并能熟练应用的思想方法。当人们碰到一个复杂的“非线性”问题时,总是会千方百计地将其分解或转化为一系列简单的线性问题,然后逐个解决。线性是一种简洁,简洁就是美。当我们领会了线性的精神,就不要再呆板地套用瀑布模型的外表,而应该用活它。例如增量模型和演化模型实质上就是多次重复的线性模型。也许,当软件工程和开发技术足够成熟时,线性模型可能会再次回归到业界实践中。
2.2.2 增量模型
增量模型(incremental model),又称有计划的产品改进模型,它从一组给定的需求开始,通过构造一系列可执行版本来实施开发活动。第一个版本实现一部分需求,下一个版本实现更多的需求,以此类推,直到系统完成。每个版本都要执行必要的活动和任务,如,需求分析和架构设计仅需要执行一次,而软件详细设计、软件编码和测试、软件集成和软件验收在每个版本构造过程中都会执行。增量模型的例子如图2-3所示。
和瀑布模型相比,增量模型具有以下显著的特点:
1)多个版本可以并行开发。在开发每个版本时,开发过程中顺序地或部分平行地进行各项活动和任务。当相继版本在部分并发开发时,开发过程中的活动和任务可以在各版本间平行地被采用。
2)每个版本都是可运行的产品。每一个线性序列产生软件的一个可发布的“增量”,这必须是可运行的产品。
3)需求在开发早期是明确的。大部分需求在项目早期就被定义,在此基础上进行整体架构的设计,然后将功能有计划地分为若干增量来逐步实现。
图2-3 增量模型
当开发人员、资源或资金不足以在设定期限内实现一个完全的版本时,增量开发尤为有用。早期的增量可以由较少的人员实现,如果核心产品很受欢迎,可以增加新的人手实现下一个增量。同时,增量能够有计划地管理技术风险,并且能提前把产品推向市场。但增量并没有缓解瀑布模型中的需求风险和架构风险。相反,一旦需求不明确、架构没有把握或变更频繁,其返工风险会更大,极可能涉及多个并行开发的版本。
2.2.3 演化模型
就像所有复杂系统一样,软件要经过一段时间的演化。业务和产品需求在软件开发过程中常常发生改变,想要一次迭代就开发出最终产品是不可能的;同时,紧迫的市场期限使得难以一下子完成一个完善的软件产品。因此,只要核心需求能够被很好地理解,我们就可以进行渐进式开发,其余需求可以在后续的迭代中进一步定义和实现。这种过程模型称为演化模型(evolutionary model),它能很好地适应随时间演化的产品的开发。
演化模型是迭代的过程模型,它的特征是渐进地开发各个可执行版本,逐步完善软件产品,如图2-4所示。每个版本在开发时,开发过程中顺序地或部分重叠平行地进行各项活动和任务。演化模型通过以下手段缓解了软件开发所遇到的进度风险、需求风险、架构风险、技术风险、集成风险和质量风险等。
1)优先级高的需求在前面的迭代实现,迭代式交付产品。当进度来不及时,宁可放弃优先级低的需求,绝不牺牲质量。
2)支持迭代间和迭代内的并行开发,加快开发进度。需求在开发早期常常不能被完全了解和确定,演化模型在一部分需求被定义后就开始开发了,然后在每个相继的版本中逐步完善。
3)在软件的开发过程中,需求总会变化,但需求变化和需求“蠕变”会导致项目延期交付、工期延误、客户不满意、开发人员受挫。通过向用户演示迭代所产生的部分系统功能,我们可以尽早地收集用户对系统的反馈,及时改正对用户需求的理解偏差,从而保证开发出来的系统能够真正地解决客户的问题。
4)当我们对项目的技术方案不确定时,演化模型通过早期迭代进行技术探索,建立架构或技术原型,通过原型的测试与反馈来评估和选择合适的技术方案,为后续的迭代化开发提供稳定的基础。
5)在每个迭代中都安排集成和测试,使得系统集成和系统测试提前并持续执行,及早发现代码缺陷。
演化模型是目前采用最广泛的模型,统一软件过程(UP)和许多敏捷过程(如XP、Scrum)都采用了这种模型。原型模型则是迭代次数为2的演化模型,它在第一个迭代中通过界面原型来识别和澄清软件需求,然后在第二个迭代中根据明确的需求进行开发。但是,演化模型也有一个明显的缺点——复杂。它比瀑布模型要复杂很多,其难点是迭代的规划和控制,当然,这也是其成功的关键。本节以下内容将详细阐述迭代化开发原则,并以统一过程为例来解释演化模型。
图2-4 演化模型
2.2.3.1 迭代化开发原则
迭代是处理不确定的复杂问题的有效手段。演化模型采用迭代来应对复杂软件开发中的不确定性,将一个软件生命周期划分为若干个迭代,前一个迭代将为下一个迭代积累经验。
● 迭代化开发原则一:要求每次迭代都产生一个可执行的软件版本。每次迭代本身都包括计划、建模、需求、分析和设计、实现、测试、评估等活动。每个迭代开始于计划和需求,结束于一个小型发布,其内部就像一个小的瀑布模型,即瀑布模型可以看作迭代化开发的一个特例,整个开发流程只有一次迭代。唯一和瀑布模型不同的是,其计划、需求、设计、实现、测试等活动允许(或鼓励)部分并行。
● 迭代化开发原则二:要求有计划的迭代。采用瀑布模型进行开发也有迭代,例如第一个迭代是对所有的功能进行需求分析、设计、实现和测试,在测试时发现需求有缺陷,然后返工至需求,再进行设计、实现和测试,形成第二个迭代,在测试时又发现缺陷,再返工……但这种迭代是无计划的、失控的。我们无法事先预计会有多少次迭代,每个迭代做什么,项目什么时候会结束。迭代化开发要求在做项目计划时就确定迭代的个数,以及每个迭代的起止时间和任务。一个软件项目通常由3~9个迭代组成,项目的风险越高,迭代就越多。迭代的安排和计划是由风险驱动的。
汽车4S店业务管理系统的迭代安排
我们首先分析汽车4S店业务管理系统的风险,发现最大的三个风险如下:
1)第一大风险:需求风险。ABC汽车集团公司提不出具体需求,同时由于激烈的市场竞争,在开发过程中需求将会发生变化。
2)第二大风险:技术风险。采用什么架构,是否要采用Web service技术?SJTU项目组没有相关经验。
3)第三大风险:进度风险。整个项目的开发进度非常紧。按当前掌握的需求,需要9个月才能完成,但ABC公司为了配合一款新车上市,要求7个月后系统就上线。
根据上述风险分析,我们进行了如下的迭代安排:
1)第一个迭代,解决需求风险,开发需求界面原型,并和ABC公司召开需求联合评审会,获得用户反馈。
2)第二个迭代,解决技术风险和架构风险,开发架构原型,并通过测试确保所选的技术和架构是合理的。
3)第三个迭代~第六个迭代,解决进度风险。我们将用户需求排出优先级,将优先级高的需求放在第三个迭代完成,构建系统的第一个版本,并在第四个迭代进行第一次移交,包括移交时的系统打包、用户手册准备、验收测试和部署上线。第五个迭代开发优先级中的需求,构建系统的第二个版本,并在第六个迭代进行第二次移交。每个迭代一个月。
在新车上线时,前四个迭代已经完成。虽然系统的功能没有全部完成,但系统最重要的功能已经移交和上线,而且质量很好,用户可以开始使用。余下的次要功能在第9个月底全部完成,不影响ABC公司的业务。
事实上,迭代的周期有长有短,同一个软件项目中多个迭代的周期也常常不尽相同。典型情况下,一个迭代一般是2~6周,这受软件项目的规模和复杂性、开发组织的规范、稳定性和成熟度,以及软件开发的自动化程度等因素的影响。
2.2.3.2 统一软件过程
每一种软件过程模型都有具体的过程实例,其中统一软件过程(UP)[1]是目前广泛接受的演化过程之一。UP是Rational软件公司(2003年被IBM收购)开发的一个风险驱动的、基于UML和构件式架构的迭代、演化开发过程,它是从几千个软件项目的实践经验中总结出来的,对于实际项目具有很强的指导意义。
UP的整体框架如图2-5所示。它展示了两个维度:水平方向是随着时间逐渐延展的项目生命周期,展示了过程以阶段、迭代和里程碑所表述的动态特性;垂直方向是以规范为逻辑划分的活动,通过过程元素,如流程、活动、制品、角色等展示了过程的静态特性。
图2-5 UP框架
UP把软件过程分为先启(inception)、精化(elaboration)、构建(construction)和产品化(transition)四个阶段。每个阶段又可分为多个迭代,其中迭代的数量和风险相关,风险越大则迭代个数越多。每个阶段结束是一个业务决策里程碑(大里程碑),每个迭代结束是一个技术里程碑(小里程碑)。
先启阶段的目的是在所有项目干系人之间就项目目标达成共识。该阶段对新项目尤其重要,新项目的重要业务风险和需求风险问题必须在项目继续进行之前得到解决。对于扩展现有系统的项目来说,先启阶段较短。先启阶段的结束是软件生存周期的目标里程碑。
精化阶段的目的是建立软件架构的基线,解决技术风险,以便为软件的详细设计和实现提供一个稳定的基础。架构是基于对大多数重要需求(对系统架构有很大影响的需求)的考虑和风险评估建立起来的。架构的稳定性则通过一个或多个架构原型进行评估和验证。精化阶段的结束是软件生存周期的架构里程碑。
构建阶段的目的是基于已建立基线的架构完成系统开发。从某种意义上来说它是一个“制造”过程——由于需求风险和技术风险已经通过前两个阶段受到控制,其重点在于管理资源和控制操作,以便优化成本、进度和质量,又快又好地实现软件的功能。从这种意义上说,从先启和精化阶段到构建和产品化阶段,管理上的思维定式经历了从知识产权开发到可部署产品开发的转变。构建阶段的结束是软件初始能力的里程碑。
产品化阶段的重点是交付最终用户可以使用的软件。它可跨越几个迭代,包括测试处于发布准备中的产品和基于用户反馈进行较小的调整。在产品化阶段,用户的反馈应主要侧重于调整产品、配置、安装和可用性问题,而所有软件架构上的问题应该在项目早期阶段就已得到解决。产品化阶段的结束是软件产品发布的里程碑。