发布于 2026-01-06 3 阅读
0

如何禁用代码:开发者的生产环境终止开关

如何禁用代码:开发者的生产环境终止开关

以下是卡洛斯·舒尔茨撰写的客座文章。

很多开发者并不了解在生产环境中禁用代码的能力,这实在可惜。能够关闭代码库的某些部分,甚至是整个功能,可以显著改进软件开发流程,因为它能帮助开发者遵循最佳实践,缩短反馈周期,并提高整体质量。

所以,这篇文章将介绍以下内容:你可以使用哪些机制来执行这种关闭操作,它们的用途以及如何入门。让我们深入了解一下。

为什么要禁用代码?

在我们深入探讨功能开关之前,解释它们是什么以及如何实现之前,你可能会问:为什么人们想要关闭代码库的某些部分?这样做有什么好处?

要回答这些问题,我们需要回顾一下几十年前的软件开发历程。是时候上一堂历史课了!

黑暗时代:融合地狱

从历史上看,对于试图共同开发软件的团队来说,集成一直是最大的挑战之一。 

想象一下,公司内部有好几个团队,各自独立工作了几个月,每个团队都在开发自己的功能。由于这些团队完全孤立地工作,他们各自开发的应用程序版本朝着不同的方向发展。现在,他们需要将这些版本重新整合为一个统一的、互不冲突的版本。这是一项艰巨的任务。

这就是“集成地狱”的含义:将同一应用程序的不同版本合并起来的困难,因为这些版本已经偏离太久了。 

解决方案:持续集成

“如果做起来很痛苦,那就多做几次。” 这句话的意思是,有些问题我们因为难以解决而选择拖延。但你往往会发现,对于这类问题,在它们积累之前更频繁地解决,痛苦感会大大降低,甚至变得微不足道。

那么,如何才能让集成变得更容易呢?答案是:更频繁地集成。

这就是持续集成 (CI) 的精髓:让开发人员至少每天一次将他们的工作集成到公共共享代码库中。每次有人集成代码时,服务器都会触发构建并运行自动化测试套件。这样,如果出现问题,就能尽早发现。

如何处理部分完成的功能

持续集成(CI)中许多团队面临的一个挑战是如何处理尚未完成的功能。如果开发人员要将代码合并到主线,这意味着任何需要超过一天才能完成的开发工作都必须拆分成多个部分。 

如何避免客户访问未完成的功能?有些简单的场景可以用类似的简单方法解决,但更复杂的场景则需要不同的方法:能够完全关闭部分代码。

特色旗帜来帮忙

定义特征标志

开发者可以通过多种机制来控制代码的开启和关闭,这些机制有很多不同的名称。有些人称之为“功能开关”或“终止开关”,但“功能标志”是最常用的名称,因此本文余下部分将沿用这个名称。那么,什么是功能标志呢?

简而言之,功能开关是一种允许团队在不修改代码的情况下改变应用程序行为的技术。通常,功能开关用于阻止用户访问和使用某些代码引入的更改,因为出于各种原因,这些更改尚不适用于生产环境。

禁用代码:有哪些使用场景?

接下来,我们将介绍一些在生产环境中禁用代码的最常见用例。

关闭未完成的功能

正如你所看到的,功能标志的主要用途之一是防止用户访问尚未准备好使用的功能。

这样一来,开发更复杂、耗时更长的功能的程序员就不会因为无法经常集成他们的工作成果而从中受益。

启用 A/B 测试

采用功能标志可以在软件开发过程中使用多种有价值的实践,其中之一就是A/B 测试。 

A/B 测试是一种用户体验研究技术,它通过比较网站或应用程序的两个版本来决定保留哪个版本。具体做法是将用户随机分为 A 组和 B 组,然后分别向两组用户推送不同版本的应用程序。一组用户可能接收到当前正式版,我们称之为“对照组”,而另一组用户则会接收到新版本的候选版本,我们称之为“实验组”。 

测试人员随后观察两组用户的行为,并确定哪个版本取得了更好的结果。 

功能标志是实现 A/B 测试的实用方法,因为它可以让你快速方便地在应用程序的控制版本和处理版本之间进行切换。

启用金丝雀发布

