看看最新的文章和各类BPM解决方案,很容易让人假定BPEL是实现工作流引擎时所使用的事实标准。从技术角度看,这可能相当正确,但极少有人会说BPEL能很容易地被终端用户(即业务分析师)理解。在实践中,他们无疑会首先选择以符号(如BPMN)为基础的图形化工具。本文将帮助读者理解技术观点(BPEL赞成派)和分析师观点(BPMN赞成派)的差异。进而,本文将解释以BPEL为基础的BPM 解决方案为何不是BPM问题解决方案的大势所趋,即使它们都能消除这种差异(因为它们通常都提供了BPMN到BPEL的映射)。我们将使用一个现实世界的例子来阐述我们的论点。
是一门结构化语言,原因是它是基于“块(Block)”的,这一点与诸如Java和C等这些传统语言非常类似。这一特性部分源于它的前身:Microsoft的XLANG,它也是基于“块(Block)”的。然而,BPEL的血统还包含了IBM的WSFL,而它对于我们的后续讨论非常重要,因为它基于图形的(因此是非结构化的)。这样我们就发现:BPEL是一个结构化(块[Block])和非结构化(控制链和事件)的混合体。而正是后者给结构化的世界引入了一丝非结构化的气息……因而结论是,BPEL不是一门结构化语言,就算它看起来像也无法改变这一事实。
相反,BPMN是一种天生就具有非结构化特性的流程图符号。不要对此表示怀疑。在BPMN规范[BPMN06]的11章(137页)中,它提供了一个从BPMN到BPEL的直接映射。一些BPMN编写者(和用户)认为BPMN是一个以BPEL语言为基础的简单GUI。这并不十分正确,在BPMN FAQ中这样解释道:
“BPEL能够描述的流程拓扑设计时就存在局限,用BPMN可以表达的流程有可能无法映射到BPEL。”
本文将对于这句重要陈述给出一些根本细节。但在此之前先让我们先关注一下结构化和非结构化语言对比。为什么这非常重要?主要原因在于,对非结构化语言进行代码分析要远远难于结构化语言(如Java、C,以及其他——就算不是全部——广为使用的编程语言)。代码分析的应用范围很广,从错误检查(比如编译器),到Bug检测(如findbugs、死锁检测……)以及质量检查(如checkstyle)。
Böhm和Jacopini的一条重要法则[BOHM66](并在Wikipedia上有通俗的解释)认为:编程语言只消以3种方式组合子程序,它就能实现任何可计算功能。这三种控制结构是:
这基本意味着任何(非结构化的)流程图都能够转化成一个结构化的内容。这形成了Dijkstra的论文《Go To语句是有害的》[DIJKSTRA68]的基础。
尽管仍然还有关于“我们是否应该允许非结构化编程语言的存在”的争论,但事实是:
世界上大多数的学生都被灌输了结构化语言;
使用最广泛的编程语言是(非严格的)结构化编程语言;
大多数非结构化编程语言已经引入了一些结构化单元(BASIC,COBOL,FORTRAN)。
因此一般而言,大多数程序员确实会关注结构化编程,但是有时出于各种原因(主要是可读性、维护,有时是性能)会使用非结构化语句(goto、jump、break、exceptions)。
业务分析师(BPM的终端用户)必须处理现实世界1发生的事情,它不仅是非结构化的,而且是高度并行的。这包含两层含义:
第2点很重要的,它已被Kiepuszewski等人[KIEPUSZEWSKI00]正式证明了。事实上,存在有并行非结构化的工作流不能够被表示成并行结构化的工作流的情况。而且,这种例子非常容易找到。看看下面这个使用BPMN符号的例子(用Intalio BPMN设计器创建):
在一个使用BPEL作为它底层格式的工具中,为了验证这个图,需要创建一个单独的池。我们随后会讨论这个问题,但现在请重点关注名叫“Employer”的池及其包含的6个活动。只要一名新员工加入公司,一条工作流就会被启动。首先需要在人力资源数据库中创建一条记录。同时,必须提供一个办公室。一旦人力资源活动完成,员工就得接受医疗检查。在此期间,会提供给他一台计算机。而这只能出现在:办公室已经安排好且账户已在来自人力资源数据库的信息系统中创建好的情况下。在计算机已提供且医疗检查已结束的情况下,员工就可以开始工作了。当然,你可能希望用不同的方式建模这条简单流程,但是有一点我需要在这里指出,你无法创建一个等同于2本流程的一个结构化并行工作流,我的意思是,你永远也办不到!我们都将使用这个简单的例子贯穿全文。
从这个学习中,我们得出第一个结论:
BPM用户会设计出一些你无法用结构化的并行工作流表达的工作流。更糟的是,它也出现在了[KIEPUSZEWSKI00]中,作者表示:就算并行、非结构化工作流能够转换成并行、结构化工作流,但这需要额外的变化和(或)节点,以至于最终结果会导致对终端用户来说几乎无法读懂。我们很快会讨论这个可读性的问题。
在文章[OUYANG06]中,作者提出了从BPMN到(可读的)BPEL的自动化转换。由于规范中的一些不清晰语义,他们定义了一个BPMN的子集。因此,他们在文中没有考虑OR 网关(OR Gateway)和错误中继事件(Intermediate Events)。在待设计流程包含多个结束事件(End Event)的情况下,问题就来了。因为转换工具没有考虑它们,而把多个结束事件(End Event)工作流转换成单结束事件(End Event)工作流的标准方法就是使用OR网关(OR Gateway)。算法大致如下:
其结果就是一个“尽量可读的”等价BPEL流程。注意,我们总是可以使用BPEL中的事件来将BPMN转换成BPEL。问题是,其生成代码根本就不可读。因而,结论是将任何BPMN图转换成一个等价3BPEL流程的算法确实存在,只是结果是“尽量可读的”4。
注意,下例中所表现的肯定不是Intalio BPM v2.0解决方案在BPMN到BPEL转换时使用的算法,如下的简单例子说明了这一点。以前面的非结构化BPMN图来说,Intalio的解决方案会将它转换成BPEL流程,部分显示如下:
<?xml version="1.0" encoding="UTF-8"?> <bpel:process xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vprop="http://docs.oasis-open.org/wsbpel/2.0/varprop" xmlns:pnlk="http://docs.oasis-open.org/wsbpel/2.0/plnktype" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:this="http://example.com/Unstructured/Employer" xmlns:Employee="http://example.com/Unstructured/Employee" xmlns:diag="http://example.com/Unstructured" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:bpmn="http://www.intalio.com/bpms" xmlns:atomic="http://ode.apache.org/atomicScope" queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0" expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0" bpmn:label="Employer" bpmn:id="_TGthsJkdEd29aqy0ek4Sxw" name="Employer" targetNamespace="http://example.com/Unstructured/Employer"> <bpel:import namespace="http://example.com/Unstructured" location="Unstructured.wsdl" importType="http://schemas.xmlsoap.org/wsdl/" /> <bpel:import namespace="http://example.com/Unstructured/Employer" location="Unstructured-Employer.wsdl" importType="http://schemas.xmlsoap.org/wsdl/" /> <bpel:partnerLinks> <bpel:partnerLink name="employeeAndEmployerPlkVar" partnerLinkType="diag:EmployeeAndEmployer" myRole="Employer_for_Employee" /> </bpel:partnerLinks> <bpel:variables> <bpel:variable name="thisEmployee_ArrivalRequestMsg" messageType="this:Employee_ArrivalRequest" /> </bpel:variables> <bpel:sequence> <bpel:receive partnerLink="employeeAndEmployerPlkVar" portType="this:ForEmployee" operation="Employee_Arrival" variable="thisEmployee_ArrivalRequestMsg" createInstance="yes" bpmn:label="Employee Arrival" bpmn:id="_THp84JkdEd29aqy0ek4Sxw"> </bpel:receive> <bpel:flow bpmn:label="GatewayParallel" bpmn:id="_DHLtcJkeEd29aqy0ek4Sxw"> <bpel:sequence> <bpel:empty bpmn:label="Fill HR DB" bpmn:id="_hCvXsJkdEd29aqy0ek4Sxw" /> <bpel:flow bpmn:label="GatewayParallel" bpmn:id="_H2UWEJkeEd29aqy0ek4Sxw"> <bpel:sequence> <bpel:empty bpmn:label="Medical Check" bpmn:id="_ivks8JkdEd29aqy0ek4Sxw" /> </bpel:sequence> <bpel:sequence> <bpel:empty bpmn:label="Provide Computer" bpmn:id="_lXApQJkdEd29aqy0ek4Sxw" /> </bpel:sequence> </bpel:flow> </bpel:sequence> <bpel:sequence> <bpel:empty bpmn:label="Provide Office" bpmn:id="_iHEigJkdEd29aqy0ek4Sxw" /> <bpel:empty bpmn:label="Provide Computer" bpmn:id="_lXApQJkdEd29aqy0ek4Sxw" /> </bpel:sequence> </bpel:flow> <bpel:empty bpmn:label="Ready to work" bpmn:id="_nh6akJkdEd29aqy0ek4Sxw" /> </bpel:sequence> </bpel:process>
要想将转换结果显示成一张漂亮的图,我们可以在Eclipse BPEL设计器中打开这个流程:
由于某些原因,“Fill HR Db”、“Medical Check”等活动的标签丢失了,但是无论怎样,我们都能够从BPEL的源代码中看到BPMN的“Employee Arrival”活动已转成了BPEL的“Receive”操作。对于业务分析师而言,会对现在看到7个活动(“Receive”和其他6个 “Empty”活动)感到奇怪,而在我们的原始流程中只包含了6个。看看BPEL源代码就能打消这个疑惑了:我们可以看到“Provide Computer”活动被复制了。在某些方面,这对于员工来说倒是件好事:他们可以在办公室拥有两台计算机!
Intalio BPMN2BPEL转换算法能否产生可读的BPEL,并不是这里的问题:问题在于这个转换完全错了。你无法想象出,那些专注于现实世界业务流程的职业BPM设计者能画出什么样的图,因为这些流程本质上就是高度并行和非结构化的。
[AALST_UNKNOWNDATE]中的作者认为:BPEL对终端用户来说是不可读的,因此需要一种用于流程设计的高级语言。但一般情况是,在流程真正执行之前,就需要运行时信息了。如何把这个信息融入到最终的BPEL代码中呢?有人可能会认为,这就是生成可读的BPEL代码之所以重要的原因。在所有信息直接输入到编辑器/设计器中的情况下,至少出于调试的目的,BPEL代码也应该尽量可读,其中可读的含义:尽量直接使用BPEL结构(sequence、flow、pick、wait 等)。
就这个可读性问题,让我们介绍一下Eclipse的JWT子项目,它旨在提供一个工作流管理(设计、转换,模拟和连接引擎)的工具。JWT 现在使用UML活动图符号(简称UML-AD)设计工作流。UML-AD 严格等价于BPMN(就表现力来说)(详见[WHITE_UNKNOWN_DATE])。那么,使用UML-AD符号,我们可以在JWT中把之前的BPMN图表示为:
JWT是可扩展的,同时提供了不同的转换插件。其中一个是UML-AD2BPEL转换,来自Augsburg大学的一个研究项目。这个BPEL转换插件会输出一个518行的BPEL-WS-1.1文档(在这片文章的结尾会提供样本)。注意,不管是Eclipse BPEL设计器还是Intalio设计器都无法正确地展示这个BPEL文件。鉴于此,我们使用了Netbeans。但产生的图还是太复杂了,无法在此展现(要了解该图的局部展现,请参见“资源”小节)。为了得到等价的5BPEL描述,JWT2BPEL转换工具大量地使用了BPEL事件。要是有人有勇气一读的话,其难度可见一斑。
因此,使用诸如BPMN或者UML-AD这样纯工作流符号表示的简单并行非结构化流程很难被表示成“可读”的BPEL格式。这就是一个普通事实,而不是单单是针对我们这里讨论的这个简单流程。在考虑BPMN-to-BPEL双向工程的情况下,情况更糟:(来自于Wikipedia) “从BPMN图生成BPEL代码,维护原始BPMN模型和所产生的BPEL代码之间的同步,一个中的任何改动都要传播给另一个”。使用诸如BPMN这样的自然工作流符号来表示用BPEL作为其最终格式的业务流程执行,无异于没事找事。
注意,从BPEL流程创建BPMN图的过程似乎要比其反过程要容易的多:把结构化元素转化成非结构化相当简单。注意,在Intalio中已经提供了这样一个转换(BPEL2BPMN)的Java类,从这里可得到。它似乎是以STP的核心,并且(目前)还不是完全地符合BPEL,在类的注释中能看出来:
;/* * 由BPEL文件产生BPMN的非常基本的例子。 * 这里解析的BPEL只是BPEL规范的一个很小的子集: * scope、assign、receive、reply、invoke、flow、sequence。 * ... */
尽管如此,由于某些未知的原因,导入由Intalio设计器生成的BPEL文件将无法工作。可是,双向工程的问题在于保持同一流程两个完全不同的表示的同步:一个是BPMN,另一个是BPEL。
首先,我们澄清了一个常见的误解:BPEL不是一门结构化语言,但它是基于结构化语言的(基于块[Block])。在某些方面,BPEL更接近于类似 Java这样的标准语言,而不是一个自然的工作流符号,比如BPMN(基于图)。直到现在,程序员都是直接打理他们的语言。集成开发环境则用来简化几个重复步骤,比如编译、重构、测试等等。 但是程序员直接“讲”他们的语言。我们认为,这种情景将同样适用于BPEL。一个IDE 只能简化编程步骤(注意,我们在这里并没有用“设计”一词)。但是,为了使用以及从中获益,BPEL程序员将不得不“讲”BPEL。关于BPEL对于大多技术人员是否是“说得出口的”-就像Java一样-这个问题已经超出了本文的范围,但它确实是一个有趣的问题。
然而对于业务分析师,BPEL则显然不够友好。BPEL难以阅读、难以学习、难以实现,而所有这些正是终端用户的主要关注点:难以回避。我们已经注意到,在文中使用的这个简单例子中,当创建“Employer”池时,为了生成BPEL文件,我们受制于创建另一个“非执行”的池。Intalio设计器中给出的许多其他BPEL相关行头,从BPMN分析师的角度来看则完全没有用:比如命名空间、Web服务调用、XML数据类型以及其他。
因此,我们认为BPMN符号是业务分析师目前唯一可用的解决方案6。不过,在流程能够实际执行之前仍需指定许多执行细节,这是BPMN规范中所没有的,并且是分析师在设计时不清楚的。这些信息通常本质上是技术、站点(如:邮件服务器地址、任务库)或实现(如:Web服务、J2EE服务或.NET 服务)依赖的。因此,技术人员输入到环境上下文的流程骨架是一个在执行语义(双向模拟)上等价于原始BPMN流程,并且它还是易读的以保证所做的修改不会改变流程的行为,这一点是极其重要的。
从BPMN到(可读的)BPEL转换相当难以实现,并会产生(如果正确的话)难以阅读的代码。顺便提一下,双向工程的问题就更难了。除非后者能得以解决,否则无法让实际业务分析师把BPEL作为设计流程的目标输出。
因此,我们很疑惑:既然已经存在一种可以直接映射到BPMN各单元的基于图的标准,即XPDL v2.0,为什么还要将BPMN转换成BPEL?使用这种映射,XPDL v2.0很自然就成了一种BPMN的持久化文件格式。此外,它还指定了之前只能用在BPEL中的可用行为,如Web服务调用和补偿。当然,有人会说,XPDL 2.0缺乏一些执行方面的规范,这就让它不适合直接执行。我们相信,在XPDL没有详细说明的地方使用BPEL,为实现一个完全符合BPMN v2.0、XPDL v2.0和BPEL的引擎留下了充足的空间。Bonita和Orchestra团队正是按这样方式去实现的他们下一代BPM引擎。但这应该是另一个故事了,需要另一篇文章来介绍……就此打住!
感谢Bonita & Orchestra 团队对本文的帮助和支持,尤其是Miguel Valdes-Faura的审校和建议。同时也感谢Gavin Terrill的校对和临门一脚。
Pierre Vignéras
Bull, Architect of an Open World™
*BPM Team*, Bull R & D
参考资料
脚注
资源
1. JWT2BPEL转换输出了这个BPEL文件。
2. 如果使用NetBeans把上一个资源给出的BPEL流程表示成一张图,我们会得到这样的图。该图表示了整个流程,中间的部分都收缩起来了(节点用“+”符号表示)。如果我们展开这个节点,我们会得到一张展开的图。在这个图中,我们可以看到包含有“+”符号的两个节点。它们分别代表了原始BPMN图中的“Employee Arrival”和“Ready to work”两个活动。从“Employee Arrival”节点,我们能够看到事件所隶属于的标记为C5的BPEL范围。在它的右边,能够看到那些事件。这些事件被用来以BPEL实现原始BPMN 图中描述的并行和非结构化流程。
查看英文原文:Why BPEL is not the holy grail for BPM?。