写点什么

BPEL 为何不是 BPM 的圣杯?

  • 2008-12-26
  • 本文字数:8370 字

    阅读完需:约 27 分钟

介绍

看看最新的文章和各类 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 种方式组合子程序,它就能实现任何可计算功能。这三种控制结构是:

  • 先执行子程序 1,然后执行子程序 2(顺序);
  • 根据布尔变量的值执行两个子程序中的一个(选择);
  • 执行一个子程序,直到布尔变量的值为真(循环)。

这基本意味着任何(非结构化的)流程图都能够转化成一个结构化的内容。这形成了 Dijkstra 的论文《Go To 语句是有害的》 [DIJKSTRA68] 的基础。

尽管仍然还有关于“我们是否应该允许非结构化编程语言的存在”的争论,但事实是:

  1. 世界上大多数的学生都被灌输了结构化语言;
  2. 使用最广泛的编程语言是(非严格的)结构化编程语言;
  3. 大多数非结构化编程语言已经引入了一些结构化单元(BASIC,COBOL,FORTRAN)。

因此一般而言,大多数程序员确实会关注结构化编程,但是有时出于各种原因(主要是可读性、维护,有时是性能)会使用非结构化语句(goto、jump、break、exceptions)。

业务分析师书写的并行和非结构化流程

业务分析师(BPM 的终端用户)必须处理现实世界 1 发生的事情,它不仅是非结构化的,而且是高度并行的。这包含两层含义:

  1. BPM 的终端用户通常都不是计算机工程师,也不是计算机科学家:他们使用为他们准备的流程图符号(这是最自然的)设计业务流程,因此是非结构化的(并且是并行的,这才是重点);
  2. 面对并行,非结构化比结构化更具有表现力。

第 2 点很重要的,它已被 Kiepuszewski 等人 [KIEPUSZEWSKI00] 正式证明了。事实上,存在有并行非结构化的工作流不能够被表示成并行结构化的工作流的情况。而且,这种例子非常容易找到。看看下面这个使用 BPMN 符号的例子(用 Intalio BPMN 设计器创建):

在一个使用 BPEL 作为它底层格式的工具中,为了验证这个图,需要创建一个单独的池。我们随后会讨论这个问题,但现在请重点关注名叫“Employer”的池及其包含的 6 个活动。只要一名新员工加入公司,一条工作流就会被启动。首先需要在人力资源数据库中创建一条记录。同时,必须提供一个办公室。一旦人力资源活动完成,员工就得接受医疗检查。在此期间,会提供给他一台计算机。而这只能出现在:办公室已经安排好且账户已在来自人力资源数据库的信息系统中创建好的情况下。在计算机已提供且医疗检查已结束的情况下,员工就可以开始工作了。当然,你可能希望用不同的方式建模这条简单流程,但是有一点我需要在这里指出,你无法创建一个等同于 2 本流程的一个结构化并行工作流,我的意思是,你永远也办不到!我们都将使用这个简单的例子贯穿全文。

从这个学习中,我们得出第一个结论:

  • 开发者会很自然地使用顺序的结构化单元(块 [Block]) 编写他们的程序;
  • BPM 用户会很自然地使用非结构化、并行的单元(图形)设计他们的流程;
  • 非结构化、并行的工作流比结构化、并行的工作流更具有表达力。

BPM 用户会设计出一些你无法用结构化的并行工作流表达的工作流。更糟的是,它也出现在了 [KIEPUSZEWSKI00] 中,作者表示:就算并行、非结构化工作流能够转换成并行、结构化工作流,但这需要额外的变化和(或)节点,以至于最终结果会导致对终端用户来说几乎无法读懂。我们很快会讨论这个可读性的问题。

BPMN 到 BPEL 的转换

在文章 [OUYANG06] 中,作者提出了从 BPMN 到(可读的)BPEL 的自动化转换。由于规范中的一些不清晰语义,他们定义了一个 BPMN 的子集。因此,他们在文中没有考虑 OR 网关(OR Gateway)和错误中继事件(Intermediate Events)。在待设计流程包含多个结束事件(End Event)的情况下,问题就来了。因为转换工具没有考虑它们,而把多个结束事件(End Event)工作流转换成单结束事件(End Event)工作流的标准方法就是使用 OR 网关(OR Gateway)。算法大致如下:

  1. 尽量找出图中可以直接映射到 BPEL 的已知模式(sequence、flow、pick、while……)。对于找到的每个模式,使用包含映射后 BPEL 代码的简单任务来代替这些组件。
  2. 接着,尽量找到一些“准结构化”组件,采用大多数组件直接映射成 BPEL 结构的方法,对它们进行转换。
  3. 接着,搜索非循环 BPMN 子模块(仅仅包含顺序流 [sequence flow] 和并行网关 [parallel gateway])。对于它们,使用 BPEL 控制连接(control link)。
  4. 最后,剩下的部分使用 BPEL 事件。

