[译]Feature Toggle - Martin Fowler

关于FeatureBranch的一个较为争论的问题是,特性分支(Feature Branch)因为待发布功能(pending features)的原因,拉长了单一发布周期(single release cycle)。可以想象一下,你每两个周发布一次生产版本,但是同时又需要去维护一个例如说三个月才能进行发布的特性分支。那么你该如何去保障团队成员们在开发主线(mainline)上的工作不受到衍生出来的、未完全实现的特性分支的影响呢?这是一个非常常见的问题,这个时候,feature toggle就是这么一个应对这种场景的便捷工具。

(曾经见过许多相同含义的概念、名词:feature bits, flags, flippers, switches等等。这在领域上似乎还没有一个统一的概念、名称。)

Feature toggle最基础的思路就是存在一个配置文件,配置文件里定义了许多的toggle,这些toggle都是待发布的特性功能。这一些toggle也正定义了哪一些features需要呈现,哪些并不需要。

这其中许多的toggle大多数都会应用在拥有用户界面的应用上,假设你构建一个网站,其中使用了jsp,你可能会使用一些jsp标签包围在需要待发布的特性功能代码前后。

1
2
3
<toggle name="petSurvey">
<p>Take our new <a href = 'petSurvey'>pet survey</a></p>
</toggle>

类似以上的代码,当你将配置toggle的开关打开之时,features的功能将会随之打开,否则将会继续忽略features功能代码。虽然不一样的UI技术实现上会存在差异,但是基础的原理都是一样的。

现实上往往还有一些特性功能,例如仅仅是引入一个新的价格算法,而这部分特性并没有对应的用户界面,纯粹是服务器端代码。对于这一情况,我们的toggle埋点可能会较为粗鲁和复杂,会直接将toggle codes耦合到系统应用层代码中,这将是比较忧虑的情况。

Toggle埋点应该以最少的埋点量,实现新特性的完全隐藏或者开放。如上图pet survey的特性,pet survey可能会有非常多的功能界面,但是入口只有一处,就是在首页的地方。也正是单一的入口,toggle的埋点只需要在该处即可,并不需要在所有相关涉及的代码各处都埋点。如此一来,之后移除toggle埋点的工作将会非常地高效。假设发现你移除toggle埋点的时间耗费的非常多,那么请关注,其中所涉及的toggle埋点是否太多太复杂了,代码结构是否已经足够规范和逻辑化。请记住,尽管简单的条件判断来设置toggle是一件非常容易的事情,但是也同时要记得使用一些类似多态替换的办法,去减少一些没有必要、过于复杂的toggle埋点的方案。

以往对于toggle的研究里,业界几乎都统称为“业务toggle”,而前面描述了那么多关于特性toggle的特点和办法,自此,可以将toggle分类为如下几种:

  1. 发布型:出现在生产环境上,用于开放或者隐藏部分特性功能的toggle;
  2. 体验型:即A/B testing,用于区分A、B方案的实际使用情况;
  3. 操作型:提供给操作员工的一系列特殊操作;
  4. 权限型:使得部分指定范围内的用户可以体验到新特性功能,而并不是面向全部用户。

大部分所见到的特性toggle都是在运行时设置的,当然,也有在编译时设置的。在编译时设置toggle,一个较小的优势是,它避免了toggle所涉及的特性功能代码被编译到生产发布的软件产品中。

Toggle不仅仅方便我们对于产品功能的管理,它也是有风险的。例如某位工程师忘了将界面UI的特性功能放置到toggle的tag闭包标签中,那么这一功能将会暴露在外,测试工作将难以进行,设置了toggle将元素隐藏的时候,并没有实际隐藏,开关功能已经处于不正确的状态下。如果这类情况在生产环境上出现,将是不可接受的。

谈到测试,大家比较关系的一个问题例如,如何对实现了toggle的系统进行测试验证?是否需要测试涉及toggle的所有场景?其实,对于一个发布型的toggle场景,只需要测试如下两类toggle使用情况:

  • 下一版本中期望实现的toggle埋点
  • 所有toggle都打开的场景

以上两点是发现多toggle集成bug的一个不错的好办法。

还有一点非常重要的,已经正式投产的toggle功能,一定要今早将toggle代码从生产环境中移除,其中不仅仅包括toggle的配置文件,还包括所有相涉及的系统toggle代码。如若不今早移除,会出现一种情况类似于,某些时候无人可以识别出某toggle是何种用途何时添加的细节情况了。一个较为清晰的案例就是,有一个需要二次编译linux内核的特殊场景,以使得可以获得更多的命令行开关的处理能力,恰巧当时就忘了这一场景,这是非常让人揪心的。

发布型toggles是你最后需要去做的事情

发布型toggles是一个非常有用的技术手段,许多研发团队都在使用它。当你要将特性功能发布到生产之时,它可能是你最后需要去做的事情。

当特性功能上线后的第一步,你需要去按照你的实际需求,打开toggle开关,使之特性功能在生产环境得以显露和使用。这种技术手段的好处在于,不需要你去频繁发布系统产品,便可以控制功能的上线与下线,更有利于在区间时间内收集真实用户的使用体验,收集用户反馈,这对于后续的产品特性功能的后续发展或者优化,都有着至关重要的作用。

如果你的的确确需要隐藏一个局部的特性功能,最好的办法是将界面UI的功能入口关闭,直至最后一次UI代码的发布。对于纯服务端的代码,也可以采用这种方式,知道最后一次发布,再打开特性功能的可见入口。

这种办法是一种优秀的可持续迭代,并且适合密集发布周期的项目。但是依然会有一些不可避免的短柄事实。前后端兼备的应用中,如此一来,在最后一次UI发布,或者后台服务端发布之前,你都将无法通过UI或者服务端入口进行toggle的测试和功能验证。当然,你也可以通过一些特殊的办法或者途径去间接地进行toggle特性的测试,例如服务端单元测试,亦或者是前端UI特性功能的某一后门入口。自然,这是不被推荐的。

总结一下,当你不希望去密集性地为了发布或者下架特性功能而频繁上线的场景下,部署toggle场景将是一个非常不错的技术手段。

进阶阅读材料

如果你想要了解本篇文章图示的feature toggles的实际应用办法,可以参考这篇文章 Pete Hodgson’s article

致谢

感谢Charles Bradley, Kent Beck and Christian Gruber通过tweets提醒我一些差点忘记的知识点。

版本

更新与2016-02-12,以适应于Pete Hodgson’s article所描述的最新细节。