6.2质量不是测试出来的

质量不是测试出来的,而是内建出来的。我认为,一个好的过程必然会有一个好的结果。质量也是如此,一个好的质量保证体系必然会产出一个好的质量结果。质量内建是要求软件生命周期中涉及的所有角色对软件的实时质量负责。那么,我们要如何内建质量呢?我总结了以下七个方面。

6.2.1 需求分析

需求分析是项目经理和团队之间持续对话的过程,也是用户故事和验收标准的基础。而澄清用户故事和验收标准是确保质量的最重要手段或工具之一。

同时,我们还要明白验收标准不是合同,用户故事也不是文档,它们最重要的作用是沟通,是项目经理用于与项目团队之间沟通的重要工具和手段,甚至有时候也是与相关方沟通的内容之一。

需求分析是质量内建的开始。我们都知道,输入是垃圾,输出必然也是垃圾。所以,没有对需求的充分分析和沟通,质量无从谈起。在澄清需求时就要注意以终为始,确保输入的需求的质量。

为了确保输入需求的质量,我们需要注意以下三点:

(1)解释清楚业务目标,即价值。换句话说,我们能够解决用户或业务的哪些问题。

(2)操作和业务流程。为实现上述目标,需要系统支持哪些用户操作?这些操作的流程什么样?

(3)业务规则。每个操作步骤对应的业务规则是什么?业务规则转化为验收标准。

需求不是文档,而是用户的价值。只有从价值出发,逐层分解,从业务到实现充分沟通,才能保证后续交付的质量。

6.2.2 持续集成

敏捷方法的创始人之一马丁·福乐(Martin Fowler)对于持续集成的定义是:持续集成是一种软件开发实践,在实践中项目成员频繁地进行集成,通常每个成员每天都会做集成工作,如此,每天整个项目将会有多次集成。每次集成后都会通过自动化构建(包括测试)来尽快发现其中的错误。

简而言之,持续集成是一种软件开发实践,即开发团队成员经常集成他们的工作。其实,这也软件开发从业者工作和生活的一部分。我在项目中也会这么做,每个成员每天至少集成一次,意味着每天可能发生多个集成。但是每个程序集都通过自动构建(包括自动编译、发布和测试)来进行验证,所以不会占用太多的时间,反而可以尽快检测到集成错误。慢慢地,你就会发现这个过程大大减少了集成问题,使团队能够更快地开发内聚的软件。

持续集成是质量内建的重要实践之一,因为它能给我们非常及时的质量反馈。集成越频繁越能早在代码中检测到问题。但是这个过程中有一个问题无法避免,因为频繁的集成意味着有很多连续的、可重复的工作。我们如果用人工肯定是不行的,效率低、成本高,而且时间也不允许,所以在持续集成的工程实践中必须实现全过程的自动化。

这项工作的自动化远比人工的手动操作可靠。作为软件开发从业者,代码就是我们的工具和武器。在自动化可行的情况下,应以自动化的方式来实现,以减少人为错误造成的缺陷,腾出精力和时间专注更有价值和创造性的任务。

6.2.3 测试先行

质量不是测试出来的,没错,为什么要等到完成以后去测试呢?为什么不可以让测试先行呢?也许在其他行业像天方夜谭,产品都没有,拿什么来测试?但是,在软件开发中是可以的,不仅可以,还有很多非常好的方法。比如测试驱动开发(test-driven development,简称TDD),是极限编程(extreme programming,简称XP)的一个重要组成部分。同时,它还是一种设计方法论。它的基础原理是在编写功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。

TDD虽是XP的核心实践,但不只适用于XP,还适用于其他开发方法和过程。TDD优点主要有以下几点。

(1)可以澄清这些需求。因为测试是先行的,所以测试用例是根据需求而不是代码来设计的。模糊需求是没有办法编写测试用例的,必须事前予以澄清。

(2)可以避免过度设计。根据测试用例只编写能够通过测试的代码,多余的代码一行都不写。

(3)测试用例其实就是最好的代码注释,避免没有注释或者文档,以及文档或注释过期的问题。

(4)与代码提交的还有一个测试用例集,保障了将来重构和代码冲突时候的安全性。

我们可以发现,以上优点都是质量的有力保证。

验收测试驱动开发(acceptance test driven development,简称ATDD),是在TDD基础上发展而来的。ATDD解决了TDD在实践中遇到的一些实际困难,如工期紧张、单元测试耗时较长等。在代码层次,在编码之前写测试用例代码就TDD,而是在业务层次,在需求分析时就确定需求(比如用户故事)的验收标准,就是这里所说的验收测试驱动开发。从需求的角度准备验收标准和测试用例,同样确保了早期开发中的高质量。

行为驱动开发(behavior driven development,简称BDD)可以看成ATDD的实例化,只是BDD更强调用户的视角、用户的行为和应用场景,为ATDD注入了“Given,When,Then”这样特定的需求描述语言。这跟敏捷的用户故事极为吻合。

TDD在编写测试用例时,经常会问“我们应该先测试什么”,然后根据测试条件编写代码,而BDD试图以另一种方式思考这个问题,会问“期望的行为是什么”,可以编写出更好的结构化代码。最后,我们可以通过BDD更好地了解客户的需求,并通过了解客户的不同行为来逐渐加深对客户需求的理解,从而驱动软件开发。

