如何构建高效的持续交付能力
持续集成、持续交付、持续部署、以及持续发布,到底是什么含义?
在回答之前,请大家先思考一个问题 :什么是交付过程最痛苦的事情?
集成的过程,测试的过程,以及部署与发布,都很痛苦,否则不会有敏捷与DevOps的各种方法与实践来解决这些问题,但是这些过程又都非常重要。
就此问题,引用《极限编程》里面的四句话来回答:
- 如果集成是重要的(集成的目的在于测试),那么我们将在一天中多次集成并测试。
- 如果测试是好的,那么所有人都应该始终进行测试。
- 如果设计是好的,那么我们应该把它当做日常事务的一部分。
- 如果迭代短些好,那么我们将使迭代时间非常短,秒、分钟或小时,而不是周、月或年。
因此,给出的对策是:如果一件事非常重要,那么我们就把它做到最好。
频繁地沟通
我们来解读第一句话:“如果集成是重要的(集成的目的在于测试),那么我们将在一天中多次集成并测试。”
代码交付是一种沟通,代码的交付过程事实上是开发人员之间的沟通:“我修改了什么代码,是为了什么,你们谁帮我review一下,谁也在改同样的文件,谁merge一下。”
来源:Jez Humble - continuous delivery
从沟通的角度上来说,当然是越频繁越好,那么自然是下面这张图会更适合,而这张图,就是持续集成的场景。
软件版本管理
软件版本管理,即SCM,为什么前所未有的受到重视?
每个公司通常会有一个Build Manager的角色,他不是manager,他管的是代码库、分支策略以及编译构建服务器。
版本管理的目的是版本控制,回溯历史信息;帮助团队之间进行协作,跨团队,甚至跨时区、跨国家;研发过程的管理,包括变更、审批以及相关的流程等,以及问题发生后的追踪。简单而言,就是为了回答,如何重现一个环境:到底是谁,在什么时候,修改了什么,是为了什么。从版本分支的管理,看到的是软件的发布机制,这是持续交付的核心。
此外,发布的过程,也是开发与运维之间的协同与沟通,这正是DevOps试图解决的问题。
版本管理的目标:为了确保即使是在发生灾难性事件的时候,也可以重复且精确的、最好还能快速的,恢复生产环境。那么所有为了达成这一目标的资源,都应该纳入版本控制系统。
- CodeArts软件版本管理
为了将所有资源纳入版本控制系统中,在CodeArts上提供了代码托管、软件发布库、私有依赖库等功能。
- 代码托管服务基于Git,项目的开发代码可以上传至CodeArts进行代码托管,统一管理。
- 软件发布库可用来存储构建好的软件包,实现软件包版本管理,提升发布质量和效率,实现产品的持续发布。
- 私有依赖库可用于将项目当中的依赖包上传至此库中,以方便云端构建,并进行版本控制,避免环境差异化。
分支策略
不论是主干开发模式,还是Git Flow、Github Flow、Gitlab Flow,事实上背后都是研发与交付的模式体现。选择哪种分支策略,与团队的能力成熟度,与自身的业务模式,与客户的管控要求,都息息相关。
下图中,左边是2006年写成的持续集成的原则,直到今天,这些原则都依然适用,而且绝大多数企业和团队都没有做到。右边是持续交付一书中列出的持续集成必选的实践,同样的经典。
需要注意的是,我们不只是要关注这些原则和实践本身,更重要的,是关注它们背后之间的关联。
持续测试
第二句话来了:如果测试是好的,那么所有人都应该始终进行测试。这句话,我们今天叫做持续测试。
今天测试人员感觉到前所未有的危机感。
以前,测试人员归属于QA部门。从这个角度来说,只要是归属于质量保障的范围,都可视为测试人员的职责范围。
如今,有几条有关有效质量控制的建议:
- 让听得到炮声的人做出决策,而不是远离一线的管理者。
- Build Quality In,所有人都有责。
- 测试与架构相关,包括技术架构,以及组织架构。
- 测试的过程,是从失败中学习的过程。
- 自动化,自动化,自动化,尽可能的自动化一切该自动化的,但又不要过度的依赖于自动化,不要过度追求自动化。
下图是测试金字塔,核心是从关注测试的数量转向关注测试的质量。尤其是在持续集成之下,测试执行要求是快速闭环的。越往下的,隔离性越高,定位问题就越容易,反馈也会越快,因此应该要发现更多的问题,投入更多的精力;越往上的,反馈周期越长,运行效率越低,修复和维护的成本都很高,复杂性也随之升高,应该做的频度越少。
事实上,我们有双层的金字塔结构,上面是线上环境的测试,包括拨测、捣乱猴子测试,以及各类的性能和安全测试。
刚才说应该测试前移,投入更多的在短周期的活动;同时又说,测试要延展到生产环境,覆盖发布和线上的运行阶段。事实上,测试应该向两端延展,测试活动应该是真正贯穿在整个产品生命周期的。从这点上来讲,测试人员如果还是用原先的方法和手段,是无法处理好问题的。
那么,缺陷成本是越来越大么?我们所有的教育都告诉我们是的,包括说要从源头来保障质量,缺陷随着时间的推移,修复的成本越高;变化的成本随时间的推移而以指数级上升。但同时,敏捷又说要拥抱变化,精益建议要推迟决策,这是不是矛盾呢?
《DevOps软件架构师行动指南》中提出,问题不在于变化,因为变化总是要发生的;问题在于发生变化时,是否有能力来应对。
决定是否易于修改的因素有:
- 简单的设计,这也是极限编程的建议。
- 松耦合的架构,频繁并主动的修改设计。
- 锻炼组织的工程能力。
- 以及构筑快速反馈、快速应对变化的能力。
测试是越多越好么?自动化测试呢?
- 处于探索阶段的产品,不确定性极高,此时投入过多精力去搞测试,一味地追求测试覆盖率等指标,最后发现市场方向不对,要推翻重做,那么前面投入的测试就全是浪费,此时应该以手工测试为主。
- 当发现市场正确,快速投入人力和物力,此刻需要的是产品的快速增长,需要开始引入关键的自动化测试来保障效率和质量。
- 到产品稳定阶段,自动化测试的目的是回归,保障质量的稳定。
那么问题又来了,测试能防范所有的问题么?当然不能,这里有两种安全,一种是试图发现尽可能多的,甚至是消除错误的部分,达到绝对的安全,这过于理想,不可实现;所以我们推荐的是第二种,弹性安全,尤其是适用于云化的场景,即便是发生了错误,我们需要追求的是快速恢复的能力。
- CodeArts测试管理
为了对测试用例等进行可回溯的统一管理,我们需要用到测试用例管理工具。
在CodeArts中,测试管理支持手工测试和接口测试。很好的帮我们解决了这一问题。
- 接口测试可以自动化集成到流水线当中。
- 所有的测试用例都可以关联到工作项当中。
架构解耦、团队解耦
第三句话:如果设计是好的,那么我们应该把它当做日常事务的一部分。
架构做的不好,留下的是技术债务。技术债务都是不好的么?当然也不是。
技术债务如同3X曲线,在早期应该有意识的去背负一些债务,来换取时间窗口,来撬动杠杆。当然这个应该是有意而为之的事情,不是懵懂无知的。随后,需要将偿还技术债务的活动,制度化,常规化。
为了持续集成、持续测试的进行,需要进行架构解耦。除了技术架构层面的,当然还有组织架构。从功能型组织,竖井的工作模式,部门墙林立,变为产品型的组织,每个产品或服务作为独立的利润中心,阿米巴模式。
康威定律说组织架构与技术架构相互对应,《赋能》里面提到的分布式的小型团队,事实上是进一步的去中心化,甚至都没有稳定的小团队。
持续交付
最后一句话:如果迭代短些好,那么我们将使迭代时间非常短,秒、分钟或小时,而不是周、月或年。
如果做到这一点,事实上就是持续交付。
持续集成、持续交付、持续部署,还是傻傻分不清楚?
持续交付是指团队确保每个变更可以部署至生产环境,但也许并不需要实际部署,通常是出于业务方面的原因。
所以核心是技术决策,与业务决策的分离。持续部署,是一个技术行为,持续交付是业务行为,交付的是业务价值。是否需要持续的部署到生产环境,是由业务形态决定的,而技术层面,反而是一蹴而就的事情。
进一步的,甚至部署到了生产环境,也可以不意味着正式发布。通过技术手段,我们可以将部署与发布解耦,通过特性开关、灰度上线等技术手段,可以赋能业务进行A/B测试,灰度发布等业务行为,这是技术赋能业务的最典型场景,也是最有力的支撑。
最终,持续交付归结为一句话,痛苦的事情反复做。
下图所示的持续交付的原则中,红体字描述的,是最与技术无关的一个实践,却也是最重要的核心理念:提前并频繁的做让人感到痛苦的事。
小结
在开始行动之前,首先应思考需要解决的是什么问题,而不是去问应该采纳何种方式。
不应去问持续集成应该怎么做,TDD应该怎么做。那些都是解决方案域的东西,而应先搞清楚自身现存什么问题。正如去医院看病,不是直接找医生开药,而是应该问清楚自己是什么病,再对症开具体的药。
实践的目的是为了解决具体问题,而不是解决所有问题。
所以说,大部分问题是文化的问题,而不是一个DEVOPS的问题。文化可以化解一切,而一切的根因又归结于文化。