如何提高一个研发团队的“代码速度”?

标签: 研发 团队 代码 | 发表时间:2018-08-04 15:03 | 作者:
出处:http://kb.cnblogs.com/

  阿里妹导读:Code Velocity(代码速度),体现了一个研发团队快速响应业务需求的能力。如果做得好,代码从 commit 到上线可能平均只需要两三天时间,甚至连紧急发布都不怎么需要了。

  今天,蚂蚁金服国际事业群技术风险部研究员南门,将和大家聊聊 Code Velocity,希望能在团队效率问题方面,为你带来一些启发。

   什么是代码速度(Code Velocity)?

  Code Velocity 的定义是:一段代码变更,从 git 里的 commit time,到在生产环境里运行,中间经过了多少时间。换句话说,代码从写完开始,多快能到达生产环境。

  举个例子,C公司的一个团队,他们今天的 code velocity 一般在是 2-4 周左右:

  他们的一个典型的迭代周期是 4 周⁽¹⁾:第一周系分测分,第二、三周 coding、testing、修 bug,第三周末或第四周初合并回 master、部署集成测试环境、跑回归、上预发、上生产环境。在这样的迭代节奏和“分支开发、主干发布” ⁽²⁾ 的模式里,从 commit time 到进生产环境,平均是 2 周左右。

  他们还有一些比较长周期的项目。例如,有几个项目是四月中上旬拉的分支,一直到五月下旬才合回 master,六月初发布上线。从四月上旬到五月下旬,这几个项目分支里的代码没有合回 master 过。这几个项目的 code velocity 就比较长,平均是 4 周左右。

   为什么要度量和提高 Code Velocity?

  Code velocity 体现的是一个研发团队快速响应业务需求的能力。

  以上文C公司这个团队今天的快速响应、交付的能力水平,在两周一次发布窗口的节奏里,大部分时候可能已经够了,但一旦遇到各种意外,就捉襟见肘了,例如:临时封网,需求变更,项目因故延期等。

  快速响应、快速交付的能力要有一定的“储备”,这就好像足球运动员要有体能储备:要想赢下加时赛,就要有踢两个加时赛的体能。研发团队要能在两周一次发布窗口的节奏里游刃有余,就要有一周一发甚至一周两发的能力。况且,可以预见在不远的将来,两周一次的发布窗口也嫌太久了,业务压力会倒逼一周一发成为常态。那时候,这个团队就要有“天天发”的能力,才能游刃有余。

  研发团队的 code velocity 和他们拿到的业务结果之间的关系,就像饭店上菜时间长短和生意火不火之间的关系一样,两者是相关的,但不是强因果关系:

  • 有些饭店上菜挺快的,但生意不火。不能就因此说“上菜时间长短”不重要。

  • 有些饭店,上菜很慢,但生意也还是很火。也不能因此就说“上菜时间长短”不重要。

  一家饭店要火,还要看地段、装潢、菜单、原料、厨子、服务员、宣传等。

  除了快速响应业务需求以外,提高 code velocity 还能帮助开发和测试同学降低项目并发、减少上下文切换、提高幸福感。在两周一次发布窗口的节奏下,很多时候研发同学把一个需求写完、测完,要等其他需求,等集成环境测试,再回来搞一波,然后到了生产环境发布再回来搞一波。事情是不连续的,开发测试其实是被打断的。Code velocity 提高了以后,开发测试有连续性,写完了测完了的代码就发走了,研发同学也不用身上同时背着一串项目了。

   为什么 Code Velocity 快不起来?

  仔细想想,一段代码从 git commit 到生产环境,这个过程中时间大部分是花在等待上的:等着和其他代码一起发布上线。之所以会要把很多代码合到一起,每两周发一次,是出于 cost vs. benefit 的权衡:

  • 每次常规发布,不管 payload(即发布的代码量)有多大,有些固定工作是逃不掉的:

  首先,由于采取了“分支开发、主干发布”的模式,代码要从各个项目分支和迭代分支合并回 master,要解决冲突,确保合并时没有漏代码。

  然后,要对 master 里的代码跑一次全量的回归:准备环境、部署代码和配置、执行回归测试用例、分析结果。这个过程做一遍,短则半天一天,长则两三天甚至更长。如果发现问题,需要修 bug,这个过程还要再重复。

  与此同时,有些团队还要写发布计划,详细列出发布的步骤:要改哪些配置,各个系统的发布顺序是什么,回滚的步骤是什么,等等。发布计;划写好了还要评审。

  最后,要走一遍发布流程:先上预发,上去以后 QA 要做预发验证;上生产环境,按照发布计划一步步做,蓝绿切流的过程中要让各个系统的 owner 确认 OK,再继续蓝绿切流。整个发布过程需要很多人的协同。

  • 在某些项目中,把代码拆成小块分多次发布会增加开发的难度和工作量。

  例如,X系统的 API 增加了一个新参数,要求Y系统在调用这个 API 的时候必须要传这个参数。如果两个系统上的代码变更一起发(而且是蓝绿发布),就比较简单。但如果把这个工作拆解成小块,开发工作就变复杂了:X的 API 新增的这个参数必须先做成 optional 的,等Y那边的代码改好发上线了以后,再把X的这个新参数改成 required。

  另外,在有些实际项目中,实际情况比上面举的这个例子更复杂,并不是那么容易一眼就能看出来怎么拆解的。  

   如何提高 Code Velocity?

  要提高 code velocity,就要对上面提到的这些原因对症下药,提升四个关键能力:

  1. 能频繁地把代码合回 master

  2. 非常强大的跑回归的能力

  3. 一键部署乃至无人值守发布的能力

  4. 把大项目拆成小项目做的能力

  提高 code velocity,要实现质的飞跃,第一个能力“能频繁的把代码合回 master”是关键抓手。把这个能力建设好了,提升 code velocity 的四个关键能力中的三个就具备了,因为“能频繁地把代码合回 master”有三个前置条件:

  1. 实行了代码门禁

  2. 有非常强大的跑回归的能力(即上面四个关键能力的第二个)

  3. 把大项目拆成小项目做的能力(即上面四个关键能力的第四个)

  代码门禁(Gated Checkin)

  代码门禁能够确保每一个进入主分支⁽³⁾的 commit 都达到了一定的质量标准,例如:编译必须通过,单元测试和接口测试必须通过,新代码的覆盖率不能低于某个水平,静态代码扫描必须通过,等等。其实今天很多公司已经有 post-checkin 的 CI 在跑这些检查项了。代码门禁看似平淡无奇,无非就是把这些检查项从 post-checkin 挪到了 pre-checkin。但别小看这一挪,它的效果,不亚于把“当月业绩决定本月提成”改成“当月业绩决定下月提成”的效果。

  代码门禁是很典型的“测试左移”的做法,和我们对质量的基本规律的认知也是一致的:问题发现得越早,修复起来代价越小。实施了代码门禁后,能确保主分支常年处于良好状态。代码门禁实施起来也很容易,很多开源和商用的 CI/CD 平台都支持,例如 GitLab+Jenkins。

  只要做得好,代码门禁是不会降低工程师的日常效率的。“做得好”的标准是:

  • 执行时间:一般能接受的是 10-20 分钟,95% 的情况下不应超过 30 分钟,否则体感就不好了。

  • False negative 率:也就是说,代码门禁如果失败,有多少比例是因为代码(包括测试用例代码)本身的确有问题,有多少是因为代码门禁的 infrastructure 的问题(比如,底层机器的资源和稳定性)。一般来说,要把 false negative 率控制在 5% 以下。False negative 率如果达到 20%-30%(也就是说,五次失败里面就有一次失败是跟提交的代码变更无关的),团队里面就会开始怨声载道了。

   非常强大的跑回归的能力

  有了强大的回归能力,就能在代码频繁的合并回 master 的情况下,仍然保持 master 分支处于可发布状态或者接近可发布的状态,有了强大的回归能力,我们甚至可以把一小部分的回归放到代码门禁里面去跑,那将会进一步有助于保持 master 分支处于可发布状态。

  回归能力的强大体现在以下几方面:

  • 无人值守:准备环境、部署代码和配置、执行测试、拿回结果,整个过程都必须没有任何人的参与。

  • 频次:跑回归不嫌多,最理想的是每次 CI 都跑回归,那样发现问题更早、定位问题更精确。

  • 覆盖率:主要是业务覆盖率⁽⁴⁾。

  • 稳定性:很高的通过率,很低的噪音率,结果非常 repeatable。

  • 执行时间:也许 6 小时和 4 小时看上去没有什么大差别,其实是有本质区别的。如果回归跑一遍要 6 小时,那么“改代码-跑回归-看结果”这个过程一天只能干两轮;但如果回归一遍只要 4 小时,那么这个过程一天就能干三轮。如果能再缩短到 2 小时,一天就能干六七轮。

  这几方面的回归能力相互之间是相辅相成的,能够形成正循环,产生“飞轮效应”:

  • 回归的运行,只有真正做到了无人值守,才有可能长期高频次运行。

  • 高频次的运行,可以充分暴露各种稳定性问题,提高回归的稳定性。

  • 缩短执行时间,一方面可以缩短“反馈弧”,加速各种稳定性问题的修复,另一方面可以提高测试环境的“周转率”,在不增加硬件成本的前提下实现更高频次的回归。

  • 提高了稳定性,可以缩短用于分析回归结果的时间。如果一个有5,000 个用例的回归用例集只有 90% 的通过率,那每次跑完回归有 500 个失败的用例需要分析

    ⁽ ⁵⁾。但如果通过率有 99%,那就只有 50 个用例需要分析了。

  强大的回归能力的背后需要的支撑能力是:

  • 优质的测试环境:要在预算允许的范围内,确保测试环境的稳定和资源充沛,这样才能支撑起回归的稳定性和高频次执行。

  • 配置代码化(configuration-as-code)的能力。今天常见的 web-based centralized 配置变更管理模式不足以支持高频词、高并发的回归运行模式。实现了配置代码化,才能实现快速的环境部署,以及在不同的环境之间用不同的配置跑回归。配置代码化并不是简单地把配置写在 config 文件里面,和代码一起打包发布。配置代码化是对这种 config 文件做法的否定之否定:配置可以在 git 里面修改;配置也可以在配置管理系统里面直接修改,变更会回沉到 git 里面。部署的时候,部署工具会把 git 里面的配置值以增量的方式推到配置管理系统里面。

   把大项目拆成小项目做的能力

  如前所述,把代码拆成小块分多次发布,的确是会增加开发的工作量的。有不少开发同学不理解为什么要这样做。增加了这些工作量,能让我们的研发模式更加敏捷。这个代价是值得付出的,这些额外的时间是值得花的。

  大项目拆成小项目做的一些常见套路包括:

  • 分两部走:先向下兼容,再去掉兼容性。这就是前文举的那个例子:X系统的 API 增加了一个新参数,要求Y系统在调用这个 API 的时候必须要传这个参数。拆成小项目的拆解方法是:首先,X的 API 新增的这个参数做成 optional 的,把X发布上线。然后等Y那边的代码改好发上线了以后,再把X的这个新参数改成 required,再发布一次X。或者,也可以用一个 feature flag 来控制这个新参数是否 required。

  • Feature flag:有了 feature flag,新功能的代码写了一半也没关系,可以把 feature flag 关掉,就算代码发上线了也不会被执行到。有时候,有些新功能所需要的代码变更是改动在老代码里面的。这样的代码变更无法用 feature flag 来屏蔽。但这也没关系,因为我们有强大的回归能力,能尽我们所能确信这些的代码变更至少不会 break 老功能、不会在发上线后造成故障。Anyway, 哪怕不是为了把大项目拆成小项目,feature flag 也是需要的。Feature flag、白名单等都是很常见的 continuous delivery 手段。

  • Capability probing:很多新功能涉及整条链路上各个系统的改造。现在往往上游系统的发布依赖于下游系统的发布。解耦这种依赖关系的一种方法是让每个系统都通过一个统一的 API 接口来暴露自己当前的能力。这样,上游系统可以判断下游系统当前是否支持某个新功能所需要的能力 Foo(例如,某种支付渠道),根据结果走不同的 code path。

  • 按域独立发布也是一种很成熟的拆分的方法。按域独立发布,实现域和域之间的解耦,能减少每次发布的系统的数量,降低发布风险,增加发布的灵活度。

  大项目拆成小项目,还需要有比较强的需求拆分的能力:能够把一个全链路级别的需求文档拆分成域级别、系统级别的需求,这样每个域、每个系统可以“分而治之”。

   Code Velocity 和质量、线上稳定性的关系

  从上面的分析可以看出来,提高 code velocity 并不是以牺牲质量为代价的。上面这些提高 code velocity 的手段,并没有 cut corner,并没有降低质量标准,并没有比今天少执行任何测试。即便是频繁的把代码合回 master,即便是把大项目拆成小项目做,该运行的各种验证和测试还是继续运行。而且,为了要提高 code velocity,实行了代码门禁,建设了强大的跑回归的能力,反而是对质量有提高作用的。

  提高 code velocity 也并不会降低线上稳定性。把大项目拆成小项目做、更加频繁的发布小块代码,能够降低单次发布的风险;发布中如果出了问题,因为 payload 小,排查和回滚也更方便。另外,在投入资源提高 code velocity 的同时,我们不会降低对故障发现能力、止血能力、应急能力、监控核对等能力的投入。提高 code velocity 不会导致线上技术风险防控体系变弱。

   将来

  如果一个团队的“能频繁的把代码合回 master”的能力做得足够好了,就可以完全抛弃项目分支和迭代分支,每一个 commit 都直接 checkin 进 master,而且 master 分支每天都有若干个可以发布的版本⁽⁶⁾,每个版本都可以用一个不同的 release 分支来保存。这就是所谓的“主干开发、分支发布”(Trunk-based Development)模式了。

  到那时候,就有做到“天天发”的能力了。那时候,代码从 commit 到上线可能平均只需要两三天时间。那时候,因为有了“天天发”的能力,甚至连紧急发布都不怎么需要了。

   【注】

  1. 一般会有两个为期四周的迭代并行,每个迭代有自己的目标发布窗口。发布窗口一般是每两周一次。

  2. “分支开发、主干发布”的开发模式来自于 A successful Git branching model。但这种模式在实践中是有不少问题的(参见 A succesful Git branching model considered harmful)。更好的模式是“主干开发、分支发布”(aka. Trunk-based Development)

  3. 主分支可以是 master,也可以是项目分支或者迭代分支。

  4. 单元测试和接口测试看代码覆盖率,回归测试看业务覆盖率。这在行业内的一部分开发和测试之间已经形成共识了。

  5. 当然,我们可以用技术的手段使得分析 500 个失败的用例变得更容易。但这并不应该成为我们不去提高通过率的理由。

  6. 版本:对于“大库模式”(monolithic repo)来说就是一个 commit,对于“小库模式”来说就是每个 repo 的一个 commit 构成的一个“截面”。

