规则引擎-利弊

我正在审计一个使用 规则引擎的项目。简而言之,它是将业务逻辑从应用程序代码外部化的一种方法。

这个概念对我来说是全新的,我对此持怀疑态度。在过去几年听到人们谈论 贫血领域模型之后,我开始质疑规则引擎方法。在我看来,它们似乎是削弱域模型的一个很好的方法。例如,假设我正在做一个与 Rules Engine 交互的 java Web 应用程序。然后我决定我想要一个基于同一个域名的 Android 应用程序。除非我希望 Android 应用程序也与规则引擎交互,否则我将不得不错过已经编写的任何业务逻辑。

由于我还没有任何使用规则引擎的经验,只是出于好奇,我有兴趣了解使用规则引擎的利弊?我能想到的唯一优点是,您不需要仅仅为了改变某些业务规则而重新构建整个应用程序(但实际上,有多少应用程序真的有那么多变化?).但是使用规则引擎来解决这个问题在我看来就像在猎枪伤口上贴创可贴一样。

更新——自从写下这篇文章以来,上帝马丁 · 福勒(Martin Fowler)就拥有了 关于使用 Rules 引擎的博客

41789 次浏览

我所见过的规则引擎最大的优点是,它允许 Business Rule 所有者实现业务规则,而不是将责任推给程序员。即使你有一个敏捷的过程,你不断地从利益相关者那里得到反馈,并且经历快速的迭代,它仍然不能达到通过让制定业务规则的人实现它们所能达到的效率水平。

另外,如果规则嵌入在代码中,删除可能由简单的规则更改导致的重新编译-重新测试-重新部署周期的价值也不能低估。通常会有几个团队参与到对构建进行祝福,而使用规则引擎可以使其中的大部分变得不必要。

在某些情况下,规则引擎可以提供很多价值。

首先,许多规则引擎以更具声明性的方式工作。一个非常粗略的例子是 AWK,您可以将正则表达式分配给代码块。当文件扫描器看到正则表达式时,将执行代码块。

在这种情况下,你可以看到,如果你有一个大的 AWK 文件,你想添加另一个“规则”,你可以很容易地到文件的底部,添加你的正则表达式和逻辑,并完成它。具体来说,对于许多应用程序来说,您并不特别关心其他规则在做什么,而且这些规则并不真正互操作。

因此,AWK 文件变得更像一个“规则汤”。这种“规则汤”的特性使人们能够非常紧密地关注他们的领域,几乎不关心系统中可能存在的所有其他规则。

例如,弗兰克对总额超过1000美元的订单感兴趣,所以他把他感兴趣的规则系统。“如果订单总数 > 1000,那么发邮件给弗兰克”。

与此同时,Sally 想要西海岸的所有订单: “ IF order. source = = ‘ WEST _ COAST’THEN email Sally”。

所以,你可以看到在这个微不足道的,人为的情况下,一个顺序可以满足这两个规则,但是这两个规则是相互独立的。一份来自西海岸的1200美元的订单通知了弗兰克和莎莉。当弗兰克不再担心的时候,他会简单地把他的规则从汤里拉出来。

对于许多情况,这种灵活性可能非常强大。它也可以像本例一样向最终用户公开简单的规则。使用高级表达式,或者使用轻量级脚本。

现在,很明显,在一个复杂的系统中,有各种各样的相互关系可能发生,这就是为什么整个系统没有“完成规则”。总会有人在某个地方负责制定规则,不让规则失控。但这并不一定降低这样一个系统所能提供的价值。

要知道,这甚至没有涉及到专家系统之类的东西,在专家系统中,规则会触发规则可以创建的数据,而是一个更简单的规则系统。

无论如何,我希望这个示例能够展示规则系统如何帮助扩展更大的应用程序。

它(就像其他所有事情一样)取决于您的应用程序。对于一些应用程序(通常是那些永远不会改变或者规则在现实生活中是最好的,也就是说永远不会明显改变,例如物理属性和公式) ,使用规则引擎是没有意义的,它只是引入了额外的复杂性,并要求开发人员拥有更大的技能集。

