规则引擎 – 优缺点

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

这个概念对我来说是全新的,我对此很怀疑。 在听到过去几年人们谈论贫血域模型之后,我在质疑“规则引擎方法”。 对我来说,他们似乎是减弱域模型的好方法。 例如说,我正在做一个java webapp与一个规则引擎交互。 然后我决定我想有一个基于同一个域的Android应用程序。 除非我想要Android应用程序与规则引擎进行交互,否则我将不得不错过任何已经写入的业务逻辑。

由于我还没有任何经验,只是好奇,我有兴趣知道利弊在使用规则引擎? 我能想到的唯一的专家是,你不需要重build你的整个应用程序只是为了改变一些业务规则(但真的,有多less应用程序真的有这么多的变化?)。 但是用一个规则引擎来解决这个问题,对我来说就像是在一个霰弹枪伤口上贴上一个创可贴。

更新 – 自写这篇文章以来,上帝本人马丁·福勒(Martin Fowler)曾经发表过关于使用规则引擎的博客 。

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

还有另一类业务规则:决策。 例如,保险公司可能需要对承保申请人的风险进行分类并收取保费。 您可以将这些types的业务规则放置在您的域模型中,但是对于这种情况的集中决策通常是可取的,而且实际上很适合面向服务的体系结构。 这不要求为什么规则引擎而不是系统代码的问题。 规则引擎可能是一个更好的select的地方是负责决策的业务规则随着时间的推移而变化(如其他一些答案指出的那样)。

规则引擎通常允许您更改规则,而无需重新启动系统或部署新的可执行代码(无论您从供应商那里得到什么承诺,确保您在非生产环境中testing您的更改,因为即使规则引擎完美无缺,人类仍在改变规则)。 如果你在想,“我可以通过使用数据库来存储改变的值”,那么你是对的。 规则引擎不是一个神奇的盒子,可以做一些新的事情。 它旨在成为提供更高级别抽象的工具,因此您可以更less地关注重新发明轮子。 许多供应商通过让您创build模板,使业务用户可以填补空白,而不是学习规则语言。

关于模板的另一个注意事项:模板永远不会比编写没有模板的规则花费更less的时间,因为模板必须至less描述规则。 计划一个更高的初始成本(就像build立一个使用数据库来存储更改的值的系统,而不是直接在系统代码中写入规则一样) – ROI是因为您节省了将来系统代码的维护。

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

我已经看到了两个在我工作的生产环境中运行的着名的商业Rete规则引擎的应用程序。 我会考虑一个成功,另一个失败。

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

不太成功的应用程序已经有〜3000条规则冲击规则数据库。 没有人知道添加新的规则时是否有冲突的规则。 对Retealgorithm有一点了解,并且产品的专业知识已经离开了公司,所以它变成了一个不可触及的,不可再生的黑盒子。 部署周期仍然受到规则更改的影响 – 更改规则时必须完成完整的回归testing。 记忆也是一个问题。

我会轻轻一点。 当规则集规模适中时,很容易理解变化,就像上面给出的简单的电子邮件样本。 一旦规则的数量攀升到数百人,我认为你可能有问题。

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

我没有看到使用对象作为划分规则引擎空间的方法。 在遵循私有规则引擎的对象中embedded行为对我来说似乎没有问题。 当规则引擎需要状态不是其对象的一部分才能正常触发时,问题会打到你。 但这只是devise难度的另一个例子。

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

首先,许多规则引擎以更具说明性的方式工作。 一个非常粗略的例子是AWK,你可以在其中分配正则expression式代码块。 当文件扫描器看到正则expression式时,代码块被执行。

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

因此,AWK文件变得更像是“规则汤”。 这种“规则汤”的性质让人们非常紧张地关注他们的领域,而不关心系统中可能存在的所有其他规则。

例如,弗兰克对总价值超过1000美元的订单感兴趣,所以他提出了他感兴趣的规则体系。 “如果order.total> 1000那么电子邮件弗兰克”。

同时,Sally希望所有来自西海岸的订单:“如果order.source =='WEST_COAST'那么给Sally发邮件”。

所以,在这个微不足道的,做作的案例中,你可以看到一个命令可以同时满足这两个规则,但是这两个规则是相互独立的。 来自西海岸的$ 1200订单通知Frank和Sally。 当弗兰克不再担心的时候,他只不过是把汤汁从汤里抽出来了。

对于很多情况,这种灵活性可能非常强大。 它也可以像这种情况一样暴露给最终用户以获得简单的规则。 使用高级expression式和可能轻量级的脚本。

显然,在一个复杂的体系中,可能会发生各种相互关系,这就是为什么整个体系不是“有规则”的原因。 有人在某个地方负责这个规则不会失控。 但是,这并不一定会降低系统所能提供的价值。

注意,这甚至不涉及像专家系统这样的规则,规则触发规则可以创build的数据,而是更简单的规则系统。

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

我见过的规则引擎最大的特点就是让业务规则所有者实现业务规则,而不是把责任放在程序员身上。 即使你有一个敏捷的过程,你不断地从利益相关者那里得到反馈,并且经历了快速的迭代,但是要达到人们制定业务规则的目标,也不能达到效率水平。

另外,如果将规则embedded到代码中,则不能不重视删除可能由简单的规则更改导致的重新编译重新重新部署周期的值。 通常有几个团队参与构build的祝福,使用规则引擎可以使许多不必要的。

