不同于一般的看法,软件开发中最困难的部分并不是系统的实际编码,而在于捕捉和解释含糊不清、不完整、往往彼此矛盾的业务需求。在沟通需求的早期引入的错误是最难纠正的系统错误,会导致开发补丁,并增加维护成本。在尝试捕捉和编码复杂业务规则时,这一点尤为明显。
业务规则有多种定义方法,但通常最好的思考方法是将其视为业务流程中的决策点。业务规则是根据 “if-then-else”类型的逻辑描述的,其中 if 是所满足的一组特定业务条件,then 是所执行的特定操作,else (否则)是可以执行的其他某些操作。举例来说,假设一家公司为其服务实行推广价格。推广存在有效时限,并且针对特定的一组产品或服务,则后台处理系统必须具有足够的能力,不仅能够为新客户正确实行推广价格,还能在恰当的时间中断推广活动。这些行为是由业务规则驱动的。
困难的部分在于将这些规则编入软件程序。大多数编程语言并未直接支持根据一组条件匹配或触发独立规则的概念 — 而大量业务流程都是规则驱动的(请参见下表)。
业务领域 | 示例 |
---|---|
财务决策 | 贷款发放 |
保险 | 意外保险 |
调度或发货 | 包裹递送 |
产品供应 | Cellular 服务 |
库存管理 | 即时供应链 |
费用计算 | 飞机、船舶、火车或公共汽车运输 |
这 篇文章探讨了捕捉和建模复杂业务规则的分析技术。作为一个示例,我将使用水污染测试的一些假定规则。在这个主题领域,美国环境保护署(EPA)定义了确定 饮用水污染物浓度的完善规范。出于本文的目的,假设测试是由监控地方供水系统质量的政府机构执行的。目的在于展示如何将简单的规则整合到复杂的结构中,实 现健壮的业务流程。
规则间的差异在于描述业务逻辑的用例行为(而 非系统行为)方面。在典型的用例中,活动流是由特定参与者与系统间以执行特定目标为目的而开展的交互驱动的(例如,“管理水健康状况样本”)。与之相对, 只有在其他系统处理(例如,为未清偿余款提供支付)导致准确匹配相应规则的条件时,该规则才会执行。因而,捕捉和验证业务规则的方法与用例开发大有不同。
规则的结构通常是定义良好的条件与操作语句对。一般来说,最佳实践是成组编写规则条件,必须满足一组中的所有条件才能触发规则。尽管某些规则引擎允许在条件中使用or结构,但在实践中,此类结构可能会导致难以理解和测试的规则。在这些情况下,最好创建多个规则,涵盖每种or情况,而不要创建一条带有多种可能匹配场景的复杂规则。因而,在下面的例子中,默认的条件组合始终是and(请参见 表 2)。除此之外,在创建规则时,应尽可能保证其可独立执行,使指定操作的执行仅需一条规则。这将允许对各规则进行独立测试和验证,随后可以将这些规则合并成为更复杂的行为。
分类 | 说明 |
---|---|
验证规则 | 数据验证、一致性检查 |
计算规则 | 根据输入数据计算值 |
决策规则 | 选择业务流程路径 |
生成规则 | 创建新数据对象 |
独立规则是在原子级别上定义的 — 也就是说,您可以定义一个独特的条件组合,为这一组触发条件执行一条(且惟一一条)规则。表 3 给出了一个简单的规则定义,在这个定义中评估了水样是否符合既定的水质标准。在这个例子中,活动就是简单地生成某种形式的通知,但也可以在规则活动中执行 更复杂的活动(如发传票)。请注意,这个规则定义可独立验证和理解,因而无需理解其他可能在此规则之前或之后执行的规则。
规则名称:评估水样 — 苯 | |
|
---|---|---|
规则组: 评估水样本 | |
|
条件 | 活动 | 注释 |
非无效水样 | 生成通知:苯超标 | 样本中允许存在的最高苯含量为 0.005 mg/L。 |
苯浓度 > 0.005 mg/L | |
|
有时,一种条件的出现会改变另一种条件。例如,考虑这样一种情况,最新研究表明,若水样中存在 carbofuran(标准上限为 0.04 mg/L),则苯浓度的标准上限应折半(新上限 = 0.0025 mg/L)。这样一条规则可按如下形式捕捉。
规则名称: 评估水样 — 苯(降低后的标准) | |
|
---|---|---|
规则组:评估水样 | |
|
条件 | 活动 | 注释 |
非无效水样 | 生成通知:苯超标 | 最新研究表明,若水样中存在 carbofuran,则苯浓度的标准上限必须降低 50%。 |
苯浓度 > 0.0025 mg/L | 生成通知:苯浓度标准上限降低(0.0025 mg/L) | |
Carbofuran 浓度 > 0 mg/L | |
|
请注意,现在不仅存在多个条件,还有多种活动。您可以使用or条件组合编写这两条规则,但正如上文所述,这将增加独立理解和测试各规则的难度,因而将规则分割为原子单位是最佳实践。
某些规则更适合以决策表 的形式表现,这种方法用于汇总大量共享同一组条件、其活动基于这些条件的可变值的规则。这种情况在金融机构中极为常见,批准贷款申请的决策要以申请人的信贷历史、工作状况、自有资产等条件为依据。
规则组:确定贷款资格 | |
|
|
---|---|---|---|
说明:信贷员将利用此表来确定贷款申请人的资格。 | |
|
|
申请额度 | 收入 | 负债 | 举措 |
<10,000 | >45,000 | <10,000 | 批准贷款,利息为 5% |
<20,000, >10,001 | >65,000 | <10,000 | 批准贷款,利息为 4.5% |
<30,000, >20,001 | >75,000 | <10,000 | 批准贷款,利息为 3% |
... | |
|
|
上述每一行都表示一条单独的规则。大多数商业和开源规则引擎都支持以规则表格的形式捕捉规则的功能。
最后一种规则类型称为树状 规则。与前例相同,这种规则捕捉技巧是表示多条相关规则的一种简便方法,但这种形式允许查看用于达成特定结论的完整决策树。如 图 1 所示,客户可根据客户回报的级别、地理位置和所获得的产品组合得到折扣。
规 则可能密切相关,它们可能匹配相同的输入数据,也可能执行一组类似的活动(例如,验证规则)。组织这些规则以限制匹配时要考虑的规则数量通常比较有用。这 样做主要是为了方便观察者,因为规则引擎优化算法足够强大,能够优化规则匹配。然而,如果一组特定数据使之前的处理步骤失败,这里会有一个显著的优势,这 组数据将不再用于下游规则的后续处理,输入无效。这种排除简化了下游规则的条件,减少了出错的可能性。
可使用规则组,根据定义良好的分类组织规则分组,允许创建规则流。如 图 2 所示,规则流可包含支点和接点,允许极为细致地管理规则执行。通过使用规则组合流,您就可以清晰地建模整个规则引擎行为,并独立验证各规则。
随 着规则集变得越来越复杂,业务主题专家(SME)要完全理解和验证规则与规则组间的所有交互也变得越来越困难。这些交互和依赖关系的可视化建模提供了一种 强大的机制,用于在开发团队、测试团队和业务参与者之间通信。在这种上下文中,最有用的三种模型是规则组的结构模型、组间的依赖关系图,以及规则引擎本身 执行的执行流。
如图 2 所示,我使用了统一建模语言(UML)«stereotype»扩展机制来增强 UML 活动图,以提供捕捉这一信息的可视化模型。«rule-group»stereotype 表示一个规则组,«rule»表示一条指定规则。图 3 显示了指出一个规则定义的«condition»和«action»对的两种方法。
在直接与业务用户一起工作时,这种方法极为有用,因为它能以可视化的方式呈现规则,而非文本。与规则组建模图相结合,这两种模型视图可提供业务规则组中的规则的全面视图。
回页首
需求定义无需以上述形式定义,但这种方法能得到简化的实现,可直接回溯到指定需求。如 表 6 所示,这三个示例规则分别用于验证水样(Validate Water Sample)、评估水样(Evaluate Water Sample)— 超标(Exposure Limit Exceeded) 和 评估水样(Evaluate Water Sample)— 大肠杆菌(Fecal Coliforms),将使用 JBoss Rules (Drools) 开源规则引擎编码。
规则名称:验证水样 | |
|
---|---|---|
规则组: WaterSample | |
|
优先级(显著性): 100 | |
|
条件 | 举措 | 注释 |
无效水样 | 生成通知:无效水样报告 | 水样将被标记为无效。 |
规则名称:评估水样 — 大肠杆菌 | |
|
规则组: WaterSample | |
|
优先级(显著性): 50 | |
|
条件 | 举措 | 注释 |
有效水样 | 生成通知:大肠杆菌报告 | 如果水样中发现大肠杆菌,则创建一份污染通知。 |
大肠杆菌 > 0 | |
|
规则名称:评估水样 — 超标 | |
|
规则组: WaterSample | |
|
优先级(显著性): 50 | |
|
条件 | 举措 | 注释 |
有效水样 | 生成通知:超标 | 所收集到的水样数据超出了水样的标准上限。 |
污染物浓度 > 暴露极限 | |
|
图 4 展示了这三种规则的 Drool 实现。
根据规则引擎实现和规则间的交互,往往需要确定规则执行的优先级。这方面的技术有两种,第一种是前面介绍的规则组和规则执行流。另一种技术是建立在独立规则级别上的,在此级别上,可为一个组中的某条规则赋予高于其他规则的优先级。(在 Drool 引擎中,这称为显著性级别(salience level)。)
有时会出现这样一些情况,例如需要在执行其他处理规则之前应用验证规则时、一条规则必须先于其他规则执行时 —— 即便两条规则都是触发的有效选择(也就是说,满足规则条件)。在这些情况下,规则可能具有重叠的条件组,或应在其他规则先执行后再执行。
在上述示例中,尽管两条规则位于同一个规则组(WaterSample)中,根据所提供的显著性水平,评估规则也将在验证规则后执行。假设水样未能通过验证,则水样的数据将从工作存储器中删除,不再用于匹配后续规则。
在 规则引擎中实现业务规则时,最后一步就是确保编码的规则匹配需求。许多规则引擎都提供了测试和评估工具,但有些时候,有必要创建专用的工具。如图 5 所示,我们编写了一种工具,作为 Drools 引擎中所提供的测试工具的补充,允许测试团队动态选择验证数据,并查看结果和执行的规则。
如 图所示,以原子单位定义、捕捉和实现规则后,可以非常轻松地测试规则的正确性。使用自动化工具支持重复测试,确保新规则添加到集合中时,旧规则不会被违 背。另外还要注意,在这个例子中,工具包含维护规则引擎的工作状态的功能,这就允许了有状态的动态测试 — 对于来自之前处理的数据必须呈现在规则引擎中以测试一组规则的执行情况的测试场景极为有用。
回页首
即 便在最有利的情况下,在软件系统中编写业务规则也是一项必要的挑战性任务。不明确、不完整、易误解的需求的出现只会使开发工作复杂化,并带来成本高昂的错 误。业务规则的可视化和文本描述的结合提供了更准确、更有效地捕捉业务规则的途径,特别对于使用规则驱动引擎的实现来说更是如此。使用本文描述的技术,您 就可以使用强大的分析框架更好地武装业务分析人员,便于其沟通复杂的业务处理规则。