相关 [研发 团队 代码] 推荐:

如何提高一个研发团队的“代码速度”?

- - 博客园_知识库
  阿里妹导读:Code Velocity(代码速度),体现了一个研发团队快速响应业务需求的能力. 如果做得好,代码从 commit 到上线可能平均只需要两三天时间,甚至连紧急发布都不怎么需要了.   今天,蚂蚁金服国际事业群技术风险部研究员南门,将和大家聊聊 Code Velocity,希望能在团队效率问题方面,为你带来一些启发.

研发团队的绩效考核(一)

- - ITeye博客
我和大家分享的内容主要包括以下三个方面:. ① 研发团队的绩效考核的方式. ② 研发团队绩效考核KPI如何评估. ③ 如何让绩效考核发挥作用. ① 研发团队的绩效考核的方式. 很多人觉得研发团队的绩效考核很头痛,甚至不想做绩效考核,其实研发团队绩效考核我认为是需要的,因为绩效考核实际是一个“指挥棒”,它会引导研发团队朝着企业认为最佳价值的方向,通过团队/个人自己的努力达到,而不是管理者通过“管理”的方式获得,这样的效果会更好.

研发团队的绩效考核(二)

- - ITeye博客
我和大家分享的内容主要包括以下三个方面:. ① 研发团队的绩效考核的方式. ② 研发团队绩效考核KPI如何评估. ③ 如何让绩效考核发挥作用. ② 研发团队绩效考核KPI如何评估. 团队部分KPI指标的评估方式:. 每次迭代的交付物是否可以被接受:以需求提出者对本次开发迭代交付物的评价为标准,分为“接受”和“拒绝”两种.