其结果就是一个“尽量可读的”等价 BPEL 流程。注意,我们总是可以使用 BPEL 中的事件来将 BPMN 转换成 BPEL。问题是,其生成代码根本就不可读。因而,结论是将任何 BPMN 图转换成一个等价 3 BPEL 流程的算法确实存在,只是结果是“尽量可读的” 4

Intalio 的用例

注意,下例中所表现的肯定不是 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。但产生的图还是太复杂了,无法在此展现(要了解该图的局部展现,请参见“资源”小节)。为了得到等价的 5 BPEL 描述,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](#footnotes)。不过,在流程能够实际执行之前仍需指定许多执行细节,这是 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
**<a name="biblio"> 参考资料 </a>**
- <a name="biblio">\[BPEL07\] </a>[OASIS, The BPEL Specification; (2007)](http://docs.oasis-open.org/wsbpel/2.0/wsbpel-v2.0.pdf)
- \[BPMN06\] [OMG, The BPMN Specification; (2006)](http://www.bpmn.org/Documents/OMG%20Final%20Adopted%20BPMN%201-0%20Spec%2006-02-01.pdf)
- \[BOHM66\] Bohm, Corrado and Giuseppe Jacopini, Flow diagrams, Turing machines and languages with only two formation rules; (1966)
- \[DIJKSTRA68\] [Dijkstra, Edsger, Go To Statement Considered Harmful; (1968)](http://www.acm.org/classics/oct95/)
- \[KIEPUSZEWSKI00\] [B. Kiepuszewski and A. H. M. Ter Hofstede and C. Bussler, On Structured Workflow Modelling; (2000)](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.85.2336)
- \[MILNER89\] Milner, R. 1989 Communication and Concurrency. Prentice-Hall, Inc.
- \[EKIE89\] Eike Best and Raymond Devillers and Astrid Kiehn and Lucia Pomello, Concurrent bisimulations in Petri nets; (1991)
- \[OUYANG06\] [Chun Ouyang and Marlon Dumas and Arthur H. M. Ter Hofstede, From Business Process Models to Process-oriented Software Systems: The BPMN to BPEL Way; (2006)](http://is.tm.tue.nl/staff/wvdaalst/BPMcenter/reports/2006/BPM-06-27.pdf)
- \[AALST\_UNKNOWNDATE\] [Wil M.P. van der Aalst1,2 and Kristian Bisgaard Lassen2, Translating Workflow Nets to BPEL](http://fp.tm.tue.nl/beta/publications/working%20papers/Beta_wp145.pdf)
- \[WHITE\_UNKNOWN\_DATE\] [Stephen A. White, Process Modeling Notations and Workflow Patterns](http://www.bpmn.org/Documents/Notations%20and%20Workflow%20Patterns.pdf)
**<a name="footnotes"> 脚注 </a>**
1. 有人会说,程序员也必须处理现实世界的事儿,但他们完全不在同一个抽象层面(否则,为分析师定义特定的符号又有何意义?)。
2. 当然,我们必须定义“等价”的含义。一般来说,在流程的世界中,使用的正式定义是“双向模拟(bisimulation)”\[MILNER89\]。但是鉴于它无法区分并行执行和它的顺序模拟(BPM 用户所希望的的),我们就用全并行双向模拟\[EKIE89\] 概念来替代它。
3. 参见全并行双向模拟的概念。
4. 参见人类可读的 BEPL 的公共思想,即,尽量用块(block)创建。
5. 顺便说一下,实现形式上确实等价(双向模拟)原始 BPMN 图的最终 BPEL 文件就留给读者您了……;-)
6. 可能也可以使用 UML-AD 符号,因为在表现力上它等价于 BPMN。不过,我们还是认为 BPMN 更贴近 BPM 分析师的要求。
** 资源 **
1\. JWT2BPEL 转换输出了 [这个 BPEL 文件](resource://JWT2BPEL-output.bpel)。
2\. 如果使用 NetBeans 把上一个资源给出的 BPEL 流程表示成一张图,我们会得到 [这样的图](resource://nbbpel1.png)。该图表示了整个流程,中间的部分都收缩起来了(节点用“+”符号表示)。如果我们展开这个节点,我们会得到 [一张展开的图](resource://nbbpel2.png)。在这个图中,我们可以看到包含有“+”符号的两个节点。它们分别代表了原始 BPMN 图中的“Employee Arrival”和“Ready to work”两个活动。从“Employee Arrival”节点,我们能够看到事件所隶属于的标记为 C5 的 BPEL 范围。在它的右边,能够看到那些事件。这些事件被用来以 BPEL 实现原始 BPMN 图中描述的并行和非结构化流程。
** 查看英文原文 **:[Why BPEL is not the holy grail for BPM?](http://www.infoq.com/articles/bpelbpm "Why BPEL is not the holy grail for BPM?")。
- - - - - -
给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 [editors@cn.infoq.com](mailto:editors@cn.infoq.com)。也欢迎大家加入到 [InfoQ 中文站用户讨论组](http://groups.google.com/group/InfoQChina) 中与我们的编辑和其他读者朋友交流。
2008-12-26 02:323483
用户头像

发布了 255 篇内容, 共 52.8 次阅读, 收获喜欢 9 次。

关注

评论

发布
暂无评论
发现更多内容

亚马逊Prime会员日火爆开启一站购全球逾3000万正品商品

爱极客侠

个人数字人民币钱包即将亮相

CECBC

央行 数字人民币

【第四周】系统架构

云龙

高难度对话读书笔记—聆听篇

wo是一棵草

LeetCode题解:94. 二叉树的中序遍历,使用栈,JavaScript,详细注释

Lee Chen

大前端 LeetCode

Programmatic Navigation using SwiftUI| 使用SwiftUI进行程序化导航

Daniel

中国银行正式启动区块链产业金融服务项目 ​

CECBC

区块链 金融 金融服务

一线城市年轻人生活工作实录(程序员篇)

Marilyn

敏捷开发 开发者工具 快速开发

有了TA,领域外企业里的小IT团队,也能轻松搞定大型项目

Marilyn

敏捷开发 快速开发

来喽,来喽,Python 3.9正式版发布了~~~

华为云开发者联盟

Python 编程

苦难过后,终会团聚

hellocj

第三周作业一

dll

Lindorm云原生数据库 - 让数字时代IT运维系统“灵动”起来

许力

DevOps APM Data Lake AIOPS

图扑软件联手阿里Lindorm数据库开启工业物联超融合存储模式

许力

IoT AIOT

国外的公司都是如何对待大龄程序员的?在国内该如何应对?

Java架构师迁哥

WSDM Cup 2020大赛金牌参赛方案全解析

华为云开发者联盟

大数据 搜索 信息

年轻人大企打拼多年,刚升迁便遇巨大阻力难以解决,到底如何才能在职场中幸存?

Marilyn

敏捷开发 快速开发

OKR-VUCA时代目标管理利器实践分享

张兆东

JVM-技术专题-对象的实例化过程

洛神灬殇

Java JVM

JVM-技术专题-Java类文件结构

洛神灬殇

Java JVM

翻译之深入注释俄罗斯民间故事的语料库,以实现对俄罗斯形式主义理论的机器学习

AI代笔

OpLog4j

Geek_746da6

区块链 | 最火的七大职业了解一下

CECBC

区块链技术人才

The story of programmers in famous enterprises.

Marilyn

敏捷开发 快速开发

在线教育企业迎来“秋招”大考,数字用户体验成胜负关键手

博睿数据

运维 APM 在线教育 AIOPS 用户体验

华为云专家讲述知识图谱构建流程及方法

华为云开发者联盟

华为 数据 知识图谱

我和我的智能联接

脑极体

拜托,学妹,别再问我怎么自学 Java 了!和盘托出

沉默王二

Java 自学编程

JVM-技术专题-类加载机制

洛神灬殇

Java JVM

从哲学源头思考自动驾驶网络架构设计

华为云开发者联盟

自动驾驶 架构

图解 K8S 源码 - Informer 篇

郭旭东

Kubernetes Kubernetes源码

  • 扫码加入 InfoQ 开发者交流群
BPEL为何不是BPM的圣杯?_SOA_Pierre Vigneras_InfoQ精选文章