InfoQ 研究中心诚意出品,一份报告带你走进中国 2000 万开发者 了解详情
写点什么

真正的敏捷工作流 —— GitHub flow

  • 2019-09-20
  • 本文字数:4479 字

    阅读完需:约 15 分钟

真正的敏捷工作流 —— GitHub flow

7991 年,随着极限编程(Extreme programming)方法论的提出,持续集成(Continuous integration)也随之成为一项标准化的敏捷实践,被逐步应用于各类软件的开发流程中。


9102 年的今天,持续集成的概念已经在软件开发领域生根发芽,广泛应用于不同平台及设备的项目开发,极大提升了项目迭代速度,降低了维护成本。


不过,作为“敏捷”的固有属性,持续集成也并不仅限于特定的模式,不同的项目可能遵循不同的实践,形式多种多样,效果可能也参差不齐。


为了解决这些问题,一些 Workflow 的通用模式被提出,而本文的主角,就是其中的天之骄子 —— GitHub flow。


GitHub flow 是什么?

GitHub flow,顾名思义,就是 GitHub 所推崇的 Workflow。千万不要理解成 GitHub 上才能用的 Workflow


其官网的描述为:


GitHub flow is a lightweight, branch-based workflow that supports teams and projects where deployments are made regularly.


从中我们可以得出的信息是 —— 这段描述完全就是废话 GitHub flow 具有很高的通用性。


为了更便于了解 GitHub flow 的内容,我们从流程图入手:



其中的主要流程为:


  • 新建分支(Create a branch);

  • 提交修改(Add commits);

  • 创建 PR(Open a Pull Request);

  • 代码评审(Discuss and review your code);

  • 部署(Deploy);

  • 合并(Merge);


细心的同学可能很快会发现,GitHub flow 最大的亮点在于部署(Deploy)发生在 合并(Merge)之前,这就是 GitHub flow 的核心,非阻塞式集成 —— 在产生任何副作用之前得知当前修改的所有集成效果,达到真正的持续集成。


GitHub flow 有什么优势?

GitHub flow 的核心优势在于其流程带来的自动化可能性,能够做到其它流程无法实现的检查过程,并极大简化开发团队的体力劳动,真正发挥自身的价值。


主要体现在以下方面:


基于修改的检查

基于修改的检查(Change-based checking) 是相对于全局检查(Global checking)的概念,最典型的例子就是代码覆盖率。项目中一般会设立覆盖率的最低阈(yù)值,并在流水线中进行检查。


根据著名的覆盖率第一定律:


随着时间的推移,项目中的实际覆盖率必将会无限趋向于要求的覆盖率。—— 沃兹基硕德


如果项目中配置的最低要求是 90%(暂不考虑覆盖率类型),那么就不要指望实际覆盖率能够超过 95%。于是问题来了,全局覆盖率要求会导致什么样的严重后果呢?


我们考虑一个假象项目,总共有 100 行代码,覆盖率要求 90%,实际覆盖率 90%。有一天,项目组成员小明发现其中有 10 行无意义的 console.log(42),决定将其删除。


学过初等数学的我们都知道,对于 0~1 之间的分数,分子分母同时增加相同数值时,分数的值会增大;反之,分子分母同时减少相同数值*时,分数的值会减小。(这里要求结果仍然处于 0~1 之间。)


如果还不能反应过来的话,可能要考虑补充六个核桃了。删除无用代码的结果是,覆盖率不再满足要求,从而无法通过流水线。


90/100 * 100% = 90.00%80/90  * 100% = 88.89%
复制代码


之后,小明可以作出以下几种选择:


  1. 撤销之前的修改,保留无用代码;

  2. 降低全局覆盖率要求;

  3. 从其它覆盖率不足的地方补充代码覆盖;

  4. 找到之前导致覆盖率不足的人,要求其补充代码覆盖。


选项 1 固然是最简单的方案,直接当作无事发生。


选项 2 虽然也简单,但是既然当前覆盖率能够降到 90%,如果降低要求以后必然还会继续下降,同时如果被其他人发现可能遭到质疑(Challenge)。