从Rails聊聊小公司的研发团队建设

- corleone1969 - robbin的自言自语
JavaEye的PV到了140万了,一年前才100万出头,增长算不错的. 仍然是单台Web服务器,Rails处理动态请求超过340万,除了真实用户访问,还有API,RSS以及很多爬虫的请求. 看JE的alexa排名,CN排92名,全球790名,不过就2台服务器(1个web+1个DB),2个程序员而已.

Google Search By Image 中国团队完成一半以上研发

- Doublel - 谷奥——探寻谷歌的奥秘
当你郊游时,突然发现一种不知名的小花,很想仔细了解它的名称、种类和特性. “五个花瓣”、“半尺高 绿叶白花”. 这些文字肯定不能帮你准确描述出详细特征,你也不大可能凭借这些只言片语在搜索框中得到准确的答案. 确实,目前用户在使用图像搜索时经常碰到的问题是经常看到一张图片,比如一个景点或不知名的事物,想要知道它的详细信息或要找到其他尺寸图片时,文字并不能完全准确表达用户的需求.

[原]国内研发团队普遍常见问题

- - 阿朱=行业趋势+开发管理+架构
以下是国内研发团队普遍常见问题,大家说说各个岗位怎么提高质量和效率吧. 1、业务没啥清晰的战略核心主干与目标,业务需求不会解构洞察,客户提什么就做什么,业务需求和软件功能要求混在一起. 2、不会建立业务模型和产品模型,客户提什么就做什么. 3、不会理性需求排级,不做数据度量论证/也没有数据可度量/也不知道度量哪些合理数据,客户谁权力大谁态度恶劣谁叫的声大,就先满足谁的需求.