6.2.4 重构

在马丁·福乐的名著《重构》一书中,他把重构定义为:“在不改变代码外在行为的前提下对代码做出修改,以改进代码内部结构的过程。”

为什么要修改正在正常运行的代码结构呢?福特汽车的创始人亨利·福特(Henry Ford)有句话是:“如果东西没有坏,就不要去修理它。”

重构的目的是随时清洁代码。我们不希望技术债堆积起来。我们希望付出最小的努力就能够扩展和修改系统。敏捷开发的原则之一是在每次迭代中提供可用的用户功能,以便更快地获得用户反馈,然后根据实际数据和反馈不断改进。

这同样适用于需求和代码。代码除了能够稳定运行现有功能,它还必须足够健壮,以便随时应对变化。如何保持代码的活力?重构是我们唯一的选择。重构也是消除技术债的有效途径。

当然,重构并不是能够轻易做出的决定。项目经理要明白重构同样代表需要额外的人力和时间,这就是成本。在重构之前,首先检查是否有一套可靠的测试机制。

6.2.5 代码回顾

代码回顾的必要性和重要性相比不需要更多的证明,代码回顾的好处也不存在争议,代码评审不仅是获得质量的一种重要手段,还是一种很好的知识共享方式。那么,如何保证代码回顾的质量呢?

(1)在团队技术能力的不同阶段采用不同的代码回顾策略。如果团队稳定,编码规范掌握良好,使用的语言熟悉,那么代码评审可以集中在业务逻辑上;如果团队是新的并在磨合中,则可能需要更多地关注编码规范;如果团队刚刚更换了一种新的编程语言,那么语法本身也可能是代码评审的重点。

(2)不同的业务阶段需要不同的代码回顾策略。例如:TO B的业务在稳步推进,那么代码审查可能需要更加小心和严格,确保代码的质量、可读性和可维护性;而在互联网行业,技术负责人必须在业务发展的早期阶段或快速试错阶段来平衡代码审查的强度和业务交付的压力。

团队内还需要开放的心态和文化。要让团队清楚,代码回顾不是设置障碍,而是一个基本的质量保证过程,也是一个相互学习的过程。在过程中,我们需要就编程规范达成共识,避免由于编程习惯而产生不必要的误解。

控制每次代码回顾的代码量。如果一次提交大量代码进行代码回顾,那么帮助代码回顾的人就很难一次性拿出这么多时间,而且很容易遗漏关键点。同时,提交代码的人必须在提交说明中明确提交代码的目的:它实现了什么功能?进行了哪些优化?哪些BUG被修复了?这样,代码回顾者就可以有一个明确的目标,并理解代码更改的上下文。

(3)为了使代码评审成为一种习惯和工作的一部分,有必要确保代码回顾者有足够的时间,因为每个人在迭代中都有自己承诺的任务。

只有在保证代码回顾时间合理的情况下,代码回顾才能作为日常任务进行。这时,就可以将代码回顾作为“完成定义(DoD)”的一部分。

6.2.6 代码共有

在建立了良好代码回顾的基础上,我们就可以尝试着代码共有制。代码共有是共享和进步精神的体现,这意味着每个人编写的代码都属于团队,每个人都可以修改任何代码。

集体所有权鼓励每个人为项目的每一个部分带来创新。任何开发人员都可以修改任何代码来添加新的特性、修复缺陷、改进设计或重构。因此,没有人会成为瓶颈,团队也会更加透明。

如果没有代码的集体所有权,很难高效地修改和重建代码,甚至会出现重复代码,增加技术债,破坏代码质量。

代码共有增强了团队对代码的所有权和“主人翁”精神,所有成员都要对代码负责,他们互相监督和共享信息。在一个代码共有的环境中,没有领导,没有权威,一个公平和开放的环境使我们能够回到最本质的工程师文化中,质量由此而生。同样,代码共有也是一个自组织团队的重要标志之一。

6.2.7 代码即文档

代码即文档是诺基亚曾经使用的一个工程实践,这同样是符合“敏捷宣言”中的“工作的软件高于详尽的文档”。把代码作为主要文档的原因是,代码是唯一能够以足够详细和准确的方式执行该角色的代码。尤其是在敏捷开发中,文档的地位变得越来越不重要(尽管敏捷从未说过它是不必要的)。但我们必须承认,不完整、过时和不正确的文档可能误导我们的开发和维护,导致不必要的缺陷和浪费,因为这也是我在项目中经常遇到的问题。

同样,包括注释,如果程序员在不修改注释的情况下直接修改代码,可能会导致很多麻烦。如果出现问题,很难确定是代码逻辑错了,还是说注释过期了,尤其是在祖传代码中,这种情况屡见不鲜。所以,将代码用作文档可以让我们有更清晰的视野。我们就可以有一个唯一的质量标准:可运行的代码。

为了保证代码即文档,开发人员需要在保证代码的整洁和可读性上下功夫,必须努力工作确保代码干净易读。同样,项目经理要做好项目监督工作。

关于软件质量,始终坚持:软件质量不是测试出来的,需要对整个软件项目的整个流程进行构建,以及质量保障体系的建立。构建质量体系才是提升软件质量的核心部分。而构建质量体系一定是内建的,依照以上七个方法,一定能够控制好软件项目的质量。