选项 3 中一个覆盖率不足的问题可能继续分为两种子类型:案例遗漏非测试友好。前者是忽略了某种应当覆盖的情况,而后者是代码的设计本身导致无法合理测试。对于前者,如果缺乏上下文而直接把当前行为当作预期,可能会埋下错误隐患(如果未覆盖当前行为本身是未定义行为甚至错误行为);对于后者需要进行额外的重构,仍然具备前述问题(在测试覆盖不足的情况重构?),并且可能导致原问题递归(如果重构本身减少了代码量)。


选项 4 原则上是最正确的方案,但实际上可行性很低。如果小明找到小红,告诉她一年前编写的代码覆盖率不足,那么得到的回应多半是:我当年都跑得好好的,你一改动就挂了,不是你的问题是什么?


归根到底,不论考虑哪种选项,对于小明而言,学到的只有一件事:


永远不要做会减少代码的修改!


永远不要做会减少代码的修改!


永远不要做会减少代码的修改!


一旦开发团队中每个人都认识到这一点之后,之后的开发过程就会向着堆垃圾的方向发展:能不动原有代码就不动,实在不行写个 if插进去。提取公共代码?双倍的覆盖就是双倍的_快乐_安全,怎么能说不要就不要?


不过,一旦我们使用合并前集成(Integration before Merge)的方式,便能够得知每个改动中每个文件的覆盖率情况,从而在开发过程中主动避免覆盖率下滑,把质疑集中到问题的来源 —— 提交代码并且覆盖率不足的人身上。



非错误级反馈

非 GitHub flow* 的流水线中,永远只存在一种反馈方式 —— 报错。(为了保持简洁,这里将所有不符合 Integration before Merge 的流程统称为「非 GitHub flow」。)


这时候有人可能会说,我们可以向流水线的控制台输出里打印日志。不过我可以保证,没有人会在正常构建的情况下守着看完每一条日志,一个合理设计的流水线也不应该需要主动关注这里的内容导致不必要的效率浪费。


日志的内容往往绝大部分都是非关键信息:



即便快速浏览日志,恐怕也很难发现关键信息。


不过,项目开发中往往存在很多非关键因素,平常不会太过关心,但一旦问题严重之后又会很麻烦。一个很好的例子就是应用体积。假如开发过程中对体积毫不关心(内网可能传输很快),那么等到用户真正无法容忍加载时间而导致使用率急剧下降的时候,还得专门回过头来做体积优化*。(如果本身就是打算靠创造额外优化工作赚钱的话,可以当我没说。)



通过 GitHub flow,我们能够在合并之前得到所有相关的信息,并自行判断问题的严重性(其他 Reviewer 也有义务判断)。如果本次改动并没有添加新的依赖,但是构建后大小急剧增加,那么可能就需要检查文件引用或者构建过程存在问题。


由于是基于集成结果的信息提示,因此还可以设置出现条件,例如某文件体积变化超过 0.5%。这样能够避免被固定消息所打扰,只关心必要内容。


除了自动执行的被动检查项目外,对于需要可观成本的检查,往往设计成主动检查项目。一般通过 PR 的标签或者评论内容进行触发,类似于:



性能测试(Performance testing) 就是一个较为典型的例子,如果小明不畏艰难险阻对实现代码进行了深度重构,那么在合并前就必然选择进行性能测试来避免非预期的影响。同理,如果只是添加了测试代码,那么性能测试将完全没有必要。


同样的,Reviewer 也应当评估是否所需的主动检查项目都被执行。


无限环境

多团队协作项目中,一个常见的痛点就是需要根据自身或者外部的需求准备各种环境,然而一些环境在大部分时候都不会使用到,往往需要在不明所以的情况下突然增加或者调整环境配置。


这时就可以回归到 GitHub flow 的重中之重 —— 合并前部署。


所谓的无限环境,就是自动将当前 PR 中的最新提交*部署到一个临时环境中,并返回该环境的 URL 地址。(如果资源丰富的话也可能部署每一个提交以方便比对。)



