部署是指代码到达生产环境时。发布是指有人可以真正使用它。混淆两者是让每次部署都变得有点紧张的最快方法之一。
feature flag 用于在这两个时刻之间留出空间。您可以今天进行部署,明天为内部团队启动,然后为试点客户,然后为 10% 的用户启动。如果出现问题,请关闭该标志。您不一定需要回滚整个版本。
标志不仅仅是一个 if
从技术上讲,它通常是 if。从文化角度来说,它的意义远不止于此。
if (await flags.isEnabled('checkout.v2.enabled', context)) { return newCheckout(input); } return oldCheckout(input);
这个小小的if可以代表逐步推出、实验、迁移、企业许可或运营kill switch。问题是,如果管理不好,它也可能成为技术债务,在代码中保留两年。
OpenFeature 是从哪里来的
OpenFeature 是一个开放规范,用于评估 feature flag 和通用 API。这个想法很简单:您的应用程序代码不应直接依赖于您用于标志的供应商或内部系统。
该应用程序询问:
const enabled = await client.getBooleanValue('checkout.v2.enabled', false, { targetingKey: user.id, plan: user.plan, country: user.country, });
提供商决定规则的来源:SaaS、文件、内部服务、flagd、GitOps 配置。如果有一天您更改了功能标记后端,则不必到处重写应用程序。
这种分离看起来像是一个建筑细节,但随着项目的发展,它会被感觉到。
上下文是成功的一半
开或关标志对每个人来说都是有用的,但有限。渐进式交付存在于上下文中:
- 内部或外部用户;
- 免费或企业计划;
- 村庄;
- 组织;
- 应用程序版本;
- 稳定的流量百分比。
重要的关键是targetingKey:必须稳定。如果它随着每个请求而变化,用户可能会在变体 A 中一次,在变体 B 中一次。对于实验来说,这很糟糕,对于结账来说,这可能是灾难性的。
明智的推出
我喜欢的流程是这样的:
- 挂旗部署;
- 开发人员和QA的点火;
- 为试点客户或租户开启;
- 5%推出;
- 推出25%;
- 100%上线; 7.删除旧代码和标志。
经常被遗忘的一点是最后一点。临时旗帜必须有死亡日期。如果它永远保留,未来的每次重构都必须问:“但是这个分支仍然有用吗?”。
Kill switch:先准备好
当外部依赖项开始困扰您、作业消耗太多资源或新逻辑产生奇怪的错误时,kill switch 是可以拯救您的标志。
一个好的kill switch必须是:
- 容易找到;
- 记录在运行手册中;
- 偶尔进行测试;
- 激活时可观察到;
- 尽可能独立于可能损坏的部分。
最糟糕的是在事故中发现旗帜存在,但没有人知道它是否仍然有效。
可观察性或非渐进式交付
在不考虑指标的情况下以 10% 的速度启用某个功能只是采取多个步骤的乐观态度。
每次推出都应该回答简单的问题:
- 错误增加了吗?
- 延迟有变化吗?
- 用户是否完成了流程?
- 还有更多票或重试吗?
- 变体是否仅影响一个部分?
OpenFeature 支持围绕标志评估的钩子。它们对于记录错误、添加指标或将评级链接到trace很有用。
命名和所有权
名字很重要。 new_ui什么也没说。 checkout.v2.enabled 说得更多。
对于每个标志,我至少会标记:
- 姓名;
- 描述;
- 所有者;
- 安全默认;
- 它存在的原因;
- 移除日期或条件。
无主旗帜几乎总是无人会清除的旗帜。
在哪里评估它们
前端、后端还是边缘?视情况而定。
如果该标志用于布局、复制或入门,则前端就可以了。如果涉及权限、计费、限制或敏感数据,则必须位于后端。如果涉及路由或高流量实验,边缘可能有意义。
简单的规则:前端可以改善体验,但它不应该是唯一的安全屏障。
结论
feature flag做得好改变了与生产的关系。它们并不能消除风险,但可以使风险更小、更易于管理。你可以分段释放、观察、停下来、返回、学习。
OpenFeature 添加了一个干净的基础:通用的 API、可互换的提供程序以及更简洁的系统扩展方式。但纪律仍然是你的:安全的默认值、清晰的名称、指标、所有者和清洁度。
最好的标志是能够帮助您平静地释放,然后在不再需要时消失的标志。