我为客户写了一个规则引擎。 最大的胜利是包括所有的利益相关者。 引擎可以运行(或重放)查询并解释文本中发生了什么。 商务人士可以看看文字描述,并快速指出规则,例外和其他特殊情况的细微差别。 一旦涉及商业方面,validation就会好得多,因为很容易得到他们的意见。 此外,规则引擎可以独立于应用程序代码库的其他部分,因此您可以跨应用程序使用它。

这意味着一些程序员不喜欢学习太多。 规则引擎和你投入其中的规则,以及实现它们的东西可能有点多毛。 虽然一个好的系统可以很容易地处理病态和扭曲的逻辑networking(或者经常是不合逻辑的),但并不像编写一堆if语句那样简单(不pipe一些头脑简单的规则引擎如何)。 规则引擎为您提供了处理规则关系的工具,但是您仍然必须能够想象出所有这些。 有时候就像在巴西电影里生活一样。 🙂

它(和其他一切一样)取决于你的应用程序。 对于一些应用程序(通常是那些永远不会改变的规则或规则对现实生活常数最好的应用程序,即在物理属性和公式方面不会明显改变),使用规则引擎是没有意义的,它只是引入了额外的复杂性,并要求开发者拥有更大的技能。

对于其他应用程序,这真的是一个好主意。 例如订单处理(订单是从发票到处理货币交易的任何事情),每隔一段时间就会有一些相关的法律或法规(在司法意义上)需要一点点改变,这就要求您履行新的要求(例如销售税,一个经典)。 而不是试图强迫你的旧应用程序进入这种新的情况,突然之间你必须考虑销售税,以前你没有这样做,更容易适应你的规则集,而不是不得不介入一个潜在的大你的代码集。

那么来自你当地政府的下一个修正案就要求在一定的标准下报告所有的销售情况,而不是必须进去补充。 最后,你会得到非常复杂的代码,当你转身,想要恢复其中一个规则的效果,而不会影响所有其他规则时,将很难pipe理。

到目前为止,所有人都对规则引擎非常乐观,但是我build议读者谨慎行事。 当问题变得复杂一点时,你可能突然发现整个规则引擎已经变得不合适,或者比一个更强大的语言复杂得多。 此外,对于许多问题,规则引擎将无法轻松检测到大大减less评估条件的运行时间和内存占用量的属性。 我相对较less的情况下,我宁愿规则引擎的dependency injection框架或更dynamic的编程语言。

“但是真的,有多less应用真的有这么多的变化?”

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

事实上,你无法预先考虑所有事情,因此也就是敏捷stream程的原因。 此外,广pipe局似乎总是错过一些重要的东西,直到在testing中发现。

规则引擎迫使您真正将演示和存储的业务逻辑分开。 此外,如果使用正确的引擎,您的BA可以根据需要添加和删除逻辑。 正如Chris Marasti-Georg所说的那样,它把责任推给了广pipe局。 但更重要的是,它可以让广pipe局得到他们所要求的。

规则引擎是可configuration应用程序的一个胜利,如果可以避免的话,您不需要进行自定义构build。 他们也擅长集中规则和algorithm的大型基础,如Rete对于快速匹配大型规则集是有效的。

已经有很多很好的答案,但是想要添加一些东西:

  1. 在对任何复杂性进行自动化决策的过程中,关键的事情迅速成为您pipe理而不是执行相关逻辑的能力。 规则引擎无助于此 – 您需要考虑业务规则pipe理系统具有的规则pipe理function。 大多数商业和开源的规则引擎已经发展成为带有存储库的规则pipe理系统,报告规则的使用情况,版本控制等。规则的存储库被构build成协调的规则集,可以进行协调以做出业务决策,比数千行代码或规则汤。
  2. 有许多方法可以使用声明式的,基于规则的方法。 使用规则来pipe理UI或作为定义过程的一部分可以是非常有效的。 然而,规则方法的最有价值的用途是自动化业务决策,并将其作为松散耦合的决策服务来执行,这些决策服务采取input,执行规则并返回一个答案 – 一个决定。 这些服务可以回答其他服务的问题,例如“这个客户是一个很好的信用风险”,或者“我应该给这个客户什么样的折扣”或者“这个客户在这个时候最好的交叉销售。 这些决策服务可以使用规则pipe理系统非常有效地build立,并允许随着时间的推移轻松整合分析,这是许多决策受益的原因。

我看到规则,stream程和数据引擎(又名数据库)本质上是相似的。 但是,由于某种原因,我们从不说黑盒子持久化子系统是不好的。

其次,从我的视angular来看,贫困模式并不是一种行为执行上的轻松,而是一种行为本身的轻微行为 。 描述域模型对象中可用行为的实际方法不一定要由对象本身来完成。

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

  1. 从OOP POV开始,重构和testing用声明性语言编写的规则是一个真正的痛苦,当你重构影响它们的代码时。
  2. 通常我们应该总是考虑规则的执行顺序,当规则的执行顺序很多时就变成一团糟。
  3. 一些小的变化可能会触发导致生产错误的规则行为不正确。 在实践中,预先覆盖所有的案例并不总是可能的。
  4. 规则中使用的对象也会增加复杂性,导致开发人员将其分解为多个阶段。