为此,环境准备工作将变得非常简单,只需要修改相应配置文件并创建 PR,即可得到一个对应的新环境。这一切甚至不需要依赖本地开发环境,而是直接在代码平台的在线编辑器中完成。


由于可以直接预览当前修改,不会再出现不必要的疑 车 虫无据的情况,Reviewer 有任何怀疑时便可以直接在预览环境中验证,而非凭空猜疑。Reviewer 也可以放心大胆的验证自己的怀疑,不需要在本地开发环境耗时耗力地切换。


有条件时甚至可以为预览模式设定特殊构建模式,例如高亮效果用于定位修改内容:



这样可以极大提升 Review 效率,降低 Reviewer 的负担。


自动化工作流

项目开发中往往有大量的时间被浪费在等待。等待构建、等待测试、等待 Review ……而这一切,都可以依靠 GitHub flow 来进行改善。


由于 PR 中能够运行所有必要的检查,所以本地开发环境中仅仅需要关注最可能受到影响的内容(例如当前文件的测试),而把其它不在固定影响范围的检查都转交给 PR。由于 PR 的工作机制,即便存在冲突无法合并也不会导致 Push 失败,并且 Push 本地代码后便可以立刻关电脑走人,即便 PR 检查失败也不会有任何后果。


PR 中能够利用 CI 环境,不受本机执行能力限制,因此可以并行检查所有需验证项目:



这里的检查本质上仍然是 Code Review,只不过参与者不是自然人。


检查期间,开发人员可以充分利用碎片时间处理其它事务,而无需关心检查进度。如果任何项目检查失败,将立刻收到邮件通知。


如果所有检查项目均已通过并且当前 PR 并非 Draft 状态*,能够自动通知 Reviewer 进行代码 Review,并且在所有 Reviewer 同意后自动 Merge,在 Happy Path 下完全无需再次人工干预。


(Draft PR 是 GitHub 最近推出的功能,用于标记当前 PR 为未完成状态。其它平台可能将采用不同的判断方式。)


说到 Reviewer,就不得不提 Code Owners。Code Owners 是 GitHub 的内置功能*,能够配置每个文件/文件夹的所有者,在 PR 完成时根据修改文件的范围自动向添加相应文件所有者为 Reviewer,只有当各个 Group 的 Reviewer 都同意时才允许合并。(一些第三方工具也提供了类似的机制,功能可能更加强大。)



Code Owners 充分保障了项目的可维护性,每个 Code Owner 同时具备以下职责:


  • Domain export:对相关代码有深度的了解,知晓其历史背景与特殊行为,能够快速发现隐藏问题;

  • Coordinator:掌握每次修改的内容及原因,避免代码/环境冲突及已有行为被破坏;

  • Contact:如果对相关代码有疑问,能够立即确定联系对象而无需层层转发;

  • Responsible person:如果相关代码出现了什么意外,负责背锅,避免不必要的推诿。


例如将环境配置文件分配个某个/某些项目组成员,那么他们就能够充分知晓各个环境的使用情况,作出合理安排。


如何开始使用 GitHub flow?

使用 GitHub flow 的基本要求有:


  • 具备一个代码版本控制环境;

  • 具备一个持续集成环境;

  • (可选)具备 CI 环境的管理员权限;

  • 能够创建一个有权限访问 VCS 平台的机器人帐号;

  • 能够自由使用 VCS 平台的 WebHook API;

  • 能够自由使用 CI 平台的 Trigger API;

  • (可选)能够自由使用 CI 平台的状态查询 API;

  • 能够创建一个高可用的内部服务器用于机器人帐号的运行;

  • 能够决定开发团队的工作流程;

  • 能够投入成本改善基础设施;


遗憾的是,我至今没有过这种条件,如果你有能力去实践 GitHub flow,希望能够珍惜这次改善开发体验的机会,让更多人了解这种流程优化带来的巨大效率优势。


如果有任何具体的技术问题,也欢迎进一步的讨论。


写在最后

以我个人的体验,GitHub flow 是 世界上唯一的真理 真正能够拯救开发效率的敏捷实践,将开发人员真正从体力劳动中解放出来,从而能够专注于学习与思考。