[原]敏捷开发团队管理系列之七:大型研发管理团队的切分(二)

- - 陈勇的博客 - Scrum 敏捷开发培训咨询,绩效管理,团队管理,《火星人敏捷开发手册》
这是敏捷开发团队管理系列的第八篇( 团队管理栏目目录). 还是敏捷开发一千零一问的第二十八篇( 在这里提问, 之一, 之二, 之三, 问题总目录). 还是敏捷开发松结对编程系列的第十三篇( 松结对编程栏目目录),与之前系列 第六篇139团队、 第九篇微软TechED上的讲座有密切关系.

坚果云开发团队分享高效代码审查经验

- - InfoQ cn
代码审查是软件开发中常用的手段, 坚果云开发团队最近在“ 月光博客”上撰文分享了高效代码审查的十个经验. 和QA测试相比,代码审查更容易发现和架构以及时序相关等较难发现的问题,还可以帮助团队成员提高编程技能,统一编程风格等. 代码审查首先要求团队有良好的文化,同时谨慎的使用审查中问题的发现率作为考评标准 :.

百度翻译研发500天幕后:团队曾经迷茫一个月

- Allen - cnBeta全文版
7月12日消息,百度自主投入、研发的在线翻译产品――百度翻译近日悄然上线,受到了业界和用户普遍关注. 近日百度翻译研发负责人日前独家披露产品背后的故事,称这款历时一年多时间打造的最新翻译工具,也曾遭遇过长达一个月的迷茫期. 据了解,互联网的出现为机器翻译的研发和应用带来了空前的机遇和挑战. 在中文搜索领域处于领先地位的百度,也意识到机器翻译的重要性.