当考虑在应用程序中使用功能切换时,这个问题最让我困惑。大多数功能都需要对数据库进行一些更改。那么,如何实现功能标志,以便能够在打开/关闭功能切换的同时平稳地恢复数据库更改?尤其是当使用一些数据库迁移工具时,如flyway或liquibase。
让我们举几个例子。例如,我有一个带有Id、Name列的简单表Playlist。我想在应用程序中添加向播放列表添加描述的功能。DB表需要更改。已添加新列。列值不是强制性的。到目前为止很简单。一段时间后,该功能将从生产中关闭。解决方案很简单,但很混乱——我们可以将列留在数据库中,不再在代码中使用它。迁移工具可以增量工作,所以当我关闭功能切换时,我看不到任何恢复到以前数据库状态的选项(或者我错了吗?)。更难的例子是当字段需要是强制性的。那我就不能把那个字段留在数据库里了。它将是向后不兼容的。那又是什么呢?如何处理这种情况?我认为这是很常见的情况。
此外,即使数据库发生了轻微的更改,我的该类应用程序模型也会发生变化。(假设使用某些ORM)。这并不像用战略模式取代实施那样容易。除非您为ORM模型的使用提供了大量抽象。因此,添加这样一个功能标志似乎非常复杂。有人能帮我理解一下怎么可能使用toogles功能吗?或者可能有人有完整的例子可以展示?首选Java
功能切换是在不更改代码的情况下更改行为的一种方式,这意味着它们也与数据库模式更改无关。关闭切换应该做一些可逆的事情,比如从UI中隐藏字段,而不是像删除数据库列这样的永久性事情。考虑到这一点,您的示例看起来像:
- 发布播放列表的v1
- 在v2中,为描述添加UI,但被功能标志禁用。迁移数据库以添加新的描述列。船
- 启用功能标志。用户现在可以使用描述
- 禁用功能标志。用户不能使用描述,但它仍在应用程序和数据库中
- 在v3中,删除休眠的UI元素和逻辑。迁移数据库以删除不需要的描述列。船
同时支持同一系统的多个版本的问题是这个问题的根源,也是我正在积极思考的问题。让我们一步一个脚印!
什么是功能切换
对不起,其他答案!功能切换只需要做一件事:将功能发布与部署解耦。正如这个问题所指出的,切换是如何对任何任意更改进行切换的,这是一个棘手的问题。
一般来说,为触发器供电的系统必须满足两个条件才能被认为是完整的:
- 向后兼容性无论此切换的状态如何,旧功能都必须仍然可用。这包括此功能的旧行为
- 前向兼容性无论此切换的状态如何,新功能都必须正常运行
对于任何微不足道的更改,这都是……具有挑战性的。无论如何,这是一个词🙄
示例1:UI样式
假设您的表单的输入样式不可访问。您的工作是修复样式以使其可访问,但您使用基于主干的开发,您的团队希望在每天结束时将所有工作与项目唯一的分支master
集成。
这种变化是极其孤立的。它影响:
- 单一形式
- 无功能(即无需更改任何业务逻辑)
- 没有非功能性需求(例如,这不会引入扩展问题)
因此,根据切换状态切换加载哪个CSS样式表就足够了:
- 向后兼容性:没有任何功能受到影响,所以旧的东西默认情况下应该可以工作。关闭标志不需要特殊的行为,所以只需要简单的条件逻辑
- 前向兼容性:这比较棘手,但假设表单正确DRYed out,任何新输入都将自动继承标志指示的样式。假设关注点分离良好,对这些样式的更改不会影响任何其他组件,反之亦然
示例2:一个新的表单字段
我希望你喜欢那种美丽的简单,因为我们现在有麻烦了。这正是OP所描述的情况。
此更改跨越多个系统。它影响(至少):
- 用户体验表单
- 后端的数据API,因为有一个新的字段
- 数据库层,因为有一个新字段
这么小的差异会让事情变得更具挑战性。我们将在这里按系统进行。
用户体验形式:
- 向后兼容性:与前面的示例相同。如果这真的是一个新字段,那么旧代码就不应该在意了。此功能切换必须覆盖任何代码路径
- 前向兼容性:这里的主要问题是,某个字段可能在某一天存在,第二天当开关转回时就会消失。新逻辑可能需要在前端状态管理中设置默认值,或者由后端提供
数据API:
- 向后兼容性:此字段表示对API合同的更改。为了支持某些用例(想到验证),如果切换关闭,可能需要提供默认值。否则,旧的东西应该可以使用YMMV
- 前向兼容性:再一次,棘手的部分是确保如果关闭此切换,新代码可以使用东西。在最坏的情况下,可能需要将特殊的条件逻辑编码为新功能,以处理关闭标志的情况
数据库层:
- 向后兼容性:在数据库级别,向后兼容性要求我们只添加可选字段。需求性可以在我们的应用程序的其他地方强制执行,但如果模式添加了一个新的需求字段,就不能认为它是向后兼容的。旧的插入和更新将立即中断。因此,您的数据迁移添加了一个新的可选字段。容易吗
- 前向兼容性:好的,新代码来了。它应该期待字段吗?如果必须的话,这就是违约发挥作用的地方。注意,我没有指定应该声明默认值的内容,因为这将取决于应用程序,但必须有一些内容。在最坏的情况下,特殊的条件逻辑将不得不涵盖字段是默认字段的可能性
这听起来很疯狂!我如何保持它的可管理性
为了保持理智,有三个主要原则需要遵循:
- 保持您的更改尽可能小,并重构阻止小更改的痛点。这意味着更多的标志,但复杂性更低。渐进式改进是游戏的名称
- 将长期标志视为关键技术债务。你的旗帜不应该在生产中持续很长时间。有明确的规则来确定何时"改变";"稳定";,以及清除相关标志的清晰窗口。作为维护的常规部分,清理标志对于控制需要支持的代码路径数量至关重要
- 不要教条主义!抛开极端,必要时使用长寿命功能分支。有些更改已经太复杂了,标记的额外开销不值得。如果你遵循第1点和第2点,这种情况应该会越来越少
祝你好运!