4种常见分支模式解析及优劣对比 | 研发效能提升36计

简介: 团队研发的本质并不是团队规模越大,研发的效率就越高。我们以为团队规模越大,研发效率就会越高,可以做越多的东西,但是我们发现团队规模大到一定程度,整个研发效率是会下降的,甚至降得非常快。为什么团队的规模越来越大,我们的发布反而越来越慢了?

image.png

策划&编辑|雅纯

团队研发的本质

image.png

我们曾经接触到一家企业,它一开始只有8个人,那个时候每个月都可以发一两个版本出去,客户都可以用到,因为他们是做医院的信息管理HIS系统。他们觉得做得还不错。后来团队发展比较快,规模到了80人左右,却半年没发一个版本。这导致实施团队没脸见客户,因为客户说半年前提的需求怎么还发不出来。

这个时候悖论就来了:我们以为团队规模越大,研发效率就会越高,可以做越多的东西,但是我们发现团队规模大到一定程度,整个研发效率是会下降的,甚至降得非常快。

image.png

站在团队的角度来说,因为人多,协作越来越慢,协作的成本也越来越高。我们发现团队的研发模式,人越多越会有问题,因为冲突更多,等待更多。这里冲突是指代码集成发布过程中的冲突,而等待也是集成和开发过程中代码彼此的等待。

以下是两个具体的场景。

image.png

假设有两个程序员A和B一起工作,A一开始每次提交都把工作逐渐成功提交到线上去,然后B提交了一个版本,导致编译失败了。这时,A就无法提交,因为提交就会挂,要等待B修复问题才能提交,这时A的提交和B的工作就产生了冲突。

第二种情况,多个分支往同一个分支合并,FeatureA先合进主干,FeatureB晚了一点结果发现无法合并,因为基线不一样了,这时候必须先解决掉代码冲突才能合进去。

image.png

如上图,假设现在有3个人,A、B和测试C,每个人的点代表它做的任务,比如A一直在做自己的事情,每完成一个事情就开始做下一个事情,做完第三个事情的时候他觉得需要去找B联调一下,就给B发了一个ping,但是B有自己的节奏,在忙他自己的任务,所以并未马上响应A的请求。他发现有一个任务可以提测了,他就告诉了C,C发现有问题就马上Pong了回去,但是这时B在忙另外一个任务,没有响应。C发现B无响应,又发了一次Pong,这时B看到了A和C的消息,他先处理了A的事情,给A回复了一个Pong的消息。

我们发现,程序员和程序员,测试人员和开发人员之间,在整个的开发协作中其实是异步的、延迟协作的过程。每个人并不是收到一个请求就马上回复,马上协作,往往都是有自己的步调和自己的动作,可能会产生延迟。所以当产品更复杂,协作更多,团队更复杂,团队的人多了以后,协作成本就会快速上升。

在这样一个异步的、延迟协作的过程中,程序员面对日常开发的工作,需要有一套相应的研发模式,来保证在协作过程中能够持续地把信息同步掉,并快速地响应掉。

软件交付过程,本质是开发者围绕代码库的协作过程。无论是产品代码、配置、环境和发布流程,都可以通过代码来描述,并保存到代码库里。

因此,研发模式的目的就是约束我们在围绕代码库工作时的行为,本质是一种围绕代码库的行为约束。

研发模式我们狭义地理解为分支模式,包含一系列的行为约束,比如分支类型及其标识、分支的生命周期、Commit在分支间的流转方式,以及流转的约束条件,还有分支和代码之间的对应关系等。接下来我们会一一探讨。

研发模式是一系列研发行为的约束,目标是避免冲突、减少等待。在协作的过程中,人多了之后带来的最大的问题就是冲突变多、等待变多,所以好的研发模式应该尽可能的避免冲突,尽可能的减少等待。

首先看一下研发模式和研发行为之间的对应关系。

image.png

这些研发行为和代码库行为有一个Mapping(映射)关系。开始新的特性开发时,我们会创建一个新的特性分支。做一次代码的提交集成,其实就是一次Commit和Push,完成之后进入集成验证,就做了一次分支的Merge。

同样地,集成完进入待发布也是在做Merge,而完成发布意味着打一个Tag。代码库里的操作记录了我们的研发行为,所以研发行为和代码库的操作可以做到一一映射。

image.png

要避免冲突,唯一的方法是大家彼此隔离,分开就没有冲突。在代码库里面,很多时候通过分支的方式,来做工作之间的隔离,避免冲突。

要减少等待,而等待是信息不同步造成的,尽可能地做到信息同步,就不用等待。在代码里面的等待,是代码之间基线的同步,比如说频繁地提交。所以其实分支是用来避免冲突和做工作隔离,而频繁地提交合并是为了做信息同步,减少等待。