如果一次性将新版本推送给所有用户,一旦版本出现问题,所有用户都会受到影响。那么,如果可以逐步推送新版本呢?您可以先部署给一小部分用户,并监控这部分用户以发现问题。如果出现故障,您可以回滚版本。如果一切正常,您可以逐步向更多用户发布新版本。这就是金丝雀发布(Canary Release)的精髓所在。这是功能开关(feature flags)可以发挥作用的另一种强大技术。

根据用户偏好定制功能

根据特定用户的需求定制应用程序并不罕见,软件团队可以通过多种方式来实现这一点——有些方式效率更高,有些则效率较低(例如,为每个客户创建单独的分支或整个存储库的公司)。

功能开关可以在这方面发挥作用,它允许团队动态地在同一功能的不同版本之间切换。

生产环境中禁用代码入门

如何禁用代码?接下来我们将分三个阶段逐步深入探讨这个问题。

第一阶段:最基本的方法

我们首先介绍一种非常原始的方法,这种方法或许根本不应该被视为一个功能开关。请看下面的伪代码:

calculateAdditionalWorkHours(Employee employee, Date start, Date end) {

    var result = useNewCalculation
        ? calculateAdditionalWorkHoursImproved(employee, start, end)
        : calculateAdditionalWorkHoursSameOldWay(employee, start, end);

    return result;
}
Enter fullscreen mode Exit fullscreen mode

上面的代码中,我们只是注释掉了某个方法的旧版本,并用新版本替换了它。当我们想使用旧版本时,只需反其道而行之即可。(嗯,我说过这种方法很原始。)这种方法缺少功能标志最基本的属性之一——无需修改代码即可改变应用程序的行为。

然而,这为采用更复杂的方法埋下了种子。

第二阶段:将决策从代码中移除

之前的做法不允许开发者在不修改代码的情况下选择所需的功能版本。幸运的是,这并不难做到。首先,我们引入一个逻辑变量来确定要使用的版本:

calculateAdditionalWorkHours(Employee employee, Date start, Date end) {

    var result = useNewCalculation
        ? calculateAdditionalWorkHoursImproved(employee, start, end)
        : calculateAdditionalWorkHoursSameOldWay(employee, start, end);

    return result;
}
Enter fullscreen mode Exit fullscreen mode

然后,我们使用某种机制从外部来源获取变量值并赋值。我们可以使用配置文件:

var useNewCalculation = config[newCalculation];
Enter fullscreen mode Exit fullscreen mode

向应用程序传递参数或许是另一种选择。重要的是,我们现在能够从外部修改应用程序的行为,这是朝着“真正”的功能开关迈出的重要一步。

请记住,您看到的代码示例都是伪代码。使用您喜欢的编程语言,您可以完全从这种方法入手,并在此基础上进行改进。例如,您可以使用类来表示功能,并使用设计模式(例如工厂模式)来避免使用if语句。

第三阶段:全面功能标志管理

当你的应用程序只有少量标志时,之前的方法或许足够了。但随着标志数量的增加,事情就会变得混乱不堪。

首先,你会遇到技术债务的问题。手动实现的特性开关会在代码库中造成极其混乱的条件流程。随着每天新增特性开关,情况只会越来越糟。此外,它们还会使代码更难理解和浏览,尤其对于经验不足的开发人员而言,这很容易导致 bug 的出现。

另一个问题是,随着旗帜数量的增加,越来越容易忘记删除旧的、过时的旗帜。 

自研方案的主要问题在于,它无法让你轻松地一次性查看和管理所有功能标志。因此,我们的第三阶段也是最后一个阶段的建议只有一个:与其自行开发功能标志方案,不如采用第三方功能标志管理系统

功能开关是 CI/CD 的推动因素

我们已经介绍了开发者如何在生产环境中禁用部分代码库而无需修改代码的机制。这项功能非常强大,支持 A/B 测试和金丝雀发布等技术,而这些都是现代敏捷软件开发流程的标志性特征。

这些技术的名称可能各不相同——例如功能开关、功能切换器等等。这些技术的实现方式也可能各不相同——从简单的if语句到复杂的云端解决方案。

但无论你怎么称呼它们,都不能低估这些机制带来的益处。它们是持续集成的推动者,而持续集成对于任何想要生存下去的现代软件组织来说都至关重要。

文章来源:https://dev.to/cloudbees/how-to-disable-code-the-developer-s-production-kill-switch-1bam