功能开关
2010年10月29日
支持功能分支的最常见论点之一是,它为需要超过单个发布周期的待处理功能提供了一种机制。假设您每两周发布一次到生产环境,但需要构建一个需要三个月才能完成的功能。您如何使用持续集成让每个人都在主线上工作,而不会在您的发布中显示半实现的功能?我们经常遇到这个问题,功能开关是一个处理它的便捷工具。
(虽然“开关”可能是现在最流行的术语,但“切换”仍然被广泛使用 [1]。在这篇文章中,我将交替使用这两个词。)
基本思想是拥有一个配置文件,该文件定义了一组用于各种待处理功能的开关。然后运行的应用程序使用这些切换来决定是否显示新功能。
这些决定中的大多数发生在应用程序的用户界面中。因此,如果您使用 jsp 构建 Web 应用程序,则可以使用一组 jsp 标签来包围待处理功能的任何用户界面部分。
<toggle name="petSurvey"> <p>Take our new <a href = 'petSurvey'>pet survey</a></p> </toggle>
然后,切换标签的实现仅在开关设置为开启时传递内容,否则跳过它。其他 UI 技术将使用不同的细节,但包装待处理元素的基本概念是相同的。
某些功能可能类似于引入新的定价算法,其中可能没有用户界面元素。在这里,对开关的测试将在应用程序代码中进行,它可以像条件测试一样粗略,也可以像通过依赖注入连接的策略一样复杂。
切换测试应该只出现在最少的切换点,以确保新功能正确隐藏。宠物调查功能中可能有很多屏幕,但如果主页上只有一个链接可以带您到那里,那么只有该元素需要用切换标签保护。不要尝试用开关保护新功能代码中的每个代码路径,专注于引导用户到那里的入口点,并切换这些入口点。如果您发现创建、维护或删除开关需要大量时间,那么这表明您有太多切换测试。请记住,虽然简单的条件语句是实现切换的最简单方法,但您应该使用多态替换等技术来最大限度地减少测试开关的点。
到目前为止,我已经将功能开关描述为用于隐藏部分构建的功能的东西,我称之为发布切换。霍奇森还确定了用于 A/B 测试的实验切换、用于为运营人员提供控制的运营切换以及用于控制不同用户子集的功能访问权限的权限切换。
我听说过的大多数功能开关都是在运行时设置的,但我还看到过在构建时设置发布开关的情况。构建时切换的一个小优势是,新功能的任何代码都不会被编译到已发布的可执行文件中。
功能切换的一个危险是意外暴露,当有人忘记将 UI 功能包装在切换标签中时。这很难测试,因为很难形成一个测试,即没有调用单个元素(这些元素很可能在同一时间被遗忘)的情况下,没有东西应该被隐藏是可见的。
我们听到的关于功能开关的一个常见问题是关于测试 - 使用功能开关是否意味着测试的组合爆炸?一般来说,没有必要测试所有功能组合。对于发布开关,通常运行两种组合就足够了
- 所有预期将在下一个版本中开启的开关都开启
- 所有开关都开启
这与您在使用功能分支时需要做的事情几乎相同,如果您想找到任何集成错误。
在待处理功能在生产环境中稳定下来后,退休发布开关非常重要。这包括从配置文件中删除定义以及使用它们的代码。否则,您将获得一堆没有人记得如何使用的切换。在一个我听说过的难忘的例子中,它需要对 Linux 内核进行特殊重新编译才能处理足够的命令行开关。
发布开关是您应该做的最后一件事
发布开关是一种有用的技术,许多团队都在使用它。但是,当您处理将功能投入生产时,它们应该是您的最后选择。
您的首选应该是将功能分解,以便您可以安全地将功能的一部分引入产品中。这样做的好处与任何基于小型、频繁发布的策略相同。您降低了出现问题风险,并获得了有关用户实际使用功能的宝贵反馈,这将改进您以后进行的增强。
如果您真的必须隐藏部分构建的功能,那么最好的方法是使用基石接口:构建所有内容,除了 UI 入口点,并在单个发布周期中添加该 UI。这样,非 UI 代码就与其他所有内容完全集成,但在您最后添加最后一点之前,没有任何内容可见或使用。
只有在您无法进行小型发布或基石接口时,才应该使用发布开关。
进一步阅读
有关功能开关及其用法的详细说明,请查看皮特·霍奇森的文章。
致谢
(感谢查尔斯·布拉德利、肯特·贝克和克里斯蒂安·格鲁伯的推文,提醒我一些我忘记包含的要点。)
修订
2016-02-12 更新,以适应皮特·霍奇森的详细文章。2023-07-14 更改了 URL 和标题为“功能开关”,并替换了文本中的许多使用“开关”。注释
1: (2023 年 7 月)当皮特和我最初在 2010 年代中期撰写博客文章和文章时,“开关”和“切换”都被使用;以及功能位、翻转器、开关等等。从那时起,“开关”似乎已成为最常见的术语,但我们仍然看到“切换”的使用频率相当高。