对于其他应用程序来说,这确实是个好主意。以订单处理为例(订单是从发票到货币交易处理的任何事情) ,不时有一些相关法律或法规(在司法意义上)的微小变化,要求你满足一个新的要求(例如销售税,一个经典)。 与其试图强迫旧的应用程序进入这种突然需要考虑销售税的新情况,而不是像以前那样,更容易调整规则集,而不是不得不干预潜在的大量代码集。

然后,当地政府的下一个修正案要求在一定的标准内报告所有的销售情况,而不是你必须进去补充这一点。最终,你会得到非常复杂的代码,当你转身想要恢复某一条规则的效果而不影响其他规则时,这些代码将被证明是非常难以管理的。

到目前为止,每个人都对规则引擎非常积极,但我建议读者保持警惕。当一个问题变得稍微复杂一点时,您可能会突然发现整个规则引擎已经变得不适合,或者比使用更强大的语言复杂得多。此外,对于许多问题,规则引擎将无法轻松检测大大减少评估条件的运行时和内存占用的属性。在相对较少的情况下,我更愿意使用规则引擎而不是依赖注入框架或者更动态的编程语言。

“但说真的,有多少应用程序真的有这么多变化?”

老实说,我开发的每个应用程序都经历了严肃的工作流程和/或从概念到部署之后的逻辑变化。这是编写“维护”程序的首要原因。

事实上,你不可能事先考虑所有的事情,因此才有了敏捷流程。此外,BA 似乎总是错过一些重要的东西,直到在测试中发现。

规则引擎迫使您真正地将业务逻辑与表示和存储分离开来。此外,如果使用正确的引擎,BA 可以根据需要添加和删除逻辑。正如克里斯•马拉斯蒂-格奥尔格(Chris Marasti-Georg)所说,这让英国航空承担了责任。但更重要的是,它允许英航得到他们想要的东西。

我为一个客户编写了一个规则引擎。最大的胜利是包括了所有的利益相关者。引擎可以运行(或重播)一个查询,并解释在文本中发生了什么。业务人员可以查看文本描述并快速指出规则、异常和其他特殊情况中的细微差别。一旦业务方参与进来,验证就会变得更好,因为很容易获得他们的输入。此外,规则引擎可以独立于应用程序代码库的其他部分,因此您可以跨应用程序使用它。

缺点是有些程序员不喜欢学太多东西。规则引擎和您放入其中的规则,以及实现它们的工具,可能有点复杂。虽然一个好的系统可以很容易地处理病态和扭曲的逻辑网络(或经常不合逻辑;) ,但它不像编码一堆 if语句那么简单(不管一些头脑简单的规则引擎做什么)。规则引擎为您提供了处理规则关系的工具,但是您仍然必须能够在头脑中想象所有这些。有时就像生活在电影 巴西里。:)

我见过的大多数规则引擎都被系统代码视为一个黑盒子。如果我要构建一个域模型,我可能希望某些业务规则是域模型固有的,例如,业务规则可以告诉我对象的值是否无效。这允许多个系统共享域模型,而无需重复业务逻辑。我可以让每个系统使用相同的规则服务来验证我的域模型,但是这似乎削弱了我的域模型(正如在问题中指出的那样)。为什么?因为我没有始终在所有系统中一致地执行业务规则,而是依靠系统程序员来确定何时应该执行业务规则(通过调用规则服务)。如果完全填充了域模型,那么这可能不是问题,但是如果您正在处理的用户界面或系统在域模型的生命周期内更改了域模型中的值,那么这可能是问题。

还有另一类业务规则: 决策制定。例如,保险公司可能需要对承保申请人的风险进行分类,并得出保险费。您可以将这些类型的业务规则放在您的域模型中,但是对于这样的场景,集中决策通常是可取的,而且实际上非常适合于面向服务的体系结构。这确实回避了一个问题: 为什么是规则引擎而不是系统代码。规则引擎可能是更好的选择的地方是负责决策的业务规则随时间变化的地方(正如其他一些答案所指出的)。

规则引擎通常允许您在不重新启动系统或部署新的可执行代码的情况下更改规则(不管您从供应商那里得到了什么承诺,一定要确保您在非生产环境中测试您的更改,因为即使规则引擎是完美的,人类仍然在更改规则)。如果您在想,“我可以通过使用数据库来存储变化的值”,那么您是对的。规则引擎不是一个能做新事情的神奇盒子。它旨在成为一个提供更高层次抽象的工具,这样你就可以更少地关注重造轮子。许多供应商更进一步,允许您创建模板,这样业务用户就可以填补空白,而不必学习规则语言。