Q:如果是一个人做软件开发,用什么样的分支模式?一个人会不会有冲突?

一个人做软件开发的时候是不会有冲突的,一个人工作的时候不需要很多分支,一个分支就足够。一个人做开发,也不用等待信息,因此可以一条主干走到底。但是如果人数扩张到10人、100人,彼此之间就会有工作的隔离,彼此之间也会存在着冲突,也存在着等待。所以在这个过程中,随着协作的人数越来越多,分支的模式会不断地发生变化。

4种常见分支模式解析

主干开发

image.png

团队人很少(比如1~2个人)的时候,最常见的研发模式是Trunk—BasedDevelopment,也叫主干开发方式。

主干开发方式一条主干分支走到底,开发的过程中不会有太多的冲突,要求代码持续集成到主干上去,所以在开发过程中不需要做相应工作的隔离。开发的过程中,所有的开发者在主干上面频繁地提交,频繁地集成。这种分支模式下,唯一的分叉出现在发布的时候,为了能够把发布版本隔离出来,有了发布分支。

这种模式下,不需要做分支隔离,信息同步通过持续频繁地提交来保证。在人数比较少,并且整个工程能力比较强的时候,这是我们推荐的研发模式。

但是当参与开发的人数越来越多时,主干开发的冲突几率就大大增加了,对工程能力的要求也越来越高。

所以说主干开发不是万能药,主干上的人越多,代码提交的冲突机率就越大,而且解决冲突的风险也越大。如果两个人的时候,即便有冲突我知道只是和另外一个人有冲突,如果是10个人,这中间就会产生很多的问题。

另外在主干开发里面,要保持信息地同步,需要做频繁持续地提交,而且每次提交的力度要很小,这针对有一些特性来说,可能只做了一半,这时需要将它提交上去,需要通过特性开关等方式来进行隔离。比如说这个是还未完成的特性,提前把它的开关制成Off,再做相应的提交,但是特性开关本质上也是一个分支。

特性开关只是用代码的形式拉了一个分支,但是这个分支只有打开的时候才能跑到,本质上还是一个分支。如果特性开关比较多,它在一定程度上会把代码变得很脆弱,维护起来比较麻烦。

主干开发当很多人同时参与时,代码冲突的机率很大,而且特性开发的时候也有很多的风险,大家彼此之间需要隔离。

Git-Flow

image.png

Git—Flow的基本原则是需要什么分支就给什么分支,任何事都有很明确的分支。比如说要集成,就有develop分支,要开发就有feature分支,要发布有release分支,每个都是不同的分支。每种类型的分支都有确定的用途。

比如说feature分支,是很多个feature并行开发的时候用来去做工作隔离,避免彼此之间有冲突。而release分支是用来做发布的隔离,使得发布之间不会有冲突。

我们发现这种模式很好地做了隔离,但是在信息同步的过程中,它需要基于develop频繁地集成去做同步,并且在各个分支中间做相应的cherry-pick或者是rebase这样的方式来做的。

这个时候,我们就会发现分支太多,而且一个commit从feature开发到最终发布要经历好几个分支,其中分支的流转和merge规则非常麻烦。

所以Git—Flow也不是仙丹,过多的分支增加了分支管理的复杂度。还有如果Feature分支的生命周期特别长,它的合并耗时也会变得很长。而且Develop分支和Master分支同时存在,好像Develop分支的意义不是特别大。另外区分Feature分支和hotfix好像意义也不是特别大。

所以Git—Flow虽然增加了很多的分支,让各种工作尽可能地隔离开来,但是它信息同步是很麻烦的,而且它管理这些分支的难度也特别大。

GitHub-Flow

image.png

GitHub引入了一个分支模式叫GitHub—Flow,明显比Git—Flow简单很多。没有Develop,没有hotfix,也没有Release,当需要开发的时候拉一个Feature分支,开发完就合并Master做发布。

这个过程中,它的隔离只发生在开发过程中,它的信息同步通过持续地往Master去做集成,和频繁从Master里面Pull代码来实现。它的发布过程是基于主干Master分支做的,因此没有在发布的过程中做相应地隔离。

这时候又会带来一个问题,就是Master分支需要做持续集成,这个分支既是集成的地方也是发布的地方。一旦集成后出现问题,它会把所有的工作堵塞掉,无法发布也无法合并。

所以GitHub—Flow很简单,可以做相应地隔离,但是如果说本身基础设施或工程能力比较弱,它会限制你集成和发布的频率。

GitLab-Flow

image.png

