本节书摘来自华章出版社《SAFe 4.0参考指南:精益软件与系统工程的规模化敏捷框架》一书中的第3章,第3.15节 作者[美]迪恩·莱芬(DeanLeffingwell),更多章节内容可以访问云栖社区“华章计算机”公众号查看。
3.15 内建质量
通过快速集成学习环,进行增量式构建。
—— SAFe原则#4
摘要
内建质量是SAFe的四个核心价值观之一。企业以最快的可持续前置时间交付新功能,并应对瞬息万变的商业环境,这些都有赖于解决方案的质量。内建质量不是SAFe特有的概念,它是精益–敏捷的核心原则之一,有助于避免与需求召回、返工及缺陷修复相关的延迟成本。敏捷宣言同样专注于质量,其中有一条敏捷原则是这样描述的:“坚持不懈地追求技术卓越和良好设计,敏捷能力由此增强”(参考资料[1])。内建质量对于大规模系统的价值是确切无疑的,并且属于强制性的。为此,本节将介绍软件、固件和硬件的质量实践。
软件方面的质量实践——很多是受到极限编程的启发,而且在极限编程中也有描述——可以帮助敏捷软件开发团队,确保他们所构建的解决方案是高质量的,易于响应变化的。这些实践间的相互协同的本质,重点在于频繁地确认,以及建立一种把工程和匠艺作为关键业务推动者的自发的文化氛围。
对于固件和硬件,其质量目标和软件是相同的,但是在物理和经济上有些不同,因此实践上也有些差异。这些差异包括,固件和硬件的开发会更加专注于建模、模拟和更多的早期探索过程,以及更多的设计验证和更频繁的系统级集成。
详述
当企业需要应对变化时,建立在良好的技术基础上的软件和系统更容易去改变和适应。这对大型系统来说则更为重要,因为即使是小缺陷的累积效应以及错误的假设,都可能造成令人无法接受的后果。
实现高质量的系统是一项严谨的工作,需要持续的培训和承诺,但对业务收益的投资也是非常必要的:
更高的客户满意度——低缺陷率的产品和服务能提供更好的客户满意度、更高的安全性、更好的投资回报,并给业务部门增添更多的信心。
开发组织的预见性与信任——如未在解决方案的质量上进行可靠的控制,那么对新功能的开发不可能做出可预测性的计划,也无法确定开发的速度。因此在公司内会造成一种信任感缺乏,降低个体对软件工艺的荣誉感,造成士气的低落。
可延展性——当组件能清楚地表达设计意图,展现出简洁的风格,并在系统架构上支持集成和测试,这时投入更多的人力和资源会为企业带来更多的商业价值。否则,增加更多的开发和测试人员反而会给企业带来拖累,最终将导致高度不确定的、企业无法接受的质量和延迟。
速度、敏捷性和系统性能——更高的质量有助于提高可维护性和增强快速开发新业务功能的能力。同时也会提高团队维护和提升关键的非功能性需求的能力,包括:性能、可扩展性、安全性和可靠性。
创新的能力——创新出现在聪明的、富有激情的人身上,以及由他们所掌控的环境中。在高质量创造出的良好技术环境下,创新的想法能够很容易地产生原型、测试和演示。
下文将对在软件、固件和硬件上达成内建质量的实践进行总结。
软件
SAFe是建立在长达几十年的不断演化、不断追求更好的工程实践的基础之上的,在很大程度上受到了创新性的精益和敏捷方法的推动。当谈到软件工程时,极限编程实践起着引领的地位(参考资料[2])。除了敏捷架构在保证系统级的质量中所起的关键作用之外,SAFe还引入了关键的精益–敏捷软件工程实践,以帮助团队实现最高级别的质量。下文总结了这些实践,其中的两个——持续集成和测试先行,在本书中会有更深入的阐述。
持续集成
持续集成(Continuous Integration,CI)是一种软件工程实践,它每天不间断地把开发人员自己工作空间中的代码合并到单一主干代码分支上。通过这种方式,所有共同开发程序的人员能一直保持在最新的程序版本上工作,开发人员之间的程序缺陷能立即被发现,假设也能立刻得到验证。持续集成有助于避免系统集成的延迟风险,及其对系统质量和项目可预测性的不利影响。
持续集成需要专业的基础设施和工具,包括自动化构建服务器和自动化测试框架。但更重要的是需要建立一种文化和使命感,要求个人和团队以交付完全集成和全面测试的软件为荣。
在SAFe中,团队至少每天执行一次本地集成,但同样重要的是要将完整的系统进行集成,并在必要的时候运行回归测试,以确保系统向期望的方向发展。在初期实现每日集成不太可行,所以合理的初始目标可能是,在每迭代中至少实现一到两次全系统的集成。这样也为成功地进行每两周一次的系统演示提供了基线。
8.1节中提供了关于该主题的更多内容,特别是系统级和解决方案级的持续集成。
测试先行
测试先行是一种鼓励团队在代码实现前深入思考系统行为的哲学。它提升了编码的效率并使得产品更易于使用,它同时建立了一种更为全面的测试策略,由此系统的需求被转化为一系列的测试案例,通常这些测试案例在编写代码前会事先写好。
测试先行策略可细分为测试驱动开发(TDD)和接收测试驱动开发(ATDD)。两者都由自动化测试所支持,自动化测试是支持持续集成、团队速度和开发有效性所必需的。
在测试驱动开发中,开发人员首先编写自动化单元测试案例,执行测试案例并观察其运行失败,然后编写一个最小的代码用以通过测试。测试驱动开发主要适用于编码方法或者单元(技术)层面,这保证了测试的真实存在,防止镀金和编写不必要的更复杂的代码。同时,测试驱动开发还有助于保证需求能持续得到自动化测试,并保持最新的状态。
接收测试驱动开发是一种先进的技术,表征系统行为的接收标准由产品负责人确定,然后将接收标准转换为可反复执行的接收测试,在系统演进的过程中保证持续的一致性。接收测试驱动开发有助于团队专注于系统级别的、用户可观测的需求,这给团队提供了清晰的成功标准。
8.2节中提供了关于该主题的更多内容。
重构
重构是“重组代码的现有结构,改变其内部结构而不改变其外部行为的技术”(参考资料[3])。敏捷避免“大量的前期设计”(BUFD),并遵从“即使在开发后期,也拥抱需求变
更”(参考资料[1]),这意味着当前的代码库在业务需要新增功能时是经得起考验的。为了保持这种应变能力,团队不间断地通过一系列小的改进持续进行重构,为未来的发展打下坚实的基础。如果因为“总是希望增加新功能”,而忽视重构,就会快速构建起一个僵化和不可维护的系统,最终导致经济效益越来越差。
重构是实现浮现式设计的关键,而且是敏捷开发中必要和不可或缺的组成部分。有关重构的更多指导信息,请参见“重构”的有关阐述。
结对工作
结对工作与结对编程相对应,结对编程是极限编程中的一种强制实践,需要两个程序员在同一台电脑上工作。一个人编码,另一个人是观察员,负责评审、检查和为编码过程增值,在结对过程中角色可以互换。在每写一行代码前,结对人员都要讨论需要做的事情,并达成对需求、设计、测试的一致理解。观察员检查代码,提出关于如何提高代码的意见,并指出潜在的错误。结对编程中会进行实时的、全面的同行评审。
结对编程是极限编程的组成部分,但它也是有争议的,有些人认为结对增加了成本,因为两个人在同样的代码上工作。同时,结对编程也可能面临人际交往和文化上的挑战。
对很多人而言,结对编程过于极端了。然而在实践中,敏捷团队中有很多种不同的结对工作方式,每一种都有其价值,并且可以结合起来应用。有的团队在所有编码工作上都遵循结对编程标准,就像极限编程中所描述的那样;有的团队中开发人员与测试人员针对故事进行结对,在故事完成时评审彼此的工作;还有的团队更倾向于自发的结对,开发人员在关键代码片段、重构遗留代码、开发接口定义以及系统级别集成等有挑战性的工作上进行结对。结对工作是重构、持续集成、测试自动化,以及代码集体所有权的重要基础。
集体所有权
集体所有权“鼓励每个人为项目的所有部分贡献新的想法。任何开发人员都可以更改任意一行代码去增加新的功能、修复缺陷、改进设计或重构。没有人会成为变化的瓶颈”(参考资料[4])。集体所有权在SAFe体系中尤为重要,因为大型系统拥有大型代码库,最初的开发人员很可能已经不在项目团队中了。即使那些人还在团队中,如果总是依赖某一个人去修改代码,就会造成工作上的交接,也一定会带来延迟等待。
扩展集体所有权的实施,需要在整个项目群中遵循经过验证的、一致商定的编码标准,拥抱简单的设计,揭示代码结构中的意图,并建立接口机制用于进行灵活的系统修改。
固件和硬件
除了编码以外,没人能够扩展低质量的组件或系统。硬件元素都很少涉及“软”的部分,比如电子、电气、流体、光学、机械、包装、热能等,所以它们更加难以变更,而且如果发生变更会更为昂贵。如图3.15-1所示(参考资料[5]),固件和硬件中的错误和未经证实的假设可能导致更高的变更和返工成本。
如下文所述,这种更高的后期变更成本,促使网络物理系统的精益开发人员使用一些相关实践,确保在解决方案开发过程中的内建质量。
探索早期迭代
正如参考文献[6]中所强调的,即使在建造“哈雷–戴维森摩托”时,也需要一个非常完整的团队在道路上测试新的摩托车,更频繁的设计周期是系统构建者的有效工具,它能够用以加快对产品知识的掌握,降低风险和后期发现错误的成本。在这方面,SAFe使用与软件相同的方式来处理固件和硬件,比如所涉及的迭代和项目群增量节奏,以及目标期望等都大致相同。然而,早期的迭代是特别关键的,因为变更成本还没有达到很高的水平。精益系统构建者应用“更软”的工具系统展开更快的迭代,包括以下内容:
敏捷架构
基于模型的系统工程
基于集合的设计
频繁的系统级集成和测试
持续集成是许多软件解决方案的一个有价值的、可实现的目标。然而,在网络物理系统中却难以应用甚至难以想象,因为有许多物理部件——模具、机械、小部件等,产品演变缓慢,而且无法每天进行集成和评估。但是,这不能成为延迟和难于进行集成的借口。
毕竟,最终所有不同的组件和子系统——软件、固件、硬件等——必须集成到一起,才能提供有效的解决方案级的行为,而且越早越好。为此,精益系统构建者尝试在早期频繁地集成和测试子系统和完整系统。这通常需要增加在开发、部署、测试等基础设施方面的投资。
设计验证
然而,仅仅集成和测试是不够的。首先,由于系统的各种组件在可用性方面的依赖,集成和测试可能在整个流程中发生得太晚;第二,集成和测试不可能覆盖所有可能的使用情况和失败场景。为了解决这个问题,系统构建者执行设计验证以确保设计满足解决方案的意图。设计验证可以包括:诸如子系统之间需求的规范和分析的步骤,最差情况下的容忍度和性能分析,失败模型和影响分析,可跟踪性,热分析,环境,以及其他系统级部署方面等。
在软件领域,虽然设计验证的诸多方法也很重要,但由于软件的变更成本较低,所以在设计的选择上不需要太多的事先承诺。然而,对于固件和硬件,需要前期设计方面的更多考虑,以及工作规范上的保证。
参考资料
[1] Manifesto for Agile Software Development. www.AgileManifesto.org.
[2] Beck, Kent, and Cynthia Andres. Extreme Programming Explained: Embrace Change. Addison-Wesley, 2004.
[3] Fowler, Martin. Refactoring.com.
[4] http://www.extremeprogramming.org/rules/collective.html.
[5] Rubin, Ken. http://www.innolution.com/blog/agile-in-a-hardware-firmware-environment-draw-the-cost-ofchange-curve.
[6] Oosterwal, Dantar P. The Lean Machine: How Harley-Davidson Drove Top-Line Growth and Profitability with Revolutionary Lean Product Development. Amacom, 2010.