阿里正在使用一种更灵活的软件集成发布模式

栏目: 编程工具 · 发布时间: 5年前

内容简介:当今典型的软件集成发布模式是,通过类似 GitHub 的 Pull Request 或 GitLab 的 MergeRequest 的方式管理特性分支(Feature Branch):在通过代码评审等方法确认一条特性分支上的改动没问题后,将其合入集成用的分支。随后,代码改动进入在集成分支上运行的持续交付流水线,直到发布上线。在阿里巴巴内部,尽管这种工作方式也得到了研发协同工具平台(Aone)的支持,但广大研发同学选择的主流工作方式却不是它,而是用一种被称之为变更(全称变更请求,英文 Change Reque

当今典型的软件集成发布模式是,通过类似 GitHub 的 Pull Request 或 GitLab 的 MergeRequest 的方式管理特性分支(Feature Branch):在通过代码评审等方法确认一条特性分支上的改动没问题后,将其合入集成用的分支。随后,代码改动进入在集成分支上运行的持续交付流水线,直到发布上线。

在阿里巴巴内部,尽管这种工作方式也得到了研发协同 工具 平台(Aone)的支持,但广大研发同学选择的主流工作方式却不是它,而是用一种被称之为变更(全称变更请求,英文 Change Request)的对象来管理特性分支,直到发布。

初看起来,变更与 Pull/MergeRequest 有不少相同点,但实际它们在理念上的差别很大。

本文详细介绍它们的相同点和不同点,并探讨用户喜欢变更这种方式的原因,当然也会介绍相应的风险和弱点。或许阅读本文,能给你带来一些思考。

相同点

变更与 Pull/MergeRequest 的相同点主要在于对特性分支本身的质量和流程的控制:

  • 一个变更,就像一个 Pull/MergeRequest 一样,大体上对应一条特性分支。

  • 在 Pull/Merge Request 中,可以看到这条特性分支上代码改动内容,进而进行代码评审(Code Review)。类似的,也可以以变更为粒度进行代码评审。

  • 在特性分支上的代码提交,可以自动触发持续集成工具做构建以及各种自动检测,其结果可以在 Pull/Merge Request 中展现。类似的,在变更中也可以展现。

  • 可以把 Pull/MergeRequest 上的最新代码构建部署到它专属的测试环境并运行,以进行测试和调试。在变更中也可以这样做。

  • 在 Pull/Merge Request 中可以设定通过的条件,比如至少两名评审者同意,且所有的代码评审中发现的问题都已修复或澄清,且特性分支上的持续集成流水线运行成功。在变更中也支持类似设置。

不同点及其主要价值

变更与 Pull/MergeRequest 的不同之处关键在于,这个特性分支与其他特性分支一起集成和交付的方式。

对于 Pull/MergeRequest,随后把特性分支合并到集成用的分支,然后就没有然后了。哦不,是然后就不再以特性分支为粒度去管理了。这条特性分支已经合入集成用的分支,其上的代码改动已经融入集成发布的洪流之中,被裹挟着和其他特性分支上的代码改动一起前进,去闯关通过集成 - 发布的各个阶段(Stage)。

而变更不同。即便是已与其他变更集成,它仍然具有一定的独立性和灵活性,在确有必要时,可针对单独变更进行操作。下面我们通过两个例子来详细介绍。

第一个例子

简化起见,假定集成交付过程有三个阶段:日常集成测试、在预发布环境测试、正式发布。

某应用的变更 A 到变更 E 共五个变更,在通过了日常集成测试这个阶段后,进入了在预发布环境测试这个阶段。测试时,发现变更 C 有一个缺陷。这个缺陷因为受日常测试环境所限,在日常集成测试阶段没有暴露出来。经分析,变更 C 与其他四个变更间没有依赖关系,不会互相影响。因此,为了让其他四个变更的发布尽量少受影响,决定把变更 C 从在预发布环境测试这一阶段中摘除出来。其他四个变更在一起再次测试验证,此时该缺陷不再出现,这四个变更在一起通过了在预发布环境测试阶段,进而进入正式发布阶段,发布上线。

阿里正在使用一种更灵活的软件集成发布模式

在这个例子中,在摘除了变更 C 后,没有将其他四个变更在一起再次经过日常集成测试阶段,是出于两方面考虑:

一是,此时的日常集成测试环境,已经被若干新添的变更所占用。它们的测试需要时间,而且可能也会反复调整。把新添的变更赶出去,或者把这四个变更和新添的变更混在一起,或者让着四个变更等着,都分别有明显的不利之处。

另一方面,A、B、D、E 四个变更,它们与变更 C 在一起,已经通过了日常集成测试。而变更 C 又与它们无关,因此对它们再次进行日常集成测试,发现问题的可能性很低。测试是要讲究性价比的,而不是一味追求保证产品零缺陷。

出于以上原因,在具体实战中,开发团队就有可能根据当时实际情况,在评估后决定,在摘除了变更 C 后,不再将其他四个变更在一起送回日常集成环境,而是直接在预发布环境再次测试。

第二个例子

仍假定集成交付过程有日常集成测试、在预发布环境测试、正式发布三个阶段。某应用的变更 A 到变更 E 共五个变更,在通过了日常集成测试这个阶段后,进入了在预发布环境测试这个阶段。此时,根据市场情况变化,需要对变更 C 所承载的新功能做出少量调整,比如页面说明文案上改几个字。考虑到新的修改与变更 C 原有内容要么都发布,要么都不发布,所以为便于管理,新的修改就在变更 C 所在的特性分支上完成。这样形成的变更 C 的最新内容,与其他四个变更在一起,在预发布环境进行测试,通过后正式发布。

阿里正在使用一种更灵活的软件集成发布模式

以上两个例子,是在传统的集成 - 发布方式基础上,加入了一些灵活性:集成 - 发布过程中,必要时可以中途撤下变更,可以中途修改完善变更。而有些团队在使用变更时,采用了更进一步的方式:不再设集成工程师之类的角色,不再规划统一的集成、发布的计划和时间点。而是每个开发同学负责自己的变更,不仅跟踪它直到把变更的质量提升到可集成的程度,而且由开发同学自己把他负责的变更依次适时推入(也可能是自动进入)集成 - 发布的各个阶段,跟踪它直到发布上线。

也就是说,尽管进入了集成 - 发布阶段,各个变更仍是被各自的开发者分别跟踪和推进的:它们可能有各自的推进速率和节奏,而不会相互拖累。彼此无关的变更,只是碰巧一同使用某个测试环境,一同批量测试以提高测试效率、一同上线以避免排队而已。

据此,尽可能缩短了一个需求从开发到发布上线的时间,并表现为相当频繁的发布上线。同时也契合了 DevOps 的理念:“谁开发谁运行”(You build it, you run it)。

这一变化趋势其实和软件研发的管理实践中发生的事情类似:瀑布模型时代就不提了。随后迭代方法取代了瀑布模型。典型的,Scrum 方法中的 Sprint。而更进一步,在精益方法的看板墙上,迭代被弱化,关注的焦点从每个迭代做什么,每个迭代进入到什么阶段,演化为关注每个在制品流动到了哪个阶段,以及每个阶段包含的在制品总量。

类似的,在上述变更管理方法中,从关注某个集成版本进入到集成 - 发布的哪个阶段,演化为关注每个变更进入到集成 - 发布的哪个阶段,以及每个阶段包含了哪些变更。

另一方面的价值

上面介绍的是使用变更管理方式带来的灵活性,以及因为灵活务实而带来的效率提升。变更管理方式,在信息记录和跟踪方面还有一些的好处:

  1. 要想方便地知道,本次测试、本次发布,到底包含了哪些特性,只要看看包含了哪些变更就好了。变更本身有说明文字,变更还可以关联需求、任务、缺陷等工作项,更详细地说明变更的目的。而在变更之外,也没有别的代码修改可以通过直接提交到集成分支等途径溜进来。

  2. 从变更的视角,这个变更相关的所有改动,都在该特性分支上,而不会因为多次反馈修改而散乱到各处。因此这些修改总是可以方便地一同查看,一同操作。同时,总是能够清晰地知道这个变更的状态,它到了哪个阶段:开发完毕了吗?进入日常集成测试阶段了吗?已经正式发布了吗?等等。

  3. 变更可以关联需求、任务、缺陷等工作项,同时变更的状态是可以自动获取的。因此,看板墙上跟踪的工作项,从原理上就可能被自动移动,以反映其实际状态。协作和进展,在看板墙上一览无余。

弱点和风险

以上谈的都是这样的变更管理方式能带来的好处。那么,它有没有弱点和风险呢?

是的,它有。从大爆炸式集成到持续部署流水线,业界几十年来几乎一直在采用一个基本模式:总是一个集成版本,去顺序经历集成 - 发布的各个阶段。这样可以保证,下一阶段收到的内容,总是精确的经过了上一个阶段的检验。

而本文介绍的变更管理方式所引入的灵活性,意味着颠覆了这一基本模式。灵活性从来都是双刃剑。灵活性意味着风险增加,意味着可能被滥用。

敏捷宣言认为“个体和互动高于流程和工具”,上述变更管理方式暗合了这样的思想。但在实际使用该方式时,需要注意到它对团队成员提出了更高的要求:要求他们在具体场景具体案例中,能够对变更间的相关性及相应风险做出评估,并了解不同选择对效率的影响,最终综合做出特定场景特定案例中的决策。具体来说:

  • 变更对应的代码改动越少,中途撤下变更带来的风险越小。

  • 中途修改完善变更所对应的代码改动越少,带来的风险越小。

  • 软件架构越好,变更中途撤下或修改完善带来的风险越小。

  • 本次变更与其他变更的相关性越小,中途撤下或修改完善带来的风险越小。

  • 越紧急,越考虑灵活处理。

  • 业务角度,对软件质量的要求越高,就越不要考虑灵活处理。

延伸一下,事实上,在微服务甚至函数服务时代,即便不使用上述变更管理方式,也有类似上文的风险,也相应需要团队成员具备类似上文的自主判断能力。为什么这么说呢?

之所以把单体应用拆分为微服务甚至函数服务,一个重要原因就是为了每个服务能单独测试和发布上线。

然而,在使用微服务甚至函数服务方式时,被测对象严格地讲并不是一个服务,而是该服务以及测试环境中与其直接或间接打交道的所有其他服务。而当把每个服务单独测试和发布时,就经常会导致本阶段测试时某个其他服务的版本,与下个阶段测试时的版本不同,或者与将来正式发布运行时的版本不同。于是就意味着类似上述变更管理方式中的风险。

相应的,这里面就需要人来判断(当然可以有智能算法的辅助),本次哪些服务上的改动务必要一起测试和上线,而另外几个服务上的改动可以单独运作。而下次可能又是不同情况,要根据下次的具体情况判断。

由此看来,“总是由一个集成版本,去顺序经历集成 - 发布的各个阶段”这个基本模式,其实已经被悄然突破了。上述变更管理方式,只是使这个突破更加明显了而已。

落地及工具支持

以上是介绍了一种独特的变更管理方式,介绍了优点,也介绍了相应的风险。下面我们来看看它在阿里是如何落地的。

首先需要一套分支方案来支持它。大体上是这样:

  1. master 分支总是代表最新已发布版本。

  2. 代码改动总是在特性分支上完成。特性分支总是从 master 分支上拉出的,并在必要时从 master 再次同步。

  3. 没有一条长期存在的集成发布用的分支。而是集成发布过程的各个阶段,各对应一条短期的,被自动管理的集成发布分支。从 master 分支自动拉出该分支,再把各特性分支自动合并到该分支(出现冲突时人工介入),于是它上面就有了用户想要的各特性。

  4. 如果发现某个特性需要进一步修改完善,在特性分支上完成,并再次合并到相应的集成发布分支。

在阿里,我们如何管理代码分支? 这篇文章对上述分支方案有更多介绍。

可以看出,这套方案,对工具平台的要求是比较高的:从界面角度,用户只需要管理各个集成发布阶段分别要有哪些变更。而工具平台要将它映射为对集成发布分支的管理,包括创建新分支或复用已有分支、从各特性分支到集成发布分支的合并等等。这里面也包括了不少算法,以尽可能减少相同的合并冲突重复出现。

对工具平台的高要求,或许是这套方法多年来一直只是在阿里巴巴内部被广为使用的原因,但是现在阿里巴巴也基于内部研发协同工具平台 Aone 对外提供了云效。

本文首发于公众号“云效”: https://mp.weixin.qq.com/s/O-9msZQW0P6lS_1u8f6L9g

作者简介

董越(花名荷锄),阿里巴巴研发效能部高级产品专家,江湖上的名号是流水先生。他在软件配置管理、集成与交付管理领域工作十余载,曾就职于西门子、摩托罗拉、雅虎、索尼爱立信、去哪儿等公司。同时在业余时间著书立说讲演,是《未雨绸缪——理解软件配置管理》等书的作者或译者。他目前在阿里巴巴从事阿里研发协同平台 Aone(对外产品叫云效)的产品设计工作。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Beginning XML with DOM and Ajax

Beginning XML with DOM and Ajax

Sas Jacobs / Apress / 2006-06-05 / USD 39.99

Don't waste time on 1,000-page tomes full of syntax; this book is all you need to get ahead in XML development. Renowned web developer Sas Jacobs presents an essential guide to XML. Beginning XML with......一起来看看 《Beginning XML with DOM and Ajax》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具