原文链接: http://www.ibm.com/developerworks/cn/rational/1402_zhaojing_urbancode1/
市场和业务瞬息万变,企业的 IT 部门必须面对产品上线周期不断变短的事实,也就是说,需要建立产品交付反馈圈,并让这个闭环圈的反馈速度持续提高。这个反馈圈是指,从一个新想法的产生,经过决策分析后准备付诸实施,对其立项并监控其开发,经过测试和部署,最后交付产品后得到客户反馈并继续优化这样一个完整过程。从图 1 可以看出,这个过程涉及客户以及企业的多个部门、多种角色,并且要和企业现有的多种流程、工具、方法打交道。
业界有很多最佳实践,都可以帮助企业建立并且逐步优化自己的产品交付反馈圈,这些最佳实践涉及了软件工程的众多领域。如耳熟能详的每日构建、持续集成(CI)等,它们已经在很多企业里被广泛使用,也为企业实现持续交付打下了良好的基础。
然而,持续集成只能说是实现了反馈圈中的一个小环节,现在需要考虑更多并一步步构建完整的产品持续交付能力。因此,为了让 IT 能跟上业务思考的速度,我们需要从持续集成迈向持续交付。
持续集成更关注代码质量。持续集成是为了确保随着需求变化而变化的代码,在实现功能的同时,质量不受影响。因此,在每一次构建后会运行单元测试,保证代码级的质量。单元测试会针对每一个特定的输入去判断和观察输出的结果,而单元测试的粒度则用来平衡持续集成的质量和速度。
决定一个构建(build)是否可以交付需要更多的测试阶段。仅仅构建和单元测试能够通过,是不足以回答“是否可以交付”这个问题的。质量有很多层面,单元测试仅仅验证了一些维度,这个构建在真正能交付前不得不通过其他额外的测试阶段。
一个构建在不同测试阶段传递的过程称之为交付管道(Delivery Pipeline)。如果一个构建在任何一个测试阶段失败,它应该重新回到开发状态并继续在管道中流通。当一个构建通过了一个测试阶段,它应该被提升(promote)到下一个测试阶段。随着测试阶段的推进,一个构建可以进入到下一阶段的准入门槛也应该越来越严苛。因此,每一次提升,构建的质量都在不断提高,通过所有测试阶段的构建,才应该被提升到生产环境中。如图 2 所示。通常企业里常用的测试阶段有:单元测试--在持续集成中执行,功能测试,系统集成测试(SIT),用户验收测试(UAT)。每一个测试阶段都需要先在指定的环境中部署好构建,然后进行相应的测试。当然,企业里也会相应增加或减少特殊的测试阶段,这样就构建了自己的交付管道。
持续集成 | 部署 | ||||
构建 | 单元测试 | 功能测试 | 集成测试 | 用户验收测试 | 生产环境 |
v.1 | 失败 | ||||
v.2 | 成功 | 失败 | |||
v.3 | 成功 | 成功 | 失败 | ||
v.4 | 成功 | 成功 | 成功 | 失败 | |
v.5 | 成功 | 成功 | 成功 | 成功 | 已部署 |
交付管道的建立和自动化是持续交付的基础。如果持续集成实现了自动化而部署过程需要大量手工操作,那部署就无法跟上持续集成的节奏。部署也需要自动化,部署自动化工具可以帮助一个构建自动地在部署管道中推进,使部署本身不成为瓶颈。另外,部署自动化可以确保整个部署过程可以固化下来,在每次部署中可重复进行。这样就可以既测试待部署工件的质量,也同时验证部署流程的质量,把这种流程也作为资产管理起来。
回页首
企业在构建了自己的交付管道后,关注点就需要从持续集成转向全面的持续交付,也就是将更多的关注点放到部署层面。在构建并优化持续交付能力时,企业或多或少都会面临如下的问题和风险,如:拥有大量自己开发并维护的构建和部署脚本;完全或部分的手工部署过程;难于实现部署失败时的追踪和定位等。因此,根据 Urbancode 公司(已被 IBM 收购)发布的白皮书(https://www14.software.ibm.com/webapp/iwm/web/signup.do?source=swg-rtl-sd-wp&S_PKG=ov17459),这里再次阐明应用持续交付改进的 7 个最佳实践。
开发团队可能分布在各处,或者即便是一起开发也会根据业务逻辑进行团队划分。每个团队都可能有自己的一套应用部署工具和流程。小规模团队这种情况还好,而不同的流程和不同的工具对于大型团队来讲,在编排发布计划时会带来巨大的挑战和风险。
因此,在制定发布计划时,需要建立一个单一的、可信任的、实时更新的部署来源。比如说,待组装的应用组件应该放在相同的容器里进行管理,发布的流程设计应该统一风格和模式,不同环境要求的配置项或者属性信息应该统一设置和管理,等等。这样可以让接入持续交付管道的各个角色协同起来,同时提供了整个交付管道的可视性和可跟踪性,清楚的知道谁、何时、做了哪些动作。
在部署过程中的手工步骤带来了许多风险。比如说,如果这个步骤没有写的特别详细,对于新手来说就存在执行的不确定性;或者这个步骤在部署到其他环境中时遗漏了,就会导致部署失败。另外,手工步骤是难于跟踪和管理的。为了解决这个问题,尽最大可能自动化现有的部署步骤。自动化能力为完成部署步骤提供了一种安全的、被验证过的、成功率更高的手段,理想情况下,所有步骤都应该被自动化。
避免仅仅依赖开发人员口头去描述和理解应用的内部依赖关系。复杂的部署通常包含应用组件的互相依赖。如果组件 A 依赖于组件 B 的某一个具体版本,那么没有部署或者没有正确部署组件 B 将导致整个发布失败。需要将这种依赖关系通过工具管理起来,而且需要保证同时部署的组件必须一起测试过,要测试这些组件的功能和他们的兼容性。当应用在不同的测试环境移动时,必须确保这种依赖关系的顺利移动,也就是说,必须清楚的知道具有依赖关系的某个组件的某个具体版本是否被正确部署。
不知道在某一个机器上或者某一个环境中部署了什么存在很大的风险。尤其当应用向更严格的环境中移动时风险就更大,如当应用从 UAT 环境向生产环境迁移,一个存在于 UAT 环境中的组件版本和生产环境的另一个组件不兼容,文档中并没有记录这一点,那么,这种部署就带来了极大地风险,甚至成为生产事故。另外,停止应用去跟踪和分析其部署也是非常耗时和浪费的事情。如果能对部署环节的“什么。。在哪里。。”管理起来并清晰可见,就可以确保各个环境确实成功部署了组件和组件版本。另外,跟踪应用的部署也变得非常轻松。生成工件部署清单并实时追踪分析就可以为整个应用部署带来更好的洞察力。
认证和审批可以确保质量。在持续交付管道中定义清晰明确的质量属性是非常重要的。只有当在某一个环境中部署的应用,符合了下一个环境的质量属性并得到审核批准后,才能将应用部署到该环境中。比如一个构建经过了 SIT 阶段,需要向 UAT 阶段移动时,理论上应该已经通过了单元测试、功能测试、性能测试、接口测试等一系列验证,并且集成测试部门经理也批准该构建可以部署在 UAT 环境中,那么,该构建的上述验证值应该为真(表示已通过验证),其部门经理批准值也为真(表示已经批准),在 UAT 测试环境的准入条件中,只有这些属性值都为真的时候,才允许部署这个构建。让这些准入条件和审核批准状态清晰可见,所有人才能知道一个应用需要什么条件才能在持续交付管道中前进。通常我们把这种质量属性称之为质量门(quality gate),它正是作为应用向下一个环境迁移的准入条件。
不同的阶段和环境使用不同的部署流程增加了出错的概率。比如,由于生产环境使用的部署流程并没有在更早期的环境中验证过,仅在该环境下的特殊步骤就有可能出现错误。应该使用测试环境去验证会在生产环境上运行的每一个步骤。当编排和设计应用的发布流程时,应该设计成一个单一流程,它被用到整个持续交付管道中的每一个阶段中。
附加说明:
1)经常会遇到在更“高级”环境中的步骤不存在于“低级”环境中的情况。比如生产环境的一个负载平衡步骤可能就不会在开发环境中存在。这种情况下,可以使用条件分支,仅在生产环境下运行该步骤。这样,就形成了具有冗余度的统一部署流程,即便该步骤没有经过前期环境验证,一旦出错,也会立刻定位是负载平衡问题导致部署失败。
2)如果不同环境的部署过程完全不同,考虑仅设计一个“高级”环境部署过程和一个“低级”环境部署过程。避免每一个环境一个过程。为了消除环境间的差异,还可以考虑通过自动环境生成能力搭建环境,如云环境。
发布计划应该做到编写容易,在计划会议上讨论时就能随手制定,而且应该易于理解,让每一个持续交付管道中的角色都能知道计划是怎样的,如果发布变化产生的影响是什么。发布变更应该有便利的协作手段去审核和批准。如果发布计划难于理解,通常都会被束之高阁,这会带来一系列问题,如变更混乱,风险增加。
综上所述,如果企业正在考虑建立或优化自己的持续交付能力,非常建议能够遵循并贯彻如上的 7 个最佳实践,基于前车之鉴快速建立一套可控的、可实施的软件持续交付流程。在宏观层面,帮助企业打造完整的一套跨多个环境的标准交付流程;在微观层面,可以帮助 IT 部门清晰的了解每一次发布是否拥有确切的来源,确定的目标和可落实的流程。
回页首
企业当前的持续交付流程成熟度如何?有没有哪些地方能够改进和提高?下面我们一起了解企业持续交付的成熟度模型。该成熟度模型来源于 Eric Minick 和 Jeffery Fredrick 两位专家,他们拥有多年的一手资料和实际经验,形成了一套企业可以借鉴和参考的持续交付成熟度模型。(http://www.urbancode.com/html/resources/white-papers/Enterprise_Continuous_Delivery_Maturity_Model/)
不同的行业和企业,对于持续交付的理解和应用场景是不尽相同的。只能寻求到他们的共同点和主要特征。为了便于描述,我们选择了 4 个通用环节,来记录和分类企业的持续交付过程,它们分别是构建、部署、测试、报告。在每一个环节中,又根据该环节所常见的一些实践,以及企业对这些实践的应用程度,形成了 5 个成熟度等级。这 5 个等级分别是基础级、起步级、中间级、高级、领先级。同时,在每个环节中,还根据实际经验,标示出了行业普遍能力以及应该达到的目标能力。有了这样的成熟度模型,企业就可以方便的衡量出自己现在处于什么位置,离行业普遍能力有什么偏差,目标能力应该是什么,从而快速找到采取什么行动去弥补差距,实现目标。如图 3。
构建环节
大部分新项目开始时,都是由开发人员在自己的机器上执行构建,而且没有一个标准的流程。一个开发人员在自己的 IDE 上进行构建而其他人可能用写好的脚本来做这件事。最糟糕的企业会容忍这样的方式做构建、测试甚至就将这样的构建发布到生产环境,如果这样,企业就连基础级也没有达到。
从空白水平到基础级:首先,需要做的是在专用环境下(如专用构建服务器)进行构建,而不要使用开发人员的机器去执行。不使用开发人员的机器去构建,可以很好的避免由于个人机器环境、个人工作空间等问题导致的构建结果不确定问题。其次,需要标准化目前的构建脚本(或流程),让其更为统一和固定。比如,如何从源代码控制系统中取到构建源,在实际中有多种实现,可以取构建分支上最新的版本,也可以取打过标签或基线的版本,也可以从某一个目录中找到。这些方法必须统一,并且形成标准规范。
从基础级到起步级(行业普遍能力级别):有了专用的构建服务器和规范的构建脚本之后,需要考虑的是自动化。首先,构建服务器必须随时待命,等待开发人员进行自助式构建,开发人员需要指定的仅仅是代码存放的位置,而其他诸如机器(构建代理)、源代码获取规则、构建规范等都应该由构建服务器统一分配和安排。其次,这种自动化构建需要支持每日定时执行,允许一些团队或个人按照自己的需要一天一次或多次自动执行。最后,所有构建前后涉及的工件都应该被存储。包括构建源代码、构建标签、构建各种配置文件及属性、构建脚本(步骤)、构建结果、构建日志等。
从起步级到中间级(目标级别):在这个级别,自动化已成为基础,需要让构建变得更有价值。首先,实现持续构建,并且每个开发人员和团队都可以使用该实践。也就是说,只要他们一提交代码,就可以自动触发构建过程;甚至当互相依赖的代码模块发生变化时,也能自动触发构建过程。其次,需要更为清晰的管理软件模块之间的依赖关系。不像之前使用约定俗成的方式,现在需要利用专门的工具去真正存储这种依赖关系并能在构建时跟踪和快速定位。这样,不仅能管理软件模块之间的依赖,还可以管理构建和构建之间的依赖关系,并把这些关系都存储在一起。最后,所有存储的构建(在网络存储设备上或者就在构建服务器中)都应该有机制保证定期被有效的清理或被正确版本化,便于将来快速利用。
从中间级到高级:更为规范的企业和团队希望采用更加可控的构建流程,能够把质量因素放进去。首先,此时的构建是可以跟踪的。团队可以针对任何一次构建(无论成功或者失败),跟踪到本次构建用到的源代码变更、计划的变更甚至需求的变更,同时,也能够方便的查看本次构建相关的所有依赖关系。其次,更加严格的管理。构建流程的修改、对构建服务器的访问、构建服务器的配置变更都需要审核和批准行为。另外,针对大型分布式的构建也需要提供支持,使用分布构建服务器去并发执行大量构建。高级阶段由于过于严格,所以建议应用在有遵规需求的企业或者针对于生产系统进行的构建部署上,其他企业/团队或更早期的阶段能做到中间级就已经足够。
从高级到领先级:有一些更为严苛的企业,他们要求能够在需要时针对早期的发布(构建成功后交付的结果)执行完美的重新构建。这就需要使用各种技术来确保重构时具有和当时一模一样的环境来保证成功。可以采用管理版本化的脚本,该脚本包括从准备操作系统到执行构建这样一个完整过程,也可以使用基于快照的虚拟机并对快照进行版本化管理来实现。目前大部分企业没有达到这种级别,因为要实现这样完美的效果需要承担很多额外的负担,如资产管理、人员投入、技术支持等,这对大部分企业来说投资回报率很低。
部署环节
部署就是将软件安装到一个环境中,对其进行配置或测试以保证能够被最终用户正确使用。如一个 Web 应用的部署,就是将其安装在 Web Server 上并更新数据库或者 Web Server 上的静态属性文件;而对于一个游戏应用而言,测试环境的部署是将其正确安装在测试机器上并执行,而生产环境的部署可能还要包括为软件建立 ISO 文件以便于客户安装使用。
部署流程最初始的形态也是手工过程。部署工程师拿到构建成功后的工件,把它放到目标环境中,通过运行事先准备好的安装手册来执行部署。这不仅很慢而且非常容易失败。部署工程师经常不得不在晚上或者周末进行风险极大的生产环境部署,即便是在测试系统上部署,如果测试人员正在进行测试,他们也不得不等待。更为糟糕的情况是,针对不同的环境,部署过程都不一样。即便在一个环境上部署成功,也不意味其他环境也同样顺利。如果企业是这样的现状,就连基础级也没有实现。
从空白水平到基础级(行业普遍能力级别):在这个阶段,最重要的是脱离完全的手工操作。能够采用一部分有帮助的脚本或者完全采用脚本进行部署可以看做是一个重要的水平提升。从目前业界情况来看,大部分企业或团队都有部分的部署脚本,然而很少能实现完全的脚本化部署,尤其是在更严格的 SIT、UAT、生产环境上的脚本化部署。
从基础级到起步级:在这个级别,测试环境的部署管理统一化变得非常重要。需要为开发或测试人员提供可以让其自助部署的测试环境。他们仅需要提供待部署工件并对测试环境有访问权限,就可以提交部署并自动完成一个部署过程,而测试环境的部署步骤是统一设计并提供的。
从起步级到中间级:开始实现一键式部署。利用自动化部署工具将部署脚本固化,并采用一键式方式在一个或所有测试环境中进行自动化部署。部署工程师的工作量和风险大为减轻,测试人员也有更多的时间进行无间断测试。另外,企业开始进行部署流程的全面标准化,可以使用统一部署流程跨各个环境进行部署。环境也许仍然有细节上的差异,但是在早期能够验证部署流程的正确性,已经可以为后面的部署带来预测性的结果。对于大部分企业和团队而言,达到这个级别已经是个不错的目标。
从中间级到高级(目标级别):在这个级别,关注点是更为严格可控的流程和生产环境。生产环境的部署也可以实现一键式,而且一旦出现问题会自动触发灾难恢复流程。同时,该级别也需要引入质量门的概念,保证跨环境的部署是严格受控的。如果是实施项目式交付,也就是生产环境的部署是在企业内部,那么应该将这个级别作为目标级别。
从高级到领先级:真正实现持续部署。可以不用手工干预的将软件构建从测试环境一步步推送到生产环境。在这个阶段,企业已经实现了自己的持续交付管道,并在管道中的每一个阶段都配有完整的自动化测试手段,一旦构建通过了所有质量门,就可以被成功、正确的自动部署到生产环境。对于一些需要快速响应变化的行业,比如互联网企业,通常变更的实现是以小时为衡量,这就要求必须具备完整的自动化部署流程、成熟的自动化测试手段、严格的环境管理和回滚流程、应用部署监控等全面的保证手段。
测试环节
持续交付管道在各个环节都离不开测试。仍然有一些企业和团队对测试不足够重视,执行构建后仅简单的测一下就部署在生产系统中。大部分企业都采用了某种程度的自动化测试--单元测试或一些测试脚本来保证应用的基本功能。能够采用和适应自动化测试的企业,已经处于基础级了。
从基础级(行业普遍能力级别)到入门级:在构建的同时可以执行快速测试,为团队提供基本的代码级质量信心。当测试失败时,开发团队可以实时得到通知以便快速修复。能够实时通知和实时反馈是这个级别的重要判断准则。
从入门级到中间级(目标能力级别):测试多样化。不仅仅可以提供在构建时的快速代码测试,还可以提供源代码静态分析测试、自动化的功能测试。源代码静态分析可以根据企业遵规需要去设计,也不需要每次构建都执行,定期或者在里程碑阶段自动进行并对违规进行修复后才能真正发布版本。
从中间级到高级:该阶段拥有完全的测试类型和能力。每一种测试类型都能充分使用并最大化发挥其价值。定义一些质量标准,单元测试可以覆盖几乎所有代码模块并达到定义的覆盖率;功能测试能实现定义的需求覆盖率;静态代码分析运行的频率更高;引入边界测试、随机测试、安全扫描、运行时分析等测试手段。该级别对大部分企业和团队来讲,已经足够。
从高级到领先级:实现 100%代码覆盖率。也就意味着每一行代码都要被验证过。这种程度的实现需要大量的资源投入,只有对某些企业,如缺陷的修复成本极高或者需要极速交付的企业。
报告环节
报告是一种反馈机制。无论是手工报告还是自动化报告,都可以一定程度了解企业当前持续交付管道各种维度的度量信息。没有报告或者不关注报告的企业是无法进步的,因为所有的测试如果不去了解和分析其结果都是没有价值的。对报告环节的成熟度定义是根据报告的可视范围以及对其利用的程度。基本所有的构建工具都能产生一定程度的报告,开发人员在进行构建时可以看到构建的时长、日志、单元测试结果、成功或失败、趋势等信息,并能够根据这些报告进行个人工作的修正。这样的企业处于基础级。
从基础级到起步级(行业普遍能力级别):报告在团队中可以共享。这和集中管理构建服务器、部署服务器相辅相成。团队中的每个角色--开发、测试、构建、部署工程师都可以运行并发布他们的执行结果报告:构建人员可以提供代码变更报告、源代码分析报告、单元测试报告等;测试人员可以提供最新的自动化或手工测试报告;部署人员可以生成缺陷报告、部署趋势和速度报告等。但此时报告仅能在团队中快速共享,由于是不同的工具产生,跨团队和部门的报告还需要手工实现。
从起步级到中间级:该阶段有两大重要变化。首先,关键的报告已经可以跨部门共享,这里的共享并不是指报告的互相交换,而是数据的贯通。比如测试人员可以深入到开发内部去看,这次测试的失败源于哪些变更,甚至是对哪些代码行的变更。每个人都可以清楚的了解到持续交付管道中上下游的信息,这时候沟通的成本更低,效率大为提升。其次,对于历史报告的重视。历史报告可以被存储并能用于和最新的结果进行对比。测试团队不仅想知道本次测试拥有 95%的通过率,他们还需要了解本次测试新增了哪些用例、减少了哪些用例,为未来的测试用例设计带来指导性意见。
从中间级到高级(目标能力级别):能够利用报告观察数据趋势,让报告带来更多决策价值。中间级可能记录了每次测试失败或成功,而高级能力则可以基于这些形成趋势信息,可以通过趋势分析出哪些代码的变更更容易导致单元测试或功能测试失败。这反过来又能帮助企业决策应该在哪些代码模块设计更多的测试,甚至是否需要对代码进行重新设计。能够跨部门的根据趋势报告和其他多种报告来进行决策和校正,是持续交付管道建设的一个重要目标。
从高级到先进级:通过报告进行预测。整合各个部门或者团队的数据和信息,生成具有多种度量元的报告,并能对今后的部署带来指导和预测。比如根据里程碑 1 的缺陷数量、代码修改量、代码复杂度、构建结果等综合信息来预测里程碑 2 时的相关数据。这样的能力保证了企业可以按照可持续的、良性的节奏实现持续交付。
持续交付成熟度模型,可以作为企业的一种参考,快速判断自己当前的状态、行业普遍具备的能力,并制定符合自己的改进目标。它把一个复杂的过程,经过不同环节和成熟度等级的划分,用一些可以衡量的实践落到实处,帮助企业意识到建立自己的持续交付管道和能力,可以通过在不同的环节逐步引入不同的实践,验证这些实践并优化它们。
该成熟度模型的另一个重要意义在于,调研和实施持续交付时,企业或团队需要有一个正确的期望。级别是随着能力不断完善而逐步优化的,不能简单的认为可以通过一个自动化的工具或者平台,就能够一步登天。另外,对自己当前的能力要有正确和深刻的认识,不是所有环节的高级和领先级都是最适合自己的,盲目的去追求更好的等级,只会无谓付出更大的代价和较低的投资回报。只有真正了解自己当前的水平和现有的能力,设定并真正实现切实可行的目标,并在日常工作中注意培养团队向下一个目标迈进的能力,才能一步步优化和提升。