使用工作流引擎,状态机引擎还是自己滚动?

时间:2012-08-17 07:11:11

标签: java grails drools jbpm activiti

我很困惑。我正在为我的公司开发基于grails的内部工具。此工具中的一个组件是一个简单的问题跟踪器(帮助台功能)。我有域对象,如问题,问题和NewFeature。每个域类都有不同的工作流程。

我最初的想法是在域对象中滚动我自己的状态机功能。然后我用Google搜索状态机引擎和工作流引擎。现在我迷路了。

我想评论其他开发人员如何解决这个问题。你用Drools,Jbpm,Activiti吗?还是一些更简单的状态机引擎?

我一直在阅读Drools的一些文档,Jbpm。他们看起来很漂亮。但似乎我只需要这些库提供的一小部分功能。

我正在使用Grails,但它当然也很容易使用Java库。

3 个答案:

答案 0 :(得分:15)

工作流引擎的主要价值在于它可以通过某些工作流定义DSL自定义流。如果您不需要允许用户定义他们自己的任意工作流程,那么您最好自己构建自己的工作流程。

此外,工作流引擎通常还能让您定义业务交易和长期运行的规则。例如,您可以拥有一个授权采购订单的工作流程,其中第一步是输入一些有关需要购买的信息,然后如果购买的价格低于100美元就可以获得规则,如果100美元到100美元之间2000美元的直线经理可以,如果它更多,然后将其发送给其他人进行审批......等等。随着金额的增加或公司的业务政策发生变化,这些类型的业务规则往往会发生变化。因此,在这些场景中使用工作流引擎是有意义的。可以从工作流引擎中受益的复杂业务交易的其他好例子是提出保险索赔,授权贷款或抵押,评估客户的信用申请......等。这些业务交易往往经过多个人/部门并需要几个小时到几天或几周才能完成。

规则引擎适用于从应用程序中提取复杂但不断变化的规则。假设您是一家在线零售商,可以向美国,加拿大,英国,德国和法国的客户发货。您需要对在线商店销售的产品征税,但计算税收的规则因国家/地区和省内的省份而异。有些东西在一个省免税,但在其他省份没有。规则引擎非常适合这些类型的复杂业务规则,只要政府改变其税收政策,这些规则就会发生变化。规则引擎可以给你一个正确的答案你只需要去规则引擎说我想运行规则#10,这里是规则#10 x,y,z的输入,你得到一个答案。

规则引擎和工作流引擎之间的主要区别在于规则引擎不跟踪事务的状态,它应该是无状态的,仅对您提供的输入有效。工作流引擎是有状态的,它必须知道当前状态是工作流,并且必须将该状态保存到数据库。工作流引擎还等待来自外部源(例如人员或系统)的输入。

根据您对应用程序的描述,我将编写一些常规类来计算故障单的下一个状态,并确保该类具有良好的文档并且在几年内易于更新。我认为规则引擎和工作流引擎对你的情况来说太过分了,你设置它们和使用它们所花费的时间要大得多,你需要在groovy中编写代码。如果随着时间的推移你发现你需要规则引擎和工作流引擎的复杂性,我会付出代价而不是现在,保持简单始终是最好的选择。

答案 1 :(得分:5)

我不能同意上述AMS'回答,我要添加的另一件事是,对于大多数情况,使用工作流/规则引擎是过度和不必要的。 KISS(保持简单和愚蠢)始终是最佳选择。并且奥卡姆的剃刀也说"实体不应该不必要地倍增"

根据我自己在阿里巴巴的工作经验,大多数工作流/规则引擎配备的应用程序正在将维护工作变为噩梦,如果您使用简化的impl而不是盲目的话,以后人们会对项目表示感谢选择工作流程/规则引擎。

那么,是否有指导说明何时使用工作流程?坦率地说,我不知道,但我所知道的是,当商业逻辑流入时,我们绝对不应该使用工作流程。因为如果你愿意的话,每个商业逻辑都可以用流程图表示。

最后,我去年做的最正确的事情之一是重新设计一个应用程序,用groovy脚本替换Drools,这使得整个系统更直接,更简单,更快。

答案 2 :(得分:1)

“状态机”很普遍design pattern,那么流口水实际上给了你什么?我个人很看重流口水的“查询语言”,这就是让它发光的原因。实际上,您有类似“ SQL从堆中查询对象”之类的东西。就像SQL为您提供了“声明式”编程方式一样,“滴水当块”描述了何时以声明方式启动状态转换。 Drools被设计为statefull by default,状态是插入到Drools会话中的所有事实(POJO)。

让我为您提出一个简单的用例。您必须为蜂窝电话公司编写应用程序才能管理电话。
如果呼叫者1正在呼叫被呼叫者2,而此时他并不“忙”,请连接他们。
如果被叫方忙,请继续通话7秒钟,并且如果被叫方在这段时间内将其原始呼叫断开,请立即连接它们。
如果被叫方在7秒钟内没有断开连接,则将呼叫者挂断并显示消息“被叫方正忙”。

简单的三重if语句业务方法很快变得非常复杂,并且容易出错。我猜想背景Timer是5到10年前或更新的背景,例如ScheduledThreadPoolExecutor。如果状态在排定的延迟期间发生了变化怎么办?您还会等到最后重新计算条件吗?如果这种情况在您的应用程序中相对经常出现或周期相对较长,您是否将“上下文”保留在内存中?您需要跟踪期货并取消期货或使用一些BlockingQueue。在这种情况下,需要为每个人保持排队,因为每个人都可能被某人呼叫。传统的OOP表示“您应该使行为与域实体保持联系”。通过这种方法,即使您将使用某些模式来简化(封装)复杂性,“状态机”开始在多个组件之间传播,您也将开始使用非常复杂的技术来使您的业务实体变得混乱。使用“分层样式”,因为您将开始为状态内容生成数据结构,例如Map<Callee, BlockingQueue<Caller>>。第二天,您的客户来找您,说:“嘿,关于电话,我还有另一个简单的用例。”

Drools使用完全不同的方法“自然”地解决了此类问题。它跟踪工作内存中的所有对象(跟踪规则条件),并且当时间到来时,流口水仅能说出您的规则是否有资格执行(追溯到1979年)。如果状态发生变化,则流口水会以有效的方式重新评估每个规则的条件,并从“议程”(执行队列)中放置或删除相应的规则。您插入“工作内存”中的所有对象都形成一个“状态”,任何规则都可以继续。这是用raw droolsthe test编写的类似用例示例,用于指定逻辑。

使用正确的工具完成任务。如果您需要在带有3-5个字段的State对象内部的实体集合上进行循环,请不要在标题中放置“ state machine”。如果您确实遇到诸如“连续行为更改”或系统中事件之间复杂的因果依赖关系之类的问题,那么流口水就是很好的选择,并且已经过时间证明是开源rete algorithm的实现。不要尝试使用广告中的所有内容,深入研究细节,了解原理,了解适合您需求的内容。