Welcome

首页 / 软件开发 / 数据结构与算法 / 详解使用功能开关更好地实现持续部署

详解使用功能开关更好地实现持续部署2013-10-05 infoq 崔力强为了快速发布开发完成的功能,现代的互联网企业通常会以比较快的迭代周期来持续的发布。但是有时候因为技术或者 业务上的原因,需要在发布的时候将某些功能隐藏起来。一种解决方案是,在独立的分支上开发新功能,全部开发测试完成 之后,才合并回主干,准备发布。这也就是我们经常提到的功能分支(feature branch)。本文将介绍如何使用功能开关( feature toggle)来更好地解决这个问题,及其在一个典型Spring web应用程序中的具体实现,最后讨论了功能开关和持续 集成如何协同工作。

功能分支的问题

功能分支可以帮助我们同时开发多个新功能,而不对发布的节奏造成影 响,这解决我们一开始提到的那个持续发布的需求,但是它也会引入很多问题。在Martin Fowler的文章中已经很全面的阐 述了这些问题,简单总结如下:

分支分出去时间长了往主干合并的时候会出现很多的代码冲突。

在一个分支中修改了函数名字,但是如果在其它分支中大量使用修改前的函数名,则会引入大量编译错误。这点被称为 语义冲突(semantic conflict)

为了减少语义冲突,会尽量少做重构。而重构是持续改进代码质量的手段。如果在开发的过程中持续不断的存在功能分 支,就会阻碍代码质量的改进。

一旦代码库中存在了分支,也就不再是真正的持续集成了。当然你可以给每个分支建立一个对应的CI,但它只能测试当 前分支的正确性。如果在一个分支中修改了函数功能,但是在另一个分支还是按照原来的假设在使用,在合并的时候会引入 bug,需要大量的时间来修复这些bug。

功能开关

下面我们来看看功能开关是如何解决上述的问题的。

第一原则,代码库中不再引入任何分支, 所有的代码都提交到同一个主线(mainline),在开始开发一个新功能的时候,引入一个布尔值的配置项,使得在该配置项 为假时,应用程序的外部行为和没有引入该功能之前保持一致;而在配置项为真时,应用程序才展现出那些新开发的功能。

实现的方式也很直观。在所有跟该功能相关的代码中都会读取该配置项的值,如果配置项值为真,则使用新功能, 如果为假,则保持以前的逻辑。我们把在某处代码使用到该布尔配置项称为该处代码使用了该开关。

对于一个典型 的Spring的web项目,代码库中会包括Java代码、JSP代码,IOC配置文件,还有CSS和JS文件。这些都是代码,根据不同的业 务需求,这些代码都有可能会用到开关。为了能够在这些代码中方便地获取开关的值,使用开关,我们需要一些基础设施来 支持。

如上图所示。需要在“功能开关”的模块中实现所需要的基础设施,然后配合配置文件的内容来对应用程序的行为进行 控制。下面我们就配置文件和基础设施做一些讨论。