功能开关何时有意义与何时无意义

Hacker News Top 工具

摘要

一位软件工程师讨论了功能开关在何种情况下有意义,例如用于A/B测试和复杂部署,并提醒团队在能够控制部署时不要过度使用它们。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/08/09 02:23

# 功能开关在何时合理、何时不合理 来源:https://software.rajivprab.com/2019/12/19/when-feature-flags-do-and-dont-make-sense/ [](https://www.redbubble.com/i/canvas-print/If-Else-Software-Developer-Joke-Beer-Lover-by-VaSkoy/33140544.5Y5V7) 过去几年里,我在多个团队工作过,这些团队在功能开关(feature flags)方面采用了截然不同的策略。我看到了两者的优缺点,随着时间推移,我发现自己对任何关于功能开关的“原教旨主义”立场都不敢苟同。这个话题有很多微妙之处,我认为值得更仔细地审视一下功能开关在哪些场景下合理、在哪些场景下不合理。 ## 支持的理由 功能开关在几个主要场景中非常合理。首先是用于 A/B 测试(https://en.wikipedia.org/wiki/A/B_testing),在这种情况下,你确实希望根据用户被随机分配到的实验组,对不同用户表现出不同的行为。我在 Amazon 看到过这种策略被运用得极为出色——新功能通过一个实际上由内部 A/B 测试框架控制的“功能开关”来门控。该框架随机让一部分 Amazon 客户看到新功能,然后监控他们后续的行为,以评估该功能上线带来的商业影响。 我最初持怀疑态度,但很快就被该框架的易用性以及它在某些功能的收益(或弊端)方面提供的宝贵洞见所折服。“流行一时”的拍脑袋决策被真实数据所取代。而这一切若没有“功能开关”来动态切换新功能,是不可能实现的。 --- 功能开关的另一个绝佳用例是:当你正在开发一个非常复杂的史诗级任务,需要系统不同部分完成许多不同的子任务时。这些子任务数量过多、侵入性过强,无法在单个 pull request 中完成。 在这种情况下,试图将这些分散的改动保留在侧分支中,并协调一次同步合并和部署,简直是灾难的配方。更可控的做法是:将所有破坏性改动都置于一个主开关之后,增量合并和部署所有子提交,等所有部件就位后再进行一次“拨动开关”。 --- 功能开关的最后一个用例,是当你无法掌控自己的部署时。例如,考虑 Facebook 的 Android 应用,它包含数百个不同团队贡献的代码,全部合并后作为一个单一二进制文件部署。在这种情况下,执行回滚可能是不可行的,无论是出于实际、政治、官僚甚至营销原因。此时,功能开关可以让你的团队切换新功能或缓解有风险的改动,而无需回滚或部署任何新的二进制文件。 *有人在 Reddit 上指出(https://www.reddit.com/r/programming/comments/i5zbvk/when_feature_flags_do_and_dont_make_sense/)一个类似的功能开关用例:出于营销原因瞄准一个非常具体的发布日期,同时更早地部署代码以确保稳定性。然后你可以有一个“动态”功能开关,在特定时间自动启用。这也是一个很好的用例,原因类似——在部署新二进制文件不切实际的情况下改变功能。* ## 风险规避 以上都是功能开关的绝佳用例,但我也见过团队被过度使用功能开关的政策拖累。例如,强制要求每一处代码改动都必须放在功能开关后面,“以防万一我们犯了错误”。 风险管理确实应该成为所有团队的优先事项。但除了依赖功能开关之外,还有更好的方法,尤其是当你的团队能够控制自己的部署时。绝大多数 bug 应该由你的自动化测试套件(https://software.rajivprab.com/2019/04/28/rethinking-software-testing-perspectives-from-the-world-of-hardware/)和/或 QA 流程捕获。而那些最后的漏网之鱼,应该通过增量部署、生产环境告警和回滚来处理(https://software.rajivprab.com/2019/11/25/the-birth-of-legacy-software-how-change-aversion-feeds-on-itself/)。 此外,一旦检测到任何问题,Google 等地方的建议是:先回滚,之后再调查问题(https://cloud.google.com/blog/products/gcp/reliable-releases-and-rollbacks-cre-life-lessons): > *我们在 Google 已经无数次看到这种情况:一个匆忙部署的“向前修复”(roll-forward fix)要么无法修复原始问题,要么反而让事情变得更糟。即使它修复了问题,也可能随后暴露出系统中其他潜在 bug;你会把自己带离已知的良好状态,进入一个未经常规严格 QA 测试的发布版本荒野。在 Google,我们的理念是“回滚是正常的”。当在新发布中发现错误或合理怀疑存在错误时,发布团队先回滚,再调查问题。* 当事情火烧眉毛时,你最不想做的事情就是去追根溯源找出 bug,并弄清楚拨动哪个开关才能安全地解决问题。而且这甚至不一定能解决问题——即使你的同事试图把他的改动放在功能开关后面,也不能保证他不会无意中引入一个无法通过拨动开关解决的 bug。 功能开关是二进制回滚的一种“穷人替代方案”,而且它们绝对无法替代一个优秀的自动化测试套件和稳健的 QA 流程。如果你正在依赖功能开关来修复生产环境 bug,你应该停下来评估一下你团队的做法。风险规避往往是你的团队进入恶性循环的一个信号,这种情况只会随着时间推移越来越糟(https://software.rajivprab.com/2019/11/25/the-birth-of-legacy-software-how-change-aversion-feeds-on-itself/)。 ## 被功能开关拖死 在这一点上,你可能会想,为什么我们无论如何都不使用功能开关呢?毕竟,“纵深防御”……而且拥有更细粒度的灵活性总不会有什么坏处吧? 虽然功能开关在某些情况下很好用,但我们也要记住它们的成本。软件工程本质上是一项管理复杂性的练习。每一个功能开关都会立刻让你的程序员需要理解的、以及你的代码需要处理的边界情况数量翻倍。*“但如果 Foo 启用、Bar 禁用,而我们同一天在 Baz 和 Kaz 上做独立的 A/B 测试,会发生什么?”* 根据我的经验,这种组合爆炸式的复杂性可能导致 bug——而且**确实会**导致 bug。更不用说它还会拖慢你的团队进行任何改动的速度。 引用一段网上分享的有趣轶事(https://news.ycombinator.com/item?id=24549917):*“一个已经一年没有关闭的开关,可能掩盖着一个重大的回归问题。在我上一份工作中,两年内发生了两次重大事故,都是因为功能开关系统未能返回开关状态时,废弃的开关默认设置为‘关’。”* *“但这些功能开关只是临时的。你应该尽快把它们移除!”* 当然,我们也应该不允许技术债务累积,还应该虔诚地遵守每一条最佳实践。不幸的是,这在任何企业环境中都不会发生。即使在优秀的团队中,面对不断出现的新需求,技术债务也常常被降级处理。团队中的新人或即将离开的人,并不总是足够自律,能够在成功上线后清理他们的开关。有时,这些任务只是从缝隙中溜走,然后被遗忘。 有人在 Hacker News 上指出(https://news.ycombinator.com/item?id=24549917),截至 2020 年 9 月,Windows 的发布版本*“大约有 2500 个功能开关。有些被永久地卡在开启位置,有些卡在关闭位置,其余的可由其实验框架和黑客配置”*。 最生动的例证莫过于 KCG 事件——一家金融公司在 30 分钟内损失了 5 亿美元,几乎破产,部分原因就是藏在功能开关后面的死代码。 > *失败的原因*(https://www.bugsnag.com/blog/bug-day-460m-loss)*包括多个因素。但其中一个最重要的因素是,一个曾经用于启用 Power Peg 的开关……Power Peg 自 2003 年起就已过时,却在八年之后仍然保留在代码库中。* *2005 年,对 Power Peg 代码做了一次修改,无意中禁用了本可防止这种场景发生的安全检查。然而,当时这个更新被部署到了生产系统,尽管没有做任何努力去验证 Power Peg 功能是否仍然有效。* --- 功能开关是一个强大的工具,可以帮助你试验新功能、管理复杂史诗级任务的上线,并缓解由于无法掌控团队部署而带来的问题。 但它们也伴随着巨大的成本,表现为代码复杂性、技术债务、开发速度变慢,以及不可避免的 bug。 尽管这很诱人,但这里没有银弹。权衡利弊,并在有意义的情况下明智地使用这个工具。 --- */r/programming 讨论帖*(https://www.reddit.com/r/programming/comments/i5zbvk/when_feature_flags_do_and_dont_make_sense/)*Hacker News 讨论帖*(https://news.ycombinator.com/item?id=24549917)*发表在 Golem.de*(https://www.golem.de/news/softwareentwicklung-wann-feature-flags-sinnvoll-sind-und-wann-nicht-2104-154494.html)

相似文章

OpenFeature - 为所有人标准化特性标志管理

Lobsters Hottest

OpenFeature 是一个用于特性标志的开放规范及社区驱动的 API,旨在跨不同工具和供应商标准化特性标志管理,避免供应商锁定。它是一个开源的 CNCF 孵化项目。

Cloudflare Flagship

Hacker News Top

Cloudflare 发布了 Flagship,这是一项功能标记服务,允许开发者在不重新部署的情况下控制功能可见性,支持原生 Workers 绑定和 OpenFeature 兼容性。

平台工程仍然重要

Lobsters Hottest

一篇观点文章,认为即使有了AI编码工具,平台工程和代码复用仍然有价值,因为token需要成本,而复用能带来杠杆作用。文中引用了Martin Fowler关于重构的类似论点。