在1960年代中期软件危机爆发之后,人们就在对软件的生产方式进行着不断地探索,以期找到更加高效,科学的软件开发方式,来提高软件的生产率,提升软件的质量。于是便有了随后提出的软件工程的概念。于是我们在现在的软件开发过程中,或者在软件工程课程老师的介绍中,就会看到这样的一种开发模式:在项目前期将调研工作尽可能做到面面俱到,客户的需求以合同的方式进行“冻结”,在这些需求确定和调查的基础之上,可以开始进行初步的软件开发计划书的说明,随后进行需求分析,系统设计等等。开发过程中或许会有迭代,但通常客户只有在测试或者培训时才会看到产品的真容。为了保证开发过程的正确性以及产品的按时交付,在每一项任务开发之前,还要撰写内容详尽的设计以及测试文档等。这种软件开发方法在软件危机爆发之后一定程度上提高了开发的规范性,可靠性,面对复杂软件的设计,也可根据各类文档中对各个功能模块的划分,然后任务分配的个人完成协同开发。然而进入21世纪之后,信息行业的迅猛发展也带来了软件产业的大繁荣,也因此市场的竞争更加激烈,产品开发周期也需要相应的缩短。面对越来越多的软件开发项目,传统的软件工程似乎不再像提出之初那样是一颗“灵丹妙药”,于是便有了后来提出的敏捷开发,。那么究竟出了什么问题呢?敏捷开发能够有效面对所有的开发场景吗?
为了对这个问题进行深入的了解,首先我们需要知道软件开发是干嘛的,什么样的软件能够被称作一个好的软件。所谓的软件开发,实质就是把用户的需求转化为能满足需求的可执行代码的一个过程,转化之后的好坏怎么判断,没有绝对的标准,但是我们可以从普遍的用户反馈上总结出以下几点:
(1) 正确性:软件的正确性是指软件按照需求能够正确执行任务,并且得到正确的反馈或者结果的能力。这无疑是软件质量的第一保证。简单试想一下,如果你开发出的计算器软件运算的结果都不正确,能够被称作一个好的软件吗?
(2) 可靠性:可靠性根据IEEE的规定,包含两个方面的含义。一方面是指在规定的时间周期内程序执行所要求功能的能力,这与软件的正确性相关;另一方面是指在规定条件和规定时间内,软件不引起系统失效的概率,这里主要牵涉到程序的健壮性,即系统如果出现了某种意外软件能够按照预定的方式进行适当的处理,从而避免出现严重的后果。比如说银行的账户管理系统,你再执行转账操作时,一方的钱你已经扣掉了,但此时机器故障,比如断电等,那么就要考虑如何处理这种意外情况,避免出现一方的钱少了,另一方钱没到的情况。
但是一个软件能够满足用户的需求并且得到正确的结果,执行过程总遇到意外情况能够有效处理,这样就能称得上一个好软件了吗?显然这样只是满足了最基本的要求,你可以交付你的产品了,然而并不能称为这是一个好软件。还应当考虑到软件的效率(需要占用多大空间啊,执行一个任务需要花多少时间啊等),在不同平台上的适应情况(当然软件也可以不跨平台),是否简明易用等等因素,这里不再一一列举。
知道了什么是一个好的软件,或者说能够满足基本要求的软件之后,我们再来看依据传统软件开发方法,我们是否能够充分利用现有的资源,正确高效地设计出一个好软件。
我们采用传统软件工程中的瀑布式开发模型来对开发过程进行说明,传统的软件工程一个项目从开始到结束基本包含以下几个基本阶段:
过程中每一个阶段的结果作为下一个阶段的输入,下个阶段的执行情况再进行反馈,对上个阶段进行相应的调整。但是这样的一个模式或者说开发方法有着很明显的缺点。首先软件开发过程是基于项目开始时进行正确的估计和设计进行的,因此在开发进行到一定阶段时,才会进行测试,这时发现的bug很可能是在设计之初被忽略的严重的问题,甚至影响到整个系统的构造。然后项目进行中会撰写各种各样的文档,设计时必须严格按照文档进行,但是实际设计中变更是无处不在的,这包括需求,设计,代码,测试各个方面,因此完全按照文档进行开发并不太现实。最后,客户见到产品是在整个过程结束之时,但是客户毕竟不参与到设计中,他陈述的需求和设计人员理解的需求,或者说实现方式,并不一致,这就导致了产品开发出来,但是客户却不买账,此时再推翻重新设计,为时已晚。这些缺点是显而易见的,从无数个软件的开发过程中就可以看到这点,归根结底,原因就是情况一致在发生改变,而你进行的设计还在基于之前某个时间点的理解进行。并不是说使用这种开发模式不能够开发出一个好的软件,团队能力卓越,当然可以,然而并不是每个团队都有这样的远见以及卓越的能力。
接下来我们再看敏捷开发。看名字就能够理解这种开发方法具有的一个特点,“快”。所谓的敏捷开发,我个人认为其核心的思想就是在尽可能早的情况下推出一款可以使用的软件,可能并没有完成用户的所有需求,设计也不够完美,但是这只是整个过程中的一次迭代。用户通过使用软件,提供反馈,从而参与到每次迭代过程中,迭代之间用户当然可以更改现有的需求,也可以提出新的需求。敏捷开发出了这一点,当然还有别的要求,具体读者可以参见敏捷开发的十二条准则,这里笔者不再赘述。那么我们来看看敏捷开发是如何解决传统软件工程中遇到的问题的呢。首先一点就是由于这是一种迭代增量的开发模式,每个迭代结束之时,用户就能够及时接触到产品,并且对需求进行明确,因此用户需求的不明确的问题会随着开发的进行逐步被解决。然后就是测试参与的太晚导致严重bug发现过晚,从而导致项目进展不能按预期进行的问题。在敏捷开发中,项目被解构成具有各个功能的子模块,每个子模块都具备可集成和可运行的特点,因此可将测试渗透到每个开发过程中。另外,敏捷开发的一个特点是以测试来驱动的,也就是说,在了解了需求之后,首先根据需求来进行测试代码的编写,然后编写相关代码能够满足这些测试用例。可以说,敏捷开发中所认识到世界更加符合现实世界的常态,情况是时刻进行变化,需要能够及时认识到变化,并且及时作出应对才能够跟得上发展的步伐。但是敏捷开发并不是没有缺点的,当面对的项目比较巨大时,可能我们很难对项目进行模块划分。而且随着项目的增大,团队的规模也需要相应的增加,这时团队中负责各个模块的小组之间的交流也就变得更加困难,使得模块之间的集成变得困难。
其实关于这两种开发方法,在查阅资料了解的过程中,看到一个比喻非常合适。传统开发方式就像普通火炮,而敏捷开发就像是制导导弹。普通火炮打击目标是,要想命中,就要开始瞄的准而且对目标的运动轨迹进行准确的预测,即使如此,发射之后还是会受到风向风速,突然出现的障碍物等的影响。而制导导弹只要在发射时设好目标,就可以在行进过程中根据目标对自身的运动状态进行调整,最终命中目标。当然这个比喻有些许片面,但是相信对于两者开发过程的理解还是很形象的。