GitLab—Flow和GitHub—Flow区别是在发布过程中有了Pre-production分支和Production分支,基于开发、集成和发布过程中不同的环境分配了相应的分支。

完成集成以后是在Master分支上,下面一步将会切换到预发分支上。对应Commit的版本已经达到了预发的条件,在预发上做完验证以后再将其同步到Production分支,说明它已经达到了发布的条件,所以它是逐级Promotion(晋级)的过程。逐步从集成的环境Promotion到预发环境,再Promotion到生产环境。

我们简单地介绍了一些常见的分支模式,下面我们再来比较一下他们之间的优劣。

常见分支模式优劣对比

image.png

TBD分支少,实施简单,做起来不需要太多的理解成本。但是它对团队协作的成熟度和纪律都有很高的要求,一旦有人不遵守纪律,那主干就会成为你的梦魇,这时就很难很好地去做持续地集成和发布了。一旦它出现问题,所有人都被Block,这是主干方式的优缺点。

Git—Flow特性之间可以并行开发,规则很完善,每个分支的职责特别明确,再大的团队协作基本上也不会有太多的问题,但是它分支太多,规则太复杂,而且分支生命周期长,合并冲突会比较频繁。尤其是Develop,Master是长期存在的。

对于GitHub—Flow,Git—Flow能支持的基本上它也能支持,但是这里面有一个问题,它的集成只有在Master分支去做,因此对集成纪律有很高的要求,而且集成和发布在一个分支上,一旦集成分支中断,无论是集成还是发布都会被中断。

Gitlab—Flow也是并行开发,但是开发分支还是会有生命周期长的问题,有合并冲突的风险。另外,发布分支之间是有耦合的,比如说Prodution和Pre—Prodution之间,是基于Promotion来耦合,所以彼此之间也是一种中断阻塞的方式,而且很多的开发分支,Prodution和Pre—Prodution,也增加了分支管理的复杂性。

因此,我们发现没有哪个分支模式是绝对好的,也没有哪个是绝对差的。

对于分支有一个简单的原则,即控制分支数目,小批量频繁集成。控制分支的数目也就是做到工作隔离,但是又增加太多管理成本。而小批量频繁集成可以加速信息同步。

所以一个简单的原则就是,从最大化生产力和最小化风险的角度,尽可能地控制分支的数目和小批量频繁集成。

最大化生产力:所有人工作在公共区域内。除了一条长期的,不被中断的开发主干外,没有任何分支。也并无其他规则,代码的提交过程相当简单。但是,每一次的代码提交,都有可能破坏整个项目的集成,进而导致项目进度的中断。

最小化风险:所有人都工作自己的分支上。每个人的工作是相互独立的,没人可以打断其他人的工作,这样,减少了开发被打断的风险。但是,这种做法却增加了额外的流程负担,同时,协作变得非常困难,所有人都不得不谨小慎微地合并自己的代码,即便是整个系统中非常小的一部分,也是如此。

那么怎么设计或选择适合自己的分支模式?下一篇文章,我们将继续分享,不同的团队如何选择适合自己的研发模式。

image.png

点击下方链接,立即体验云效流水线Flow
https://www.aliyun.com/product/yunxiao/flow?channel=yy_rccb_36

image.png