关于模板的一个最后的警告: 模板永远不会比编写没有模板的规则花费更少的时间,因为模板必须在最低限度上描述规则。计划一个更高的初始成本(就像你要建立一个系统,使用数据库来存储变化的值,而不是直接在系统代码中编写规则)-ROI 是因为你节省了系统代码的未来维护。

规则引擎是可配置应用程序的一个胜利,在这个应用程序中,如果可以避免的话,您不希望必须进行自定义构建。它们还擅长集中大型规则库,像 退下这样的算法可以有效地快速匹配大型规则集。

我认为你对贫血领域模型的担忧是有道理的。

在我工作的生产环境中,我看到了两个著名的商业 Rete 规则引擎的应用程序。我认为一个是成功,另一个是失败。

成功的应用程序是一个决策树应用程序,由约10棵树组成,每棵树有约30个分支点。规则引擎有一个允许业务人员维护规则的 UI。

不太成功的应用程序有大约3000条规则被塞进一个规则数据库。没有人知道添加新规则时是否存在相互冲突的规则。人们对 Rete 算法了解甚少,而且对该产品的专业知识已经离开了公司,所以它已经变成了一个不可触摸和不可重构的黑盒子。部署周期仍然受到规则更改的影响——规则更改时必须进行完整的回归测试。记忆力也是个问题。

我会小心行事。当规则集的大小适中时,很容易理解更改,如上面给出的简单的电子邮件示例。一旦规则的数量攀升到数百,我想你可能有一个问题。

我还担心规则引擎会成为应用程序中的单例瓶颈。

我认为使用对象作为划分引擎空间的方式没有什么错。在遵从私有规则引擎的对象中嵌入行为对我来说似乎没问题。当规则引擎要求不属于其对象的状态正确激发时,问题就会出现。但这只是另一个设计困难的例子。

已经有很多不错的答案了,但我还想补充几点:

  1. 在自动化任何复杂的决策过程中,关键的事情很快就变成了你管理而不是执行相关逻辑的能力。规则引擎对此没有帮助——您需要考虑业务规则管理系统具有的规则管理功能。大多数商业和开源规则引擎已经发展成带有存储库的规则管理系统,报告规则使用情况,版本控制等。与数千行代码或一堆规则相比,将规则存储库结构化为一致的规则集,并对其进行编排以做出业务决策要容易得多。
  2. 有许多方法可以使用声明性的、基于规则的方法。使用规则来管理 UI 或作为定义流程的一部分可能非常有效。然而,规则方法最有价值的用途是自动化业务决策,并将其作为松散耦合的决策服务交付,该服务接收输入、执行规则并返回答案——决策。这些服务回答其他服务的问题,如“这个客户是一个良好的信用风险”或“什么折扣,我应该给这个客户为这个订单或“什么是最好的交叉销售为这个客户在这个时候。使用规则管理系统可以非常有效地构建这些决策服务,并允许随着时间的推移轻松地集成分析,许多决策都从中受益。

我认为规则、流程和数据引擎(又名数据库)在本质上是相似的。但是,由于某些原因,我们从来没有说过对持久性子系统进行黑箱处理是不好的。

其次,从我的观点来看,贫血模型在行为的 实施中不是一个轻的模型,而是在 行为本身中一个轻的模型。描述域模型对象中可用行为的实际方法不必由对象本身完成。

根据我在规则引擎方面的经验,最大的复杂性是:

  1. 从 OOP POV 来看,重构和测试用声明性语言编写的规则,同时重构影响它们的代码,是一件非常痛苦的事情。
  2. 我们经常应该考虑规则的执行顺序,当有很多规则时,它们就会变得一团糟。
  3. 一些小的更改可能会触发不正确的规则行为,从而导致生产错误。在实践中,并不总是可能用预先的测试覆盖所有的情况。
  4. 规则变异其他规则中使用的对象也增加了复杂性,导致开发人员将它们分成几个阶段。