Feature flag 发布说明:该说什么,又该什么时候说
阅读约 1 分钟
给一条功能请求关闭反馈闭环,默认的前提是存在一个干净利落的时刻,那个东西就是在那一刻被真正发布出去的。Feature flag 恰恰抹掉了这个时刻,这也正是 feature flag 发布说明难以把握时机的原因。代码合并了,flag 也已经存在了,但接下来的好几天甚至好几周里,这个功能会同时处于两种状态:它已经在生产环境里活生生地跑着,同时又对几乎所有可能想用它的人都不可见,而这些人里,往往就包括最初提出这个请求的那个人。通知得太早,会让对方一头撞上一个根本还不存在的功能。通知得太晚,则会让本来应该建立信任的这个反馈闭环,读起来反倒像是被遗忘了。
为什么 flag 会打破”发布了,就通知”这套惯常的顺序
因为它把一个事件,硬生生拆成了至少两个:代码变成上线状态,和 flag 为某个特定账户被打开,这是两件事。任何一套关闭反馈闭环的流程,默认都假设这两件事是同时发生的,这个假设对大多数常规发布来说是成立的,但对任何藏在用于灰度发布、定向投放、或者作为紧急熔断开关的 flag 背后的东西来说,这个假设是不成立的。关闭客户反馈闭环 里描述的做法,是恰好在一条体验日志记录被批准并发布的那一刻,去通知提出请求的那个人;那一步的设计前提,是发布这条记录和这个功能变得可用,正好是同一个时刻,而 flag 恰恰就是这两者不再是同一个时刻的那种情况。
| 时刻 | 事实是什么 | 是不是已经该通知提出请求的人了 |
|---|---|---|
| 代码已合并,flag 在所有地方都是关闭的 | 功能已经存在,但没人能用 | 不该 |
| Flag 为提出请求那个人的账户打开了 | 功能已经存在,这个具体的人可以用它了 | 该 |
| Flag 为某个把这个人排除在外的灰度百分比打开了 | 功能已经存在,这个人依然用不了 | 不该 |
| Flag 已经被彻底移除,功能就这么直接开着了 | 功能对所有人都存在了 | 该,如果还没通知过的话 |
到底该在什么时候通知某个人,这条真正的规则是什么
在 flag 为对方的账户打开的那一刻通知,而不是在代码合并的时候,也不是在 flag 被创建的时候。这一条规则,就足以覆盖上面表格里的每一行,因为它把通知这件事,绑定在了唯一一个对提出请求的人来说真正重要的事实上:他现在,此刻,能不能真的去用那个东西。一条绑定在代码合并或者 flag 创建那一刻的通知,实际上是一份工程进度报告,而一个提出了功能请求的人,要的从来不是进度报告,他要的是知道自己什么时候该去看一眼。
这是不是意味着提出请求的人需要提前获得或者特殊获得访问权限
不一定,而且硬性要求这么做,反而会制造出它自己的新问题。如果 flag 是出于负载或者稳定性的考虑而逐步灰度放量的,仅仅为了更快关闭一条反馈闭环,就把某一个账户塞到队伍最前面,这恰恰破坏了这次灰度发布之所以要分阶段进行的初衷。诚实的选项只有两个:要么等提出请求的那个账户自然而然地被灰度覆盖到,到那时候再通知,要么,如果紧迫程度真的能站得住脚,就有意识地提前为这个人打开 flag,把这当成灰度发布的负责人做出的一个真实决定,而不是想要发一条通知这个念头带来的副作用。
如果这个 flag 是一个紧急熔断开关,而不是一套灰度发布机制呢
那么安全的默认假设就要反过来了。一个设计初衷是为了能快速关掉某个功能,而不是为了把发布过程分阶段推进的 flag,通常意味着这个功能本来就该在创建的那一刻起就完全上线,flag 存在是出于安全考虑,而不是出于顺序上的考虑。在这种情况下,在部署那一刻就通知提出请求的人是正确的做法,跟任何一次没有 flag 的常规发布完全一样;flag 的存在只是一个运营层面的细节,不应该改变反馈闭环到底该在什么时候关闭。真正重要的区别在于这个 flag 到底是为了什么而存在的,而不是它到底存不存在。
Flag 会改变 feature flag 发布说明本身应该写的内容吗
它改变的是这条记录发布的时机,而不是它包含的内容。一条恰好在 flag 为 100% 的账户打开那一刻发布的记录,读起来会跟一条普通的体验日志记录一模一样,而这本来就是对的;一个日后才找到这条记录的读者,完全没有理由需要知道这里面曾经涉及过一个 flag。它不应该做的,是在 flag 只为一小部分灰度百分比打开的时候就被发布出去,因为一条公开的体验日志记录,会让每一个读到它的人,包括那些没有这个 flag 的账户,都跑去寻找一个他们根本找不到的功能,这其实是同一个问题的一个更糟糕的版本,只是规模从一个提出请求的人,放大到了整个产品。这条时机上的规则,正是 feature flag 发布说明和一条普通条目之间唯一的区别:内容完全一样,变的只是发布的那个日期。怎样写发布说明 讲解了同样适用于这里的”不需要任何操作”这条纪律:读者需要知道的是这件事到底跟自己有没有关系,而不只是知道它在某个地方存在这个事实本身。
产品更新邮件是不是应该对一个带 flag 的功能区别对待
应该,而且主要是通过推迟发送,而不是重写内容来实现。产品更新邮件模板 讲解了定向通知跟大范围摘要邮件之间的区别;一个带 flag 的功能,恰恰是这样一种情况:一条定向通知发送之前,必须先跟接收者自己的 flag 状态核对一下时机,而这件事,一份大范围的摘要邮件根本没法轻易做到。这也是为什么,对任何还处于灰度发布中途的东西来说,摘要邮件都是一个错误的渠道的又一个理由。
FAQ
Flag 已经存在、但还没为某个人打开的时候,是不是应该告诉提出请求的人他的功能”即将上线”? 只有在真的有一个明确、临近的日期时才应该这么说,而且就算这样也要谨慎使用。一句没有日期的”即将上线”,在过了足够长的时间之后,读起来跟彻底沉默没什么两样,而且还会额外制造出第二个同样需要被追踪、被兑现的承诺。
到底该由谁来判断一个 flag 的进度是不是已经足够,可以关闭反馈闭环了? 应该由灰度发布的负责人来判断,而不是由通知的负责人来判断。掌握灰度发布进度的人,才知道”100% 的账户”到底是近在眼前,还是还要再等好几周;把关闭反馈闭环这一步,绑定在灰度发布的实际状态上,而不是绑定在一个固定的日历日期上,才能让通知本身保持诚实。
藏在一个永久性 flag(从来不会被彻底移除的那种)后面的功能,会不会有拿到一条公开体验日志记录的那一天? 会,一旦它达到了这个产品语境下”全面可用”所代表的那个状态就会有,哪怕这个 flag 本身出于运营上的原因,会永远留在代码里。体验日志记录关心的,是这个功能对读者来说到底能不能用,而不是这种可用性到底是通过什么实现细节达成的。
如果 flag 被移除了,而这个功能是被彻底砍掉、而不是被真正发布出去的呢? 那属于一次拒绝,而不是一条发布通知,它值得跟任何其他一次拒绝同样的用心对待。该怎样拒绝一个功能请求 讲解了那条消息到底该说些什么;诚实地关闭一个反馈闭环,有时候意味着用一句”不做”来关闭它。
Feature flag 发布说明需要一套跟普通条目不一样的模板吗? 不需要换模板,只需要在发布之前多加一道检查关口:核对的是提出请求的那个账户的 flag 状态,而不只是核对代码有没有合并,并且把这条记录一直压着,直到那道检查通过为止。除此之外,条目的其他一切,措辞、长度、FAQ 的规范,都跟任何一条普通的发布说明完全一样。
本文的技术内容未经独立审核。如有错误,请告诉我们,我们会更正。