我们团队第一次大规模用特性开关,动机很朴素:新功能没测完,又要赶发布节点,就加一个开关,先关着上线,测完了再打开。
这套用法用了大半年,没出过大问题。直到有一次,我写了个「清理陈旧开关」的脚本,图省事,把三个月没人碰过的开关全删了——包括一个我以为早就该转正、其实还在被某个边缘客户依赖的开关。
那次事故让我重新想了一遍:特性开关到底是什么。
一、它不是「临时的 if」,是一层正式接口
事故复盘时我才看清楚:那个开关从技术上看只是一个 if enabled:,但从产品角度看,它是某个客户和我们之间一份没写在合同里的约定——「这个功能对你是关的」。
把它当成临时代码,就会用临时代码的心态去维护:随手加、随手删、没有文档、没有负责人。把它当成接口,你就会自然而然地问:谁在用?什么时候可以下线?下线前要不要通知?
这个心态转变,比任何工具都重要。
二、开关要分类,而且类别决定生命周期
事故之后,我们把开关分成了四种,每种有不同的默认寿命:
- 发布开关(Release Flag):功能没测完时用,上线后应该在几周内转正或删除。这类开关如果活过一个季度,就该被巡检工具标红。
- 实验开关(Experiment Flag):A/B 测试用,生命周期跟着实验走,实验结束当天就该清理,不该拖到「有空再说」。
- 权限开关(Permission Flag):控制某个功能对谁可见,这类开关可能长期存在,是正常的产品配置,不是技术债。
- 应急开关(Kill Switch):出问题时能一键关掉某个功能,这类开关故意长期存在,而且要定期演练——一个从没被真正触发过的应急开关,你不知道它到底能不能用。
我删掉的那个开关,本该归类成权限开关,却被我的清理脚本当成了发布开关处理。分类错了,清理规则就全错了。
三、给每个开关配一个「到期提醒」,别指望人会记得
发布开关和实验开关最大的问题是:加的时候都说「这是临时的」,但没人会主动想起来去删它。
现在我们要求每个开关创建时必须写一个预计下线日期,到期前一周自动开一张工单提醒负责人。不是不信任自己会记得,是承认没有人会记得——包括我自己。这条规则实施半年后,我们的开关总数从 340 个降到了 90 个出头,剩下的大部分都能说清楚自己为什么还活着。
四、别把「关闭」和「删除」混为一谈
另一个我踩过的误区:以为一个开关被永久关闭,就等于可以安全删除背后的代码。
不对。一个开关被关闭,只说明当前没人走那条路径,不代表那条路径没有价值、或者可以放心清理。真正安全的删除顺序应该是:先确认没有活跃依赖 → 关闭开关一段时间,观察是否有人反馈 → 再删除开关本身 → 最后才清理背后不再可达的代码。跳过中间的观察期,就是我那次事故的直接原因。
现在每次我加一个新开关,都会先问自己一句:这是四类里的哪一类?它的下线条件是什么?
答不上来,就说明我还没想清楚要不要加这个开关——这本身就是一个有用的信号。


SERVICES.waline即生效。想说话可以先去 留言板,那边我每条都回。