如果你也觉得 GitHub flow 真正拯救了你的项目开发,不妨将它继续推广下去。


作者介绍


余泽江,ThoughtWorks 咨询师,拥有多年 Web 应用开发经验,主要专注于前端框架底层实现与 Web 规范演进。


本文转载自 ThoughtWorks 洞见


原文链接


https://insights.thoughtworks.cn/real-agile-workflow-github-flow/


2019-09-20 08:002793
用户头像

发布了 84 篇内容, 共 19.0 次阅读, 收获喜欢 227 次。

关注

评论 1 条评论

发布
用户头像
进来就是7991年......
2019-09-20 11:10
回复
没有更多了
发现更多内容

云上弹性高性能计算,支持生命科学产业高速发展、降本增效

阿里云弹性计算

HPC 高性能计算 生命科学 药物设计

喜讯!云效度量能力获信通院先进级评估

阿里云云效

云计算 阿里云 DevOps 研发效能 研发

「微服务的细节」—— 周期性注册 or 一次性注册

袁世超

微服务

Larix真正的去中心化借贷平台,并开启double Mining活动

鳄鱼视界

对讲功能在远程办公中的应用 | 社区征文

Changing Lin

初夏征文

百度安全再次亮相高性能计算国际顶会SC 2022 — 采用Fuzzing技术防护高性能计算静默数据损坏安全风险

百度安全

百度安全 百度安全实验室 高性能计算国际顶会 SC 2022 Fuzzing技术防护

稳住了,别抖!—— 看GetX 的Worker如何防抖

岛上码农

flutter ios 前端 安卓开发 6月月更

数据库每日一题---第18天:每天的领导和合伙人

知心宝贝

数据库 大数据 前端 后端 6月月更

AWS的运营管理类服务

冯亮

云计算 AWS

一问带你彻底了解JVM-Java虚拟机内存区域详解

派大星

JVM

如何把企业内部碎片信息系统化?

小炮

浅谈融云即时通讯服务「日志优化」

融云 RongCloud

数据资产管理

奔向架构师

数据资产 数据管理 6月月更

攻防演练中红队的内网横向扩展

穿过生命散发芬芳

6月月更 攻防演练

2022华为全球校园AI算法精英大赛即将升级启航,等你来战,开拓未来边界

最新动态

链上智能合约Dapp系统开发部署搭建

薇電13242772558

区块链 智能合约

携手腾竞体育后,英特尔IMC如何加速电竞生态正循环?

科技之家

透过华为军团看科技之变(四):互动媒体(音乐)

脑极体

【网络入门】详解常用的基础网络知识(面试常考内容)

dvlinker

网络知识 TCP与UDP 心跳机制与丢包重传 网络命令 抓包分析

覆盖接入2w+交通监测设备,EMQ为深圳市打造交通全要素数字化新引擎

EMQ映云科技

物联网 IoT 智慧交通 实践案例 6月月更

AIOps落地五大原则(二):价值路线

BizSeer必示科技

从华为WeAutomate数字机器人论坛,看政企领域的“政务新智理”

王吉伟频道

RPA 数字化转型 华为WeAutomate 政务新智理 数字政府

客户案例|观测云助力合思信息升级新一代可观测平台

观测云

flutter系列之:flutter中的builder

程序那些事

flutter 程序那些事 6月月更

Android 修改系统音量及监听

yechaoa

android 6月月更 AudioManager

毕业回馈!Apache Doris 社区所有贡献者来领礼品啦!

SelectDB

数据库 数据湖 开源项目 apache doris 社区活动

A/B测试助力游戏业务增长

字节跳动数据平台

游戏开发 游戏 ab测试 游戏运营

统一日志

卢卡多多

日志 6月月更

vue导航路由

小恺

6月月更

新课上线 | 每次 5 分钟,轻松玩转阿里云容器服务!

阿里巴巴云原生

阿里云 云原生 容器服务

真正的敏捷工作流 —— GitHub flow_文化 & 方法_Thoughtworks洞见_InfoQ精选文章