Spockwang's Blog

使用Feature Flags进行并行开发和持续集成

| 评论

Introduction

在服务开发过程中经常需要一边修复线上bug,一边又要开发新特性,而且可能需要同时开发好几个新特性,不同 的新特性开发持续的时间不等。这样要等到所有代码都开发完、测试好需要很长时间,代码一直处于无法上线的状 态,无法敏捷响应需求。如果这时候线上又出现紧急bug,就没法及时发布修复。

使用feature branch的解决方案

为了防止修复bug和特性开发不相互干扰,并能及时响应线上bug,一般采用源代码版本管理系统的分支功能:

  • trunk分支是经过严格测试的稳定分支,随时处于发布状态,并与线上代码一致;
  • 每个特性可以另开一个branch开发,等到稳定后再合入trunk发布;
  • 修复bug时也开一个branch开发,验证通过后再合入trunk发布。

笔者采用这种传统的解决方案使用了一段时间,确实可以解决并行开发的问题,但是在实践中也发现了一些恼火的 问题:

  • 一个潜在的风险是合入trunk,多个特性单独测试是ok的,一旦合入就容易引起bug,所以合入trunk后还得继续 测试;
  • SVN操作比较复杂:建立分支,开发,合并trunk的更新,反向合入trunk,测试,提交trunk,删除branch。对于 新手来讲更容易出错,尤其是多人开发时需要解决冲突,严重影响效率。

使用feature flag

要解决SVN操作复杂的问题就必须停止使用branch开发,只使用trunk。但是trunk又必须保持随时可以发布的状态。 这可以借助于灰度发布的思想解决,新特性若没开发完毕可以使其代码不生效,用户看不见,待到成熟后再上线, 这可以采用开关控制其是否上线,就像一个个模块一样,可要可不要。

我们可以为每个特性取一个名字,在配置文件中控制其是否上线:

use-new-feature=true

然后在代码中这样判断:

if (config->isFeatureLaunched("use-new-feature")) {
    // 新特性代码。
    ...
}

更进一步,开关出了打开和关闭这两种状态外还可以引入中间状态,进行灰度测试:

use-new-feature=10%

意思是说对于10%的用户使用新特性,灰度测试新特性是否正常。并且在某些情况下如果出了紧急问题可以先用开 关关掉,提供有损服务。

引入feature flag后我们完全可以换个角度去看待特性开发。每个特性可以看成一个个独立的模块,可以上线也可 以下线,可从技术角度和业务角度决定是否上线,更好地降低了特性之间的耦合。

Comments