相关文章
|
1月前
|
数据采集 机器学习/深度学习 数据挖掘
10种数据预处理中的数据泄露模式解析:识别与避免策略
在机器学习中,数据泄露是一个常见问题,指的是测试数据在数据准备阶段无意中混入训练数据,导致模型在测试集上的表现失真。本文详细探讨了数据预处理步骤中的数据泄露问题,包括缺失值填充、分类编码、数据缩放、离散化和重采样,并提供了具体的代码示例,展示了如何避免数据泄露,确保模型的测试结果可靠。
69 2
|
2月前
|
人工智能 数据挖掘 大数据
排队免单与消费增值模式:融合玩法与优势解析
排队免单模式通过订单排队、奖励分配、加速与退出机制等,结合消费增值模式中的积分制度、利润入池与积分增值等,共同提升消费者参与度和忠诚度,促进商家销售增长。具体包括订单自动排队、大单拆小单、异业联盟、线上线下融合及数据分析优化等进阶玩法,以及积分增值模型演算,形成一套完整的消费者激励体系。
|
2月前
|
开发工具 Android开发 iOS开发
深入解析安卓与iOS开发环境的优劣
【10月更文挑战第4天】 本文将深入探讨安卓和iOS两大主流移动操作系统的开发环境,从技术架构、开发工具、用户体验等方面进行详细比较。通过分析各自的优势和不足,帮助开发者更好地理解这两个平台的异同,从而为项目选择最合适的开发平台提供参考。
27 3
|
2月前
|
Web App开发 存储 前端开发
前端开发必备:requestAnimationFrame、setInterval、setTimeout——功能解析与优劣对比
前端开发必备:requestAnimationFrame、setInterval、setTimeout——功能解析与优劣对比
173 0
|
2月前
|
前端开发 算法 JavaScript
无界SaaS模式深度解析:算力算法、链接力、数据确权制度
私域电商的无界SaaS模式涉及后端开发、前端开发、数据库设计、API接口、区块链技术、支付和身份验证系统等多个技术领域。本文通过简化框架和示例代码,指导如何将核心功能转化为技术实现,涵盖用户管理、企业店铺管理、数据流量管理等关键环节。
|
3月前
|
设计模式 存储 安全
PHP中单例模式的深入解析与实践指南
在PHP开发领域,设计模式是构建高效、可维护代码的重要工具。本文聚焦于单例模式——一种确保类仅有一个实例,并提供全局访问点的模式。我们将从理论出发,探讨单例模式的基本概念、应用场景,并通过实际案例分析其在PHP中的实现技巧。最后,讨论单例模式的优势、潜在缺陷及如何在实际项目中合理运用。
|
4月前
|
API C# 开发框架
WPF与Web服务集成大揭秘:手把手教你调用RESTful API,客户端与服务器端优劣对比全解析!
【8月更文挑战第31天】在现代软件开发中,WPF 和 Web 服务各具特色。WPF 以其出色的界面展示能力受到欢迎,而 Web 服务则凭借跨平台和易维护性在互联网应用中占有一席之地。本文探讨了 WPF 如何通过 HttpClient 类调用 RESTful API,并展示了基于 ASP.NET Core 的 Web 服务如何实现同样的功能。通过对比分析,揭示了两者各自的优缺点:WPF 客户端直接处理数据,减轻服务器负担,但需处理网络异常;Web 服务则能利用服务器端功能如缓存和权限验证,但可能增加服务器负载。希望本文能帮助开发者根据具体需求选择合适的技术方案。
201 0
|
4月前
|
开发者 云计算 数据库
从桌面跃升至云端的华丽转身:深入解析如何运用WinForms与Azure的强大组合,解锁传统应用向现代化分布式系统演变的秘密,实现性能与安全性的双重飞跃——你不可不知的开发新模式
【8月更文挑战第31天】在数字化转型浪潮中,传统桌面应用面临新挑战。本文探讨如何融合Windows Forms(WinForms)与Microsoft Azure,助力应用向云端转型。通过Azure的虚拟机、容器及无服务器计算,可轻松解决性能瓶颈,满足全球用户需求。文中还提供了连接Azure数据库的示例代码,并介绍了集成Azure Storage和Functions的方法。尽管存在安全性、网络延迟及成本等问题,但合理设计架构可有效应对,帮助开发者构建高效可靠的现代应用。
34 0
|
4月前
|
C# Windows 开发者
超越选择焦虑:深入解析WinForms、WPF与UWP——谁才是打造顶级.NET桌面应用的终极利器?从开发效率到视觉享受,全面解读三大框架优劣,助你精准匹配项目需求,构建完美桌面应用生态系统
【8月更文挑战第31天】.NET框架为开发者提供了多种桌面应用开发选项,包括WinForms、WPF和UWP。WinForms简单易用,适合快速开发基本应用;WPF提供强大的UI设计工具和丰富的视觉体验,支持XAML,易于实现复杂布局;UWP专为Windows 10设计,支持多设备,充分利用现代硬件特性。本文通过示例代码详细介绍这三种框架的特点,帮助读者根据项目需求做出明智选择。以下是各框架的简单示例代码,便于理解其基本用法。
222 0
|
4月前
|
开发者 iOS开发 C#
Uno Platform 入门超详细指南:从零开始教你打造兼容 Web、Windows、iOS 和 Android 的跨平台应用,轻松掌握 XAML 与 C# 开发技巧,快速上手示例代码助你迈出第一步
【8月更文挑战第31天】Uno Platform 是一个基于 Microsoft .NET 的开源框架,支持使用 C# 和 XAML 构建跨平台应用,适用于 Web(WebAssembly)、Windows、Linux、macOS、iOS 和 Android。它允许开发者共享几乎全部的业务逻辑和 UI 代码,同时保持原生性能。选择 Uno Platform 可以统一开发体验,减少代码重复,降低开发成本。安装时需先配置好 Visual Studio 或 Visual Studio for Mac,并通过 NuGet 或官网下载工具包。
397 0

推荐镜像

更多