7

我为之工作的公司已经通过功能切换配置键进入了深层次,这些键可以根据特定条件打开/关闭特定行为。Martin Fowler 实际上将它们称为业务切换 ( http://martinfowler.com/bliki/FeatureToggle.html )。

我们有许多客户都使用相同的服务,但每个客户都希望行为略有不同。更糟糕的是,许多人希望他们的用户的某些子组看到不同的行为。因此,我们使用业务切换。切换已成为 if/else 逻辑的意大利面条球,偶尔会出现意想不到的交互。

是否有任何设计模式可用于管理此类情况?

干杯!

4

2 回答 2

4
  • 开关应该是运行时开关,而不是编译时开关。原因是,交换机应该无需重新部署即可操作。
  • 实现运行时条件逻辑有两种可能性:
    1. if-then-else(或switch-case用于多状态开关)
    2. 多态,这需要面向对象的编程语言。

我个人更喜欢使用简单的构造,并在适用时if-then-else用注释来装饰。TODO: Remove when feature has been tested.

请记住,每个功能标志都是技术债务。不要过度使用它们。我建议不要将它们用于业务逻辑。


但是,关于您的业务切换意大利面球,我建议您进行重构。

  • 任何函数的嵌套深度都不应大于 2。如果有,则拆分为具有有意义名称的多个函数。
  • 消除双重否定。
  • 德摩根定律对于重新组织条件逻辑特别有用。

如果这还不够,您可以使用图形(例如决策流程图)或矩阵对业务逻辑进行建模,并使用相应的标准算法。

于 2017-08-10T06:45:17.827 回答
2

我觉得用一个小例子更容易回答这个问题:

示例问题:您有一个组件根据一些输入进行一些计算。根据客户的不同,以下情况往往会发生变化:

  • 输入数据的来源/格式
  • 输入数据的预处理
  • 根据客户用例计算某些输出的三种不同方法 [A..C]。
  • 计算结果的输出格式。

所以工作流程可能看起来有点像这样:

预处理 -> 使用 [A..C] 风格计算 -> 格式化输出 -> 完成。

我会考虑在没有一堆配置意大利面条的情况下处理这个问题的设计是:

  1. 为每个处理步骤分类一个行为类型。在预处理步骤的示例中,这可能类似于 IInputShaper,负责将特定类型的输入数据转换为内部格式并进行一些预处理。可能这可以再次拆分:IInputFitter、IPreprocess。对于工作流程中的其他步骤,请相应地执行。这为您留下了许多行为类型的合同(这也有助于理解您的问题域。您现在可以轻松查看自由度实际来自哪里,系统有多少不同类型的行为,并且您可以保留核心实现干净。您还可以测试核心代码库,可以记录每个行为契约的要求,并且可以以单元测试方式而不是“体内”测试行为实现
  2. 根据第 1 步中定义的契约实现每个行为。在行为实现中接受一些重复的代码,而不是过度设计并试图找出这些行为之间的共性。把事情简单化。并对他们每个人进行测试。

结果:具有 0 个配置选项的行为实现集合和具有 0 个配置选项的核心代码库。最后一步是为客户项目选择行为实现,如果有特别之处,可能会编写一个新的实现。

如果你做对了,你将从此过上幸福的生活,而无需更改合同和核心系统。如果您错过了完美的设计,您将进行几次迭代,直到您找出最佳的合约接口设计,从而使您的核心代码库变得稳定。

使用这种方法,您还可以更轻松地估算工作并为新客户编写报价。您可以简单地检查报价阶段,如果您已经拥有所有行为实现,或者是否需要编写一些新的实现。而且,如果您首先跟踪编写它们需要多长时间,您甚至可以很好地猜测所需的工时。

于 2015-09-01T20:52:34.540 回答