构建功能开关:从零搭建的经验分享
我一直在进行一个项目,其中的开发速度远快于我们的QA流程。你知道那种感觉吗?每天都在部署代码,但QA和客户验收测试却是批量进行的。这就是我的现实。
当我意识到自己在避免部署一两周前编写的更改时,问题变得严重了。如果在测试后出现问题,而我已经合并了其他内容,该怎么办?是回滚所有内容?挑选提交?在生产环境着火时处理合并冲突?
功能开关似乎是解决这些头痛问题的最佳方案。
但真正的关键在于 - 我还希望某些功能能在用户级别进行配置。不仅仅是全局开关,还包括用户特定的配置。比如,我不想改变所有用户的主要行为,只想为特定测试人员调整。
那时我意识到我需要两个级别:全局控制和用户特定控制。
🎯 为什么这很重要
让我举些具体例子:
支付测试噩梦 🤑 我们想在生产环境中测试支付功能。最低时薪设置为60美元。但我不希望仅仅为了测试支付流程(可能需要多次测试)就支付那么多钱。因此我构建了用户级配置来设置最低时薪。现在我可以将其设置为1美元进行测试。这更像是动态配置而非功能开关,但机制相同。
新积分系统 💳 我们引入了应用内积分,因此支付不再仅限于Stripe。由于我将资金视为任何应用中最关键的部分,我想要一个即时关闭开关。当出现问题时关闭它,当我们有信心时再开启。
回滚地狱 🔥 在匆忙时,你总是更容易遇到错误。发布到生产环境,出现错误,你跳过了一些配置,某些功能工作方式不同。你需要回滚,但你已经合并了一堆更改。在生产事件期间处理合并冲突?这是制造更多错误的配方。
使用功能开关?只需翻转开关。不需要发布流程。
🙄 问题:发布地狱
没有功能开关的主要问题不是你不够灵活。问题是你的发布过程与部署过程紧密耦合。
要更改任何内容,你需要发布完全不同的代码版本。这意味着要经历整个测试过程。时间就是金钱,而这正在消耗两者。
这是我的日常现实:我想每天发布代码。我正在开发功能A - 比如影响用户可用性的外部日历集成。由于可用性是业务流程的核心,这很关键。
在完成此功能之前,没有安全的选项来发布每个提交。因此我堆叠所有更改,完成所有工作,按下部署按钮,祈祷它不会爆炸。
如果它真的爆炸了呢?
代码更改 → 提交 → 测试 → 发布(开发 → 测试 → 生产)→ 回到起点
我构建的替代方案是: 从一开始就将影响隐藏在功能开关后面。
|
|
从第一个提交开始,我就可以推送到生产环境,即使这个函数看起来像:
|
|
因为我只需将EXTERNAL_CALENDAR_INTEGRATION设置为False。
下一步?为特定用户将其切换为True,进行测试,如果出现问题 - 立即将其翻转回False。无需部署,无需CI,无需QA流程。只是更快更安全。
💡 我的解决方案:保持简单,保持快速
现在让我们谈谈我是如何构建这个系统的。开始时这是一个简单的机制。你可以使用外部解决方案,但让我们构建一个真正有效的自定义方案。
你需要:
- 功能开关的存储
- 用于CRUD操作的管理面板
- 在代码中使用它们的工具
在我的应用中,我使用内存事件总线和我在这里描述过的上下文模式。关键见解:功能开关是开启还是关闭?取决于谁在询问。
我将标志存储在请求全局的Context变量中。对于每个请求,在构建上下文时,我获取全局启用的所有功能开关以及特定用户的功能开关。
|
|
检查逻辑非常简单:
|
|
就是这样。用户特定标志覆盖全局标志。清晰的优先级,可预测的行为。
🎉 我实际构建的内容(诚实版)
让我实话实说 - 我称之为"功能开关",但我主要构建了一个动态配置系统。
以下是我在生产中实际使用的3个配置:
MINIMUM_TIME_REQUIRED_BEFORE_BOOKING_IN_HOURS
- 控制预订提前时间。我们设置为24小时,但测试时可以设为0CAPTIONER_HOURLY_RATE_MIN
- 允许的最低时薪CAPTIONER_HOURLY_RATE_MAX
- 允许的最高时薪
这些不是布尔标志 - 它们是类型化的配置值,我可以在不部署的情况下更改。
|
|
💭 经验教训与下一步计划
构建与购买:从自定义开始,因为它更快且实现起来不那么复杂。
缺少TTL的问题:这是我应该从一开始就实现的东西 - 自动标志过期。功能开关应该是临时的。没有TTL,它们会成为永久的技术债务。你最终会有数十个旧标志杂乱地充斥你的代码库和数据库。
在真正的功能开关系统中,每个标志都应该有过期日期。当标志过期时,它们应该:
- 自动禁用并提醒团队
- 强制进行代码清理决策
- 完全自行删除
这防止了"标志墓地"问题,即你有50多个标志,但没人记得其中一半是做什么的。
我接下来要添加的:
- 带有自动清理功能的TTL实现
- 重命名为"具有功能切换的动态配置"
🤔 轮到你了
你的配置管理是什么样的?你还在通过部署来更改单个值吗?或者你已经构建了类似的东西?
我很好奇你对用户特定配置的方法以及如何处理性能影响。
留下评论 - 我很想听听你的功能开关成功经验和灾难经历。
想要更多类似的帖子吗?我写关于实用软件架构和我们在生产中解决的实际问题。查看我关于构建事件系统或修复FastAPI中属性传递的帖子。