一、概念篇
为什么要持续交付?
当前互联网变化非常迅速,在这个背景下,提升产品研发运营效率,快速发现新的机会并快速试错,降低试错成本已经变得非常重要。由此,带来几个问题:
- 如何平衡软件的质量与交付速度?
- 如何让产品创新快速交付部署,并让团队得到反馈?
我们都知道,要快速发现新机会并快速试错,就必须加快产品迭代速度,而加快迭代速度必然使得一些常规事务性占比增大,诸如测试成本,发布成本等。持续交互,即是这些问题的解决之道。
软件工程的发展历史
让我们先搁置问题本身,先来回顾软件工程的发展历史。
瀑布软件开发模型
1970年,Dr.Winston W.Rovce 首次提出瀑布软件开发模型,它将软件开发定义为多个阶段,每个阶段都有严格的输入和输出标准,很多人将这种开发方法称为“重型软件开发方法”。但这种方法会需在写第一行代码前,甲乙双方花费大量精力确定需求范围,编辑并审核软件需求说明书,即便如此,还是避免不了互相扯皮。敏捷软件开发
2001年,敏捷软件开发方法出现,敏捷方法强调发挥人的主观能动性,提倡面对面沟通,拥抱变化,通过迭代和增量开发尽早交付有价值的软件。和瀑布软件开发方法对比,敏捷能更快的看到可运行的软件,而不是到交付后期才能看到。此间,持续集成作为敏捷开发中的工程实践,率先被广泛的it组织所接受,它能减少大量重复性劳动,并排除某些沟通障碍。但敏捷方法并没有解决发布间隔长的问题,以及业务与研发团队关于需求变更和研发效率的矛盾。无论是瀑布或者敏捷开发,关注的都是如何快速将需求变为可交付的软件包。DevOps
2008年,DevOps萌芽,起初的想法是将敏捷实践应用于运维领域。DevOps概念本身也在不断的变化中,如下是曾经的定义
DevOps是一种软件工程文化和实践,旨在统一整合软件开发和软件运维。DevOps运动的主要特点是强烈倡导对构建软件的所有环节(从集成、测试、发布到部署和基础架构管理)进行全面的自动化和监控。 DevOps的目标是缩短开发周期,提高部署频率和更可靠地发布,与业务目标保持一致。
DevOps并非一个标准、一种模式或者一套固定方法,而是一种IT组织管理的发展趋势,也就是说,通过多种方式打破IT职能部门之间的隔阂,改变IT组织内部的原有合作模式,使之更紧密结合,从而促进业务迭代速度更快。这种发展趋势将会引起IT组织内部原有角色与分工的变化,甚至范围更大,会影响到相关的业务组织。对互联网公司来说,其软件产品对业务发展起到极其关键的作用,业务结果与IT效能强关联,因此顺应这一发展趋势的动力更加明显和迫切。
- 持续交付
2010年,Jez Humble 和 Dave Farley 合著了《持续交付》一书,可以称之为“持续交付1.0”。持续交付1.0提供的原则和方法是DevOps运动的具体实操指引,事实上,敏捷开发更多的是涉及产品需求方,开发工程师,测试工程师。DevOps更多的是开发、测试和运维工程师。而持续交付1.0则涉及产品需求方,研发团队,运维团队。
持续交付2.0是1.0的升级版,它将精益创业的最小化可行产品和持续交付1.0相结合,强调业务与IT间的快速闭环。
持续交付2.0核心概念与原则
概念
企业开发软件产品的目标是创造客户价值,为此,它必须不断探索发现真正要解决的业务问题,提出科学的目标,设计最小可行解决方案。通过快速实现解决方案并从真实反馈中收集数据,以验证该问题是否得以解决。这是一个从业务问题出发,到业务问题解决的完整业务闭环,简称为持续交付“8”字环。
它由两个相连的环组成:第一个环为“探索环,其主要目标是识别和定义业务问题,并制订出最小可行解决方案进入第二个环;第二个环为“验证环”,其主要目标是以最快速度交付最小可行方案,可靠地收集真实反馈,并分析和验证业务问题的解决效果,以便决定下一步行动。
探索环包含4个可持续循环步骤,分别是提问、锚定、共创和精炼。
- 提问,即定义问题。通过有针对性的提问,找出客户的具体需求,并找出具体需求后的原因,即具体需求后要解决的根本问题。在提问中形成团队期望达成的业务目标或者想要解决的业务问题。如果问题无法清晰定义,那么找到的答案自然就会有偏差。因此,在寻找答案之前,应该先清晰地定义问题。
- 锚定,即定义结果目标指示器。针对问题进行信息收集,经过分析,去除干扰信息,识别问题假设,得到适当的衡量指标项,并用其描述现在的状况,同时讨论并定义我们接下来的行动所期望的结果。
- 共创,即共同探索和创造解决或验证该问题的多种具有可行性的解决方案。
- 精炼,即对所有的可行试验方案进行选择,找到最小可行性解决方案,它既可能是单个方案,也可能是多个方案的组合。
验证环也包含4个可持续循环的步骤,分别是构建、运行、监测和决策。
- 构建,是指根据非数字化描述,将最小可行性解决方案准确地转换成符合质量要求的软件包。
- 运行,是指将达到质量要求的软件包部署到生产环境或交到用户手中,并使之为用户提供服务。
- 监测,是指收集生产系统中产生的数据,对系统进行监控,确保其正常运行。同时将业务数据以适当的形式及时呈现出来。
- 决策,是指将收集到的数据信息与探索环得出的对应目标进行对比分析,做出决策,确定下一步的方向。
探索环就像是一部车子的前轮,把握前进方向。验证环则像车子的后轮,使车子平稳且驱动快速前进。它们之间相互促进,探索环产生的可行性方案规模越小,越能够提高验证环的运转速度;如果价值验证环能够提高运转速度,则有利于探索环尽早得到真实反馈,有利于快速决策,及时对前进方向进行验证或调整。
4个核心原则
持续交付2.0可以使得企业以可持续发展的方式,在高质量、低成本及无风险的前提下,不断缩短持续交付“8”字环周期,从而与企业外部频繁互动,获得及时且真实的反馈,最终创造更多客户价值的能力。持续交付2.0有如下4个核心原则:
- 坚持少做
在咨询的过程中,最常听到的一句话就是:我们最大的问题是人力不足。”无论公司实力如何,想做的事情永远超过自己的交付能力,需求永远做不完。然而,做得多就一定有效吗?我们应该抵住“通过大量计划来构建最佳功能”的诱惑,坚持少做,想办法对新创意尽早验证。 - 持续分解问题
复杂的业务问题中一定会包含很多不确定因素,它们会影响问题解决的速度和质量。在实施解决方案之前,通过对问题的层层分解,可以让团队更了解业务,更早识别出风险。企业应该坚信,即便是很大的课题或者大范围的变更,也可以将其分解为一系列小变更,快速解决,并得到反馈,从而尽早消除风险。与其设计一大堆特性,再策划一个持续数月的一次性发布,不如持续不断地尝试新想法并各自独立发布给用户。 - 坚持快速反馈
当把问题分解以后,如果我们仍旧只是一味地埋头苦干,而忽视对每项已完成工作的结果反馈,那么就失去了由问题分解带来的另一半收益,确认风险降低或解除。只有通过快速反馈,我们才能尽早了解所完成工作的质量和效果。 - 持续改进并衡量
无论做了什么样的改进,如果无法以某种方式衡量它的结果,就无法证明真的得到了改进。在着手解决每个问题之前,我们都要找到适当的衡量方式,并将其与对应的功能需求放在同等重要的位置上,一起完成。
价值探索环
意义
探索环的目标是持续识别和定义三个有价值的假设:
- 用户假设,即我们提供的产品服务是针对某类潜在用户人群的需求的假设;
- 问题假设,即目标用户群之所以有这种需求,是因为他们的确存在某些痛点(或问题)需要解决的假设;
- 解决方案假设,即我们提供的解决方案可以解决这些痛点或问题,而且比其他现存的解决方案都有效且高效。
这3类假设中,任何一个假设不成立,都会导致我们事倍功半,甚至前尽弃。因此,我们需要选择并验证其中风险最高或最易验证的价值假设,并借助价值验证环得到数据反馈,以便深入理解用户需求,把握业务前进方向。
4个关键环节
为了达成探索环的目标,我们需要经历4个关键环节:
提问
该环节是持续交付“8”字环的起点。其目的在于通过不断地提问,澄清客户需求背后要实现的真正目标,以便找寻更多解决问题的方法,同时也有助于团队成员从业务问题出发,充分理解业务问题。锚定
“锚定”是设定目标以及目标分解的讨论过程,其目的是确定要达成的目标以及可以衡量它的指标,并能够指导后续的共创与精炼活动。对于目标的选择,应该遵循两点:一是识别价值指标,而非虚荣指标;二是指标应该可衡量且可获取,易于客观对比。共创
共创是指:当我们制订了想要达到的目标后,团队为设法验证或达成目标而找出多种可行性解决方案的过程。
共创分析方法有很多,书中列举了两个:
量化式影响地图
它是用Why-who-how-What的分析法,通过结构化的显示方式,让团队寻找达成业务目标的方法。还应该了解当前的影响程度,以及对实施后达到效果的预期。也就是,从业务问题域出发,按“角色一影响一方案一量化”的顺序进行讨论,从而尽可能多地发掘出可行性解决方案。我们可以称它为“量化式影响地图”。我们有时无法马上对所有指标进行量化。此时可临时性地收集一部分数据,并进行相应的推断,通过一段时间的运行,进行指标量化的校准即可。另一种可能是希望衡量的指标较难直接量化。此时可通过一些过程指标或相近指标来替代。需要注意的是,这两种情况都存在一定的偏差,因此在数据的应用过程中,应该格外注意。用户旅行地图
用户旅行地图(user journey map)是指以可视化方式,将用户与产品或服务之间的互动,按业务流分阶段呈现出来。
在“共创”这一环节中,需要注意两个陷阱,分别是分析瘫痪(paralysis by analysis)和直觉决策(extinct by instinct)。分析瘫痪是指因为过度分析(或过度思考)而无法决策或采取行动,最终影响结果产出的一种状态。通常是由于有太多的细节选项,或者过于寻求最佳或“完美”的解决方案,并担心做出任何可能导致错误结果的决定。而直觉决策是指不做分析,基于匆忙的判断或直觉反应而做出致命的决定。它是与分析瘫痪相反的另一个极端。
- 精炼
精炼环节就是对共创环节中得出的众多方案进行评估,从中筛选出团队认为最小可行性解决方案的过程。评估因素包括备选方案的实施成本、时间与人力、效果反馈周期,以及该方案对业务目标的影响程度。在VUCA环境中,时间是最大的隐形成本。精炼的目标并不是为了删除在共创阶段得出的解决方案,而是将它们按优先级排列,并让团队将解决方案进一步分解,顺序选出共同认可的最重要改进项,并确保它能够尽早被验证。
工作原则
在探索环的工作中应该遵循“分解并快速试错”“一次只验证一点”“允许失败”原则。
分解并快速试错
“一次到位式”解决方案通常需要较高的实施成本,而其带来的实际效果具有较高的不确定性。由于前期投入的成本较高(即沉没成本),一旦这个解决方案未能带来预期效果,团队不愿意放弃这一方案,决策者通常选择保留它,或者仍会持续优化,使其慢慢“死去”,而这会带来不必要的产品复杂度和维护成本。一次只验证一点
一次只验证一个需求假设。在执行整个试验方案过程中,我们仍旧要保持开放心态,不断优化这些试验方案。时刻提醒自己,我们的目标是验证我们的假设,试验方案只是我们验证假设的手段,而不是我们的目标。允许失败
尽管每个产品经理都希望所有方案都获得成功,但是我们却无法保证每个方案都会获得成功。但是,只要具有开放的心态,我们就可以从所有方案中都学到很多新的知识。
共创与精炼的常用方法
关于共创与精炼,书中花了大量篇幅介绍了6个常用方法,这里我只简单介绍2个。
装饰窗方法
所谓装饰窗方法(Decorative Window),就是指为新功能预留一个“入口”,让用户能够看到,但实际上并没有真正实现其功能。这是一种了解用户喜好的方法,其目的是利用最小成本,来验证用户是否喜欢某个功能,以及其紧迫程度,为是否研发后续更全面的解决方案提供数据支持。最小可行特性法
最小可行特性法(Minimum Viable Feature)是指在产品从1到n的过程中,寻找用户可直接感知到的需求假设作为产品的最小可行特性优先开发的方法,以尽可能少的成本快速增加或修改某个产品特性,让用户使用,收集真实反馈,专注于验证功能改进,同时也可提升用户使用体验。
快速验证环
当我们通过“探索环”对最小可行方案达成共识以后,要借助“验证环”的快速运转,才能将其交付到用户(客户)手中,从而得到真实且可靠的反馈,以验证之。快速验证环的运转速度由两部分决定:一是探索环中得出的最小可行性解决方案的大小和复杂性;二是验证环自身运转的速度。
验证环的目标
进入验证环的基本前提是“团队已达成共识,所选的方式是当前所处环境下,验证或解决业务领域问题的最佳方式“。验证环的目标就是借助各种方法与工具,让质量可靠的解决方案以最快的速度到达客户手中,从而收集并分析真实的反馈。
质量与速度是验证环的关键,它们却常常被认为是互斥的。然而, Puppet LabsDev发布的2017年DevOps现状调查报告结果显示,与低绩效IT组织相比,高绩效IT组织可以同时实现这两个目标,也就是说,发布质量好而且频率高。持续交付1.0在这方面发挥了巨大作用,如质量内建、小批量交付、自动化一切重复工作等。
验证环的4个关键环节
验证环的主要工作内容就是以最可靠的质量和最快的速度,将最小可行性解决方案从描述性语言转换成可运行的软件包,并将其部署到生产环境中运行,准确收集相关数据并
呈现,以便团队根据相关数据做出判断和决策。与探索环一样,它也包含4个环节,分别是构建、运行、监测和决策。
构建
构建环节是将自然语言的描述转换成计算机可执行的软件,即“质量达标的软件包”。这一环节既要求相关人员能对业务问题及试验方案达成共识,又要求能够准确地将团队的意图转换成最终仅由0和1组成的数字程序。这一环节的参与角色最多,尤其当开发一个新产品或者产品有重大变更的时候,参与角色如业务人员、产品经理、开发工程师和测试工程师,以及运维工程师。每个角色的背景知识和技能优势各不相同,如何快速将人们头脑中的解决方案变成可以运行的高质量软件包,一直是软件工程领域的一个难题。这是验证环内不确定因素最多的一个环节。时间盒管理、工作任务分解和持续验证是应对这种不确定性的好方法。运行
将达到质量要求的软件包部署到生产环境或交到用户手中,并使之为用户提供服务。监测
监测环节收集数据,并统计展现结果、及时发现生产系统问题以及业务指标的异常波动,并做出适当的反应。它也是团队做出决策的最重要数据源之一。团队必须在验证环一开始就讨论并确定验证所需的数据需求,尽早讨论并定义数据需求规范制订日志记录标准,建立数据日志元数据,并与相对应的功能需求一并同时实现。决策
决策是指收到真实的业务数据反馈结果后,根据探索环中已确定的相应衡量指标进行对比分析,从而验证是否符合最初的预期。下一步行动既可能是从精炼环节的最小可行方案列表中选择下一个试验方案,也可能是返回到持续交付“8”字环的起点,开始新问题的探索。
工作原则
验证环的工作原则主要包括质量内建、消除等待、尽量并行、监测一切。
二、组织机制
组织机制是一个复杂课题,书中仅仅讨论持续交付所需的文化,以及建立文化的四步法。关于组织架构、人才结构、激励机制等内容被略去,不得不说是一个遗憾,当然我想更多的是篇幅所限,不得已而为之。
组织文化塑造四步法
书中列举了几个企业组织的四步法,但大同小异,这里我以谷歌工程师的质量文化为例,
- 第一步:定义想要做的事情
- 提高代码质量,减少生产问题,减少手工测试工作量,快速发布软件。
- 第二步:定义期望的做事方法
- 开发团队编写自动化测试。
- 主动运行自动化测试用例。
- 做代码评审。
- 第三步:提供相应的培训
- 在公司范围内组织代码设计与自动化测试培训。
- 为每个团队指派自动化测试教练,帮助团队提高自动化测试技能。
- 第四步:做些必需的事情来强化那些行为
- 建立团队测试认证机制(test certified mechanism),共分3个大级别,12个子级,用于评估每个软件产品团队的测试成熟度。通过每个季度统计各级别上的团队数量分布,来评估自动化测试文化在公司内部的进展程度。
- 建立自动化测试组( test group)和测试教练组(test mentor),帮助团队提升自动化测试能力。
- 建立代码评审资质证书。
- 代码合入版本仓库之前强制做代码评审。
- 代码评审之前,必须运行自动化测试用例,并提交报告给代码评审者。
当然,这4步并不是非常容易的,谷歌的执行过程也花费了4年的时间,其中还有很多非常具体的细节,书中并没有展开讨论。
行动原则
行动原则有3个,分别是“价值导向,快速验证,持续学习”。
价值导向
所有人都会一致同意,“我们做事情时,应该价值导向”。然而,这却是在工作中经常被忽视的一点,也是最难判断的一点。因为我们每天有太多的事情要做。为了能够早一点儿完成所有任务,我们常常忘记思考完成这些任务的最终目的,以及它与目标之间的关系。为了能够做出正确的判断我们应该时常强迫自己停下来,花一些时间,认真思考一下我们手头上正在做的事情是否仍旧具有价值,是否仍旧最有价值。之所以难以判断,是由于组织中每个人的背景与经历各不相同,对外部市场环境的感知也各不相同,对于同一个工作场所带来的价值感也会有所不同。因此,当我们讨论“价值”时,应该限定于一定的业务上下文,避免离题太远。同时,在讨论时应该尽量提供完整的上下文,并聆听他人的方案与建议。
即便进行了充分的沟通与讨论,面对同一个问题的多种解决方案,我们可能也无法达成一致意见。此时,我们可以采用行动原则的第二原则,即“快速验证”。
快速验证
在高度不确定的环境中,并不是所有的方案都能很容易提前对其价值进行准确判断因此我们需要快速验证。通过快速实施,得到真实反馈,从而做出决策。在一个安全的工作环境中,只要我们能够主动拥抱“快速验证”原则,充分发挥员工的主观能动性,就可以找到很多快速试验方案。
对于与组织管理相关的改进,也可以使用快速验证方式。例如,针对具体问题,选择不同的试点团队进行快速实施,根据团队实际运行效果进行调优、验证。
持续学习
我们无法保证每个决策都是正确的。团队应当将每一次反馈作为一次学习的机会,结合从中学习到的新知识,总结成功经验或失败教训。除了通过业务试验产生的业务结果对业务领域进行深入了解和学习,还要保持对做事过程的学习与反思,不断优化工作流程,提升各环节的效率。
对于团队日常工作过程的学习与反思,有两种常见的方式,一是定期回顾,二是事件复盘机制。
关于持续学习,我认为是比较重要的,所以我重点介绍下持续学习。
定期回顾
定期回顾是指每隔一定周期,团队主动安排一次会议,共同讨论在过去的这个周期内,团队在协作过程中的优点与不足,并讨论相应的对策,以便在后续的工作中能够保持优点,改进不足,持续取得进步。回顾会议结束后,应该有改进措施与计划,并能够跟踪执行结果。同时,不要制订过多的改进项,以免落入“反复提出,反复执行,没有实际进展”的境况。
复盘机制
复盘机制通常是指针对发生的问题进行分析,其目的是避免相同问题重复出现。首先要针对问题发生的前后进行信息收集与整理确定问题的严重程度,理解问题发生的过程(对于疑难问题,可能还需要在事故后进行线下模拟测试,甚至线上测试,以复现问题和寻找原因)。然后进行根因分析,最后总结经验,制订改进措施与计划,并能够跟踪执行结果。对于根本原因分析,需要注意以下几点。
- 放松心态,开放共享。
- 分清“因”和“果”。
- 五问法,鼓励多问“为什么”。
- 发挥群体智慧。
- 不要停于表面,而要寻找深层次原因。
- 对答案进行求证。
对于每一次复盘,都应该详细记录和总结,作为知识在企业中全员共享。只有这样,才能收益最大化。
在以上两种学习方式中,都应该运用“系统思考”方法。简单来说,就是对事情全面思考,不能仅是就事论事,而是把想要获得的结果、实现该结果的过程、过程优化以及对未来的影响等一系列问题作为一个整体系统进行研究。在传统的思维模式中,人们假设因与果之间是线性作用的,即“因”产生“果”;但在系统思考中,因与果并不是绝对的,因与果之间有可能是环形互动的,即“因”产生“果”,此“果”又成为他“果”之“因”,甚至成为“因”之“因”。
度量原则
作为管理者,如果无法度量,很显然你也无法有效率的进行改进。所以,我们也必须有度量原则。度量指标可以分为4类属性,分别是引领性指标、滞后性指标、可观测性指标和可行动性指标。
- 引领性指标与滞后性指标
引领性指标是指那些对达成预定目标有着重要作用的指标。通常,一个好的引领性指标有以下两个基本特点:第一,它具有预见性;第二,团队成员可以影响这些指标。
滞后性指标是指那些为了达成最重要目标的跟踪性指标,如销售收入、利润率、市场份额、客户满意度等研究分析都属于滞后性指标。当你得到这些结果的时候,导致这些结果的事情早已结束,你得到的都是历史性结果数据。
例如,在其他因素相同的情况下,假如软件质量与性能越好,则软件的市场竞争力越强,客户就越愿意为之买单,软件销售量就会越高。对于软件销售这件事情,软件销售量就是一个滞后性指标,而软件质量与性能就是一个引领性指标。我们可以通过优化软件性能,提升软件质量来影响软件销售量,但无法确保一定达成软件销售量这一滞后性指标。
企业的终极后验性指标是客户价值,相对于这一滞后性指标来说,其他指标均可认为是引领性指标。
- 可观测性指标与可行动性指标
可观测性指标是指可以被客观监测到,但无法通过直接行动来改变的指标。可行动性指标是指在能力可触达范围内,通过团队努力可以设法直接改变的指标。
例如,千行代码缺陷率就是一种可观测性指标。我们无法以非常直接的方式来改变它,只能通过更全面的质量保障活动(写出高质量的代码、做更加完整的测试等活动)来影响这一指标。
代码规范符合度、代码圈复杂度、重复代码率则既是可观测性指标,也是可行动性指标,因为团队可以直接通过修改代码来直接影响和改变这些指标,但无法确保一定达成“千行代码缺陷率”这一后验性可观测性指标。
“DevOps状态报告2017”指出,衡量IT高绩效组织的4个度量项分别是发布频率、发布周期、MTBF/MTTR、吞吐量。其中,发布频率是指软件部署并运行于生产环境的频率,例如, Facebook手机App每周发布一次。该报告中的发布周期是指从代码提交到发布之间的时间周期。MTBF,全称是 Mean Time Between Failure,即平均失效间隔。就是新的产品在规定的工作环境条件下从开始工作到出现第一个故障的时间的平均值。MTTR的全称是 Mean Time To Repair,即平均恢复时间,指从故障出现到恢复之间的时间周期。吞吐量是指在给定时间段内系统完成的交付物数量。
假如将上述4个度量项作为滞后性指标的话,那么编译速度、测试时长、部署效率等指标则可能是达成这些目标的引领性指标。我们可以推断,从滞后性指标出发,一级一级地向前推导,可以发现很多可行动性的引领性指标。需要注意的是,指标之间的关联影响可能还存在时间延迟效应,即对某一个度量指标的改善,需要经过一段时间,才能在其关联度量指标上有所体现。并且,指标链条越长,可预测性就越低。
三、软件架构
持续交付架构的要求
为了提升交互速度,获得持续交付能力,我们会需要对系统架构做一些调整。书中对系统架构做了一些要求,要求如下:
- 为测试而设计(design for test)。如果我们每次写好代码以后,需要花费很大的精力,做很多的准备工作才能对它进行测试的话,那么从写好代码到完成质量验证就需要很
长周期,当然无法快速发布。 - 为部署而设计(design for deployment)如果我们开发完新功能,当部署发布时,需要花费很长时间准备,甚至需要停机才能部署,当然就无法快速发布。
- 为监控而设计(design for monitor)。如果我们的功能上线以后,无法对其进行监控,出了问题只能通过用户反馈才发现。那么,持续交付的收益就会大幅降低了。
- 为扩展而设计(design for scale)。这里的扩展性指两个方面,一是支持团队成员规模的扩展;二是支持系统自身的扩展。
- 为失效而设计(design for failure)俗语说“常在河边走,哪能不湿鞋。”快速地部署发布总会遇到问题。因此,在开发软件功能之前,就应该考虑的一个问题是:一旦部署或发布失败,如何优雅且快速地处理。
系统拆分原则
根据目前软件的发展趋势,以及持续交付的要求,对系统进行拆分有以下几个原则。
- 作为系统的一部分,每个组件或服务有清晰的业务职责,可以被独立修改,甚至被另一种实现方案所替代。
- “高内聚、低耦合”,使整个系统易于维护,每个组件或服务只知道尽可能少的信息,完成相对独立的单一功能。
- 整个系统易于构建与测试。将系统拆分后这些组件仍需要组合在一起,为用户提供服务。
- 使团队成员之间的沟通协作更加顺畅。
常见架构模式
微核架构
微核架构(microcore architecture)又称为插件架构(plugin architecture),指的是软件的核心框架相对较小,而其主要业务功能和业务逻辑都通过插件实现,如图所示。核心框架部分通常只包含系统启动运行的基础功能,例如基础通信模块、基本渲染功能和界面整体框架等。插件则是互相独立的,插件之间的通信只通过核心框架进行,避免出现互相依赖的问题。
这种架构方式的优点有以下几个:
- 良好的功能延伸性(extensibility):需要什么功能,开发一个插件即可。
- 易发布:插件可以独立地加载和卸载,使它比较容易发布。
- 易测试:功能之间是隔离的,可以对插件进行隔离测试。
- 可定制性高:适应不同的开发需要。
- 可以渐进式地开发:逐步增加功能。
当然,它也有不足,具体有以下几点:
- 扩展性(scalability)差,内核通常是一个独立单元,不容易做成分布式,但对客户端软件来说,这就不是一个严重问题。
- 开发难度相对较高,因为涉及插件与内核的通信以及内部的插件登记机制等,比较复杂。
- 高度依赖框架,既享受框架带来的方便性,当框架接口升级时又可能会影响所有插件,导致大量的改造工作。
微服务架构
微服务架构(microservice architecture)是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP协议的 RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。
这种软件架构的优点有以下几个。
- 扩展性好——各个服务之间低耦合。可以对其中的个别服务单独扩容,如图所示的D服务。
- 易部署——每个服务都是可部署单元。
- 易开发每个组件都可以进行单独开发,单独部署,不间断地升级。
- 易于单独测试——如果修改只涉及单一服务,那么只测试该服务即可。
但是,它也有不足,具体有以下几点。
- 由于强调互相独立和低耦合,服务可能会被拆分得很细。这导致系统依赖大量的微服务,变得很凌乱和笨重,网络通信消耗也会比较大。
- 一次外部请求会涉及内部多个服务之间的通信,使得问题的调试与诊断比较困难,需要更强大的工具支持。
- 为原子操作带来困难,例如需要事务类操作的场景。
- 跨服务的组合业务场景的测试比较困难,通常需要同时部署和启动多个微服务。公共类库的升级管理比较难。在使用有一些公共的工具性质的类库时,需要在构建每个微服务时都将其打包到部署包中。
在使用微服务架构模式时,除确保每个服务一定要能够独立部署之外,还要确保在部署升级时不影响其下游服务(例如通过支持API的多版本兼容方式),同时建立全面的微服务监测体系。
巨石应用
巨石应用(monolithic application)也称巨石架构,是指由单一结构体组成的软件应用,其用户接口和数据访问代码都绑定在同一语言平台的同一应用程序。这种巨石架构应用通常表现为一个完整的包,如一个Jar包或者一个Node.js或 Rails的完整目录结构。只要有了这个包,就什么都有了。
组织良好的巨石架构同样也有其优势,包括以下几个。
- 利于开发和调试:当前所有开发工具和IDE都很好地支持了巨石应用程序的开发。系统架构简单,调试方便。
- 部署操作本身比较简单:例如,只需要有运行时所需部署的一个WAR文件(或目录层次结构)即可。
- 很容易扩展:只要在负载均衡器后面运行这个应用的多个副本就可以扩展应用程序。
它的劣势有以下几个。
- 对整体程序不熟悉的人来说,容易产生混乱的代码,污染整个应用,给老代码的学习和理解带来困难。
- 难与新技术共同使用。
- 只能将整个应用作为一个整体进行扩展。
- 持续部署非常困难。为了更新一个组件,必须重新部署整个应用程序。
架构改造实施模式
通常,这类改造有3种实施模式,分别是拆迁者模式、绞杀者模式和修缮者模式。其中,绞杀者模式和修缮者模式都有利于持续交付,降低架构改造和发布的风险。
拆迁者模式
“拆迁者模式”就是指根据当前的业务需求,对软件架构重新设计,并组织单独的团队,重新开发一个全新的版本,一次性完全替代原有的遗留系统,如图所示。
这种方式的好处在于,它与旧版本没有瓜葛,没有历史包袱,可以按预期进行架构设计。但是,这种模式的风险包括以下几个方面。
- 业务需求遗漏。软件的历史版本中,有很多不为人熟知的功能还在使用。
- 市场环境变化。由于新版本架构无法一蹴而就,当市场需求发生变化时,就会错失市场良机。
- 人力资源消耗大。必须分出人力,一边维护旧版本的功能或紧急需求,一边要安排充分人力进行架构改造。
- “闭门造车”。新版本上线后,无法满足业务需求。
绞杀者模式
“绞杀者模式”是指保持原来的遗留系统不变,当需要开发新的功能时,重新开发一个服务,实现新的功能。通过不断构建新的服务,逐步使遗留系统失效,并最终替代它,如图所示。
这种方式的好处在于:
- 不会遗漏原有需求;
- 可以稳定地提供价值,频繁地交付版本,可以让你更好地监控其改造进展;
- 避免“闭门造车”现象。
其劣势在于:
- 架构改造的时间跨度会变大;
- 产生一定的迭代成本。
修缮者模式
“修缮者模式”是指将遗留系统的部分功能与其余部分隔离,以新的架构进行单独改善。
其收益包括:
- 系统外部无感知;
- 不会遗漏原有需求;
- 可以随时停下改造工作,响应高优先级的业务需求;
- 避免“闭门造车”现象。
而其劣势在于:
- 架构改造的时间跨度会变大;
- 会有更多额外的架构改造迭代成本。
数据库的拆分方法
一般来说,关系型数据库很可能是巨石应用中的最大耦合点.因此,对于有状态微服务的改造,我们需要非常小心地处理数据库数据做数据库拆分时,我们应该遵循以下步骤,如图所示。
- 详细了解数据库结构,包括外键约束、共享的可变数据以及事务性边界等,如图a所示。
- 先拆分数据库,并按照12.3.2节的介绍进行数据迁移,如图b所示。
- 数据库双写无误后,找到程序架构中的缝隙,如图c所示。
- 将拆分出来的程序模块和数据库组合在一起,形成微服务,如图d所示。
四、基础设施
前三个章节介绍了持续交付的概念,实施持续交付三大板块中的组织机制和软件架构,而最后一个板块则是基础设施。基础设施部分是产品研发过程中最基础的工作。
这部分涵盖持续交付部署流水线及其工具设计原则,以及建立该流水线和优化所需关注的五大领域,分别是,业务需求协作流程、分支与配置管理、构建与环境管理、自动化测试管理,以及部署发布与监控管理。这部分内容相当细节,我并不想在此展开。此外,此部分和目前流行的DevOps有大量共同的内容。
部署流水线
为实现“谁构建,谁运营”,企业对于DevOps工具的建设,应该坚决从开发工程师的工作场景出发,为其构建强大的DevOps工具。不仅是生产环境的运维工具,而且是整个工作流程中的业务软件监控工程基础设施,它包括:
- 基础的研发流程自助平台,如各类运行环境(构建、测试、生产)的自助平台;
- 数据自助平台(包括三层监测数据);
- 用于业务快速试错的实验测量平台;
- 针对移动设备,建立用户触达平台。
关于部署流水线,书中介绍了团队设计和使用部署流水线的原则,以及企业定制开发私有部署流水线工具链的设计要点和工具平台的能力要求。同时,还对四大基础支撑服务(编译构建服务、自动化测试服务、部署管理服务及基础环境服务)的逻辑组件进行了简要介绍。同时,还介绍了三大受信源(需求管理仓库、源代码仓库和制品库)之间的关联关系,以及对它们的管理要求。书中列举了几个不同的产品场景以及相应的部署流水线设计方案。
要想让部署流水线发挥最大的作用,研发团队需要尽可能遵守以下5条原则。
- 任何软件包的取用皆须通过受控源,各角色之间禁止通过私有渠道(如电子邮件、即时通信工具等)获取。
- 尽可能将一切流程自动化,并持续优化执行时间。
- 每次提交都能够自动触发部署流水线。
- 尽可能地少用手动触发方式。
- 必须执行立即暂停原则(stop the line)
业务需求协作管理
业务需求协作管理一章具体阐述了产品版本周期准备期、交付期的重点内容,以及需求拆分带来的收益与随之而来的固定成本。如果无法降低这些固定成本,那么很难收获更大的价值。为了能够真正获得拆分带来的收益,在做需求拆分时就要尽可能遵守 INVEST原则(INV<EST)为了帮助读者更好地掌握拆分技术。书中总结了五大拆分技法,以及每个用户故事应该包含的7个组成部分。需求分析与管理的方法与工具有很多,用户故事地图、用户故事树和依赖关系图是较为常见的需求梳理工具。另外,书中还介绍了迭代过程中提高团队协作的工具与方法,包括共享时间表、回顾会议、持续集成和故事验证。
分支与配置管理
关于版本控制系统,如果不是有能力自定义自己代码仓库功能特性的大厂,个人强烈建议使用git,可以节省很多不必要的时间。如果还在使用svn等传统工具的团队,应尽快迁移到git中,git有提供非常方便的工具,方便svn用户做迁移,提交记录等信息都能比较好的迁移到git中。关于分支与配置管理,书中分析了各种分支策略的优点和挑战。目前的发展趋势是:软件发布频率越来越高,发布周期越来越短。硅谷顶级互联网公司多采用“主干开发”或高频的 GitHubFlow分支模式。一个企业到底选择哪种分支策略,需要根据团队的具体情况来决定。如果相关的配套条件(如软件架构、人员能力和工具平台的成熟度)不足,那么,盲目提高发布频率、缩短发布周期会造成不必要的损失。
“持续交付2.0”提倡鼓励持续集成的分支策略,因此,选择分支模式的原则有以下几条。
- 分支越少越好,最好只有一条主干。
- 分支生存周期越短越好,最好在3天以内。
- 在业务允许的前提下,发布周期越短越好。
持续集成
本书还花了一章的篇幅讲述了持续集成的起源,团队实施持续集成的原则,介绍了持续集成6步提交法,以及快速建立团队持续集成实践的5个步骤。
需要注意的是,并不是安装部署了一个持续集成服务器,每天用它进行自动化编译打包,就说明团队正在使用持续集成实践。要真正做到持续集成,获得最大的持续集成收益,需要做到以下6点:
- 主干开发,频率提交代码。
- 每次提交都是完整有意义的工作。
- 提交构建阶段在10分钟之内完成。
- 提交构建失败后,立即修复;且其他人不得在修复之前提交代码。
- 应该在10分钟内修复失败,否则回滚引起失败的代码。
- 自动化构建成功后,团队对软件质量比较有信心。
自动化测试
对交付频率的要求越高,希望前置周期越短,自动化测试就越为重要。书中阐述了软件快速交付对自动化测试的4项基本要求,即快速、便捷、可信和及时。为了能够做到这4点,需要以分层的自动化测试金字塔为指导合理设计自动化测试的实施策略,从而增加自动化测试的收益。对自动化测试的实践管理来说,有5条重要原则:
- 自动化测试用例运行次数越多,平均成本越低,收益就越大。
- 自动化测试用例之间应该尽可能相互独立,互不影响。
- 在质量有保障的前提下,自动化测试用例的数量越少越好。
- 遗留代码的自动化测试编写应该从代码热区开始。
- 自动化测试用例从测试金字塔的中间层开始补充,投入产出比最高。
软件配置管理
良好的软件配置管理是打造持续交付部署流水线、加速持续验证环的基础支撑。
本书讨论了软件配置管理的3个核心原则。
- 对一切进行版本管理。
- 共享唯一受信源。
- 标准化与自动化。
可以用下面5个问题来验证检查你是否对一切都做了版本管理。
- 产品源代码和测试代码是否放入了版本控制系统。
- 软件应用的配置信息是否放入了版本控制系统。
- 各类环境的系统配置是否放入了版本控制系统。
- 自动化的构建和部署脚本是否放入了版本控制系统。
- 软件包是否进行了版本管理。
另外,也可以用下面两个问题来检查软件配置管理是否做得足够好。
- 只要从源代码仓库中检出产品源代码仓库,就可以一键式自动化地构建出完整软件包吗?
- 在没有他人的帮助下,任何团队成员都可以一键式自动化搭建出一套应用软件系统,用于体验产品新功能吗?
低风险发布
本节讨论了如何在快速部署发布的情况下通过多种技术手段降低风险,如开关技术、数据库迁移技术、蓝绿部署、金丝雀(灰度)发布、抽象分支以及暗部署等。并且强调,即便没有使用开关,假如团队能够一直使用“小步完整的代码提交”策略,也可以比较容易地做到将缺陷快速回滚。
在一些业务场景下,我们的确无法直接高频地对外发布软件。但是,如果我们能够使用本章介绍的方法持续向预生产环境进行发布与部署,就可以尽早获得软件的相关质量反馈,从而减少正式发布后的风险。如果我们能够将每次发布的平均成本降低到足够低,那么将会直接改变团队的产品研发流程。
监测与决策
生产环境的监测范围包括3个层次,它们分别是“基础监测”“应用监测”和“业务监测“。尽管根据每一层次的特点,监测数据的采集方式有所不同,但是其处理流程基本一致。每个监测体系都包括数据收集、上报、整理、分析、展现与决策这几个环节。而对监测系统能力的衡量有3个维度,即数据的准确性、全面性与及时性。而抽样能力是提高监测灵活性、节约资源、提升用户体验的一种有效方法。
告警处理是研发人员和运维人员的常规工作但是,如果告警过多也会成为工作中的困扰,降低工作产出。因此,我们应该不断对告警点的设置与阈值计算方式进行优化,从而尽可能提升有效告警率。一旦告警成立,就需要启动问题处理流程。这个流程的最后两个环节“根因分析”和“根源解决”,是学习型组织的重要特征。
随着发布频率的提高,测试场景的复杂性提高,越来越多的团队开始找寻方法在生产环境上进行软件测试,这被称为测试活动右移。这种右移目前多发生于展示性软件,这类软件出错后的成本和影响相对较少。而对那些交易性软件或回收成本较高的软件来说,测试左移的趋势也比较明显。
右移的测试主要有两种类型。一是将测试用例在生产环境上自动运行。二是混沌工程,即通过注入“问题”,发现生产环境的潜在稳定性问题。 Netflix公司开发了一系列破坏性测试工具(Simian Army)可以促使工程师在软件设计与开发之时,就提前考虑各种失败的可能性,这被称为“为失败而设计(Design for Failure),从而提高生产环境的软件服务稳定性,为用户提供更好的服务体验。
当收集到真实的数据反馈以后,我们就可以用来印证我们在价值探索环中所提出的假设或目标,并通过主动关联分析,最终确定是继续进行更多的试验,还是重新再选择一条新的“路”。
后续章节
后续三个章节主要是实战案例的分析,分别代表不同类型的公司、不同大小的团队以及不同的软件产品特点。本书作者带领读者深入案例现场,了解当时状况,分析问题,并提出解决思路。由于是案例解析,此次不再摘录要点。