只有验证 才可交付--由一个典型的错误所想到的

只有验证 才可交付

--由一个典型的错误所想到的

/陈尚义

只有验证,才可交付,在软件工程领域,这似乎是一个非常简单的、连一般的软件工程师都懂得的道理,然而在实际工作中,这一基本的原则往往得不到贯彻执行。下面举一个例子。

五月份,W4.2作为标准版,正在不断出货。对“不断出货”的标准版W4.2有以下几个方面的要求:

l 及时修复客户在使用中发现问题(bug);

l 及时响应客户提出新的要求(不是很复杂的要求);

l 满足OEM厂商对W4.2的要求,即W4.2的每次升级都要反映到OEM厂商。

所有这些,迫使W4.2处在动态的升级和维护中。

为了应对市场需要、击败竞争对手,我们要在W4.2中增加一个新的很复杂的功能X。在一个动态的、不断变化的W4.2中增加这样一个大功能,我们面临着两个选择:

第一,将W4.2的代码库(code base)复制一份,变成两个代码库:base Abase B。在base A上修复bug响应客户的需要, 满足用户提出的一些新(但都不是很复杂)的功能,以及时出货;在base B上,开发功能X(很大、很复杂的功能),因为功能X的开发可能对WB4.2带来很大影响,引入很多新的bug,在base B上开发功能X不会造成什么影响。同时,时刻保持两个代码库同步,一旦base B+功能X变得成熟、满足发布条件时,抛弃base A(因为base B=code base A)。这个方案的好处是,在开发功能X时,其可能带来的很大风险不影响当前客户的出货要求;这种方案的坏处在于,保持两个代码库同步(即:使base A中改正的bug或增加的小功能体现在base B上)是一件很难的事情,需要手工将修改好的代码同时往两个代码库中存放(check in)。手工存放操作是很费事的,且为了保证base Abase B的一致性,除了测试没有别的办法,而测试两个功能一样的系统是巨大的浪费。

第二,在一个代码库上开发,即直接在代码库中增加功能X,同时修复一些原来系统中的bug、增加一些新功能以满足特殊客户的需要。这样做的好处是,只维护了一套代码,省却了同步的烦恼;其坏处是,文件功能X可能对系统造成较大影响,当前正在等待出货的客户要求不能及时满足。

尽管第一种方案存在很严重的缺陷,但经过仔细研究,我们还是决定采用它。但同时要求,在base B上进行的功能X一旦稳定之后,抛弃base A。做出这个决定是5月份的事。5月份到8月份之间,实际执行的情况是这样的:在base A上,测试组测试该代码生成的系统W4.2,不断发现的bug一个一个地得到修复;客户不断提出的增加新功能(非常小的功能需求)的请求也得到实现;OEM的版本也能和base A保持同步。这样,base A所生成的产品越来越成熟,其产品在很多客户处使用着。在base B上,开发着功能X,另一部分测试人员对这个功能进行着仔细的、较为全面的测试,但这个测试与base A上的测试不同,对base A的测试只测试base A所对应的产品功能,而在base B上的测试只测试功能X base B上的功能不被测试。

经过三个月的开发和功能X的测试,814日,召开会议讨论功能X的发布问题。会上,有人建议将base B代码加上功能X的代码,这两部分代码合成在一起生成新的build,因为base Bbase A的映射,应该没有问题,因此这个build可以作为发布的候选(Release Candidate)。

这是一个严重错误的建议!

为什么呢?因为他们错误地认为baseA= baseB了,因为这两个代码库经过了手工同步。而“手工同步”只是简单地对代码进行人工比较,而没有进行动态测试。很明显,base B对应的产品没有得到充分验证。提出上述建议的人,主观地认为base Bbase A经过了手工同步,“应该”是一样的,所以base B无须验证。

除此之外,在base B和功能X的代码之间,不可避免地、必然存在一个藕合区”(如下图所示)。所谓藕合区,是指由于两个部分集成到一起所增加(或修改)的必要的代码。显然,这个区域的代码被那些人忽略了,尽管这个藕合区很小,但是个盲点。只有验证 才可交付--由一个典型的错误所想到的

这个藕合区的代码既没有得到验证,也不在上面的同步的范围之内,没有得到任何检查。所以正确的做法应该是,集成base B、藕合区和功能X,生成新的build,再对新的build做充分测试,才能发布。然后才可以抛弃base A

软件是一个非常复杂的系统,是看不见也摸不着的逻辑产品,没有充分验证,是无论如何也不能交付的。上面的例子只不过是某些错误观点和倾向比较集中的体现,这个例子让我想起了很多:

一、以为没问题就交差。这种现象不仅出现在产品发布阶段,也体现在每一个软件过程中,体现在每个工作产品(work product)的提交上。他们往往主观地判断可能没错误应该没错误,这些都是非常错误的观点。在保证软件产品质量的措施中,验证(Verification and Validation)是必不可少的。以为是正确的地方偏偏发现有问题,这样的例子太多,其教训也是非常惨痛的。没有验证,决不能交付是软件工作者必须遵守的铁定的规律。

二、把增量测试作为发布前的验证。由于时间紧任务重,测试工作做不完,于是只对那些改动了的部分做一些测试,还美其名曰增量测试。这是一个非常危险的举动,因为任何改动所波及的范围是事先很难估计出来的,其潜在的、隐形的影响更是无法估计。很多莫名其妙的问题(Wicked problem)就是由于考虑不周引起的。发现并排除这些问题,只有靠软件验证,别无他路可走。

三、自动化测试是好的,但不是必须的。持这种错误观点的人,没有认识到软件测试的难度和软件自身的复杂性。竞争加剧,软件需求变化快,用户要求千奇百怪、甚至相互矛盾,研发部门虽然对各项工作作出了优先级识别和排列,但是,计划没有变化快。在软件开发的实践中,测试速度成为软件开发的瓶颈。一个修改后的软件,到底对其它地方有没有构成影响,局部修改后整个系统还能不能工作?不准确清楚地回答这些问题,产品质量就无从考察。要回答这类问题,没有自动化的测试手段和工具是不可能实现的。所以说,自动化测试不仅降低了测试者的劳动强度,更主要的是自动化测试成为软件质量控制过程中必不可少的手段。有了自动化测试,一个build很快就可以得到验证,不会出现没有时间就只能做增量测试的情况。

类似的错误做法和观念还有很多,在此不能一一列举。很多人喜欢把这些归于客观因素,道理都明白了,就是没有精力做。其实,这些人并没有正确认识到验证在软件开发环节中的重要作用。树立正确的服务意识,把客户牢记在心中,坚持只有验证才可交付的原则,是每个职业化的软件工程师应具有的起码的素质。