Why Business Process Languages?
October 22nd, 2008 by matthieu
I’ve heard that too many times when first mentioning what a business process language does to a random hacker “So this is some sort of bash script, right?” (bash being a fairly powerful Linux shell). So let me say that clearly: a business process language has very little to do with bash. Except maybe that they’re both domain specific languages (like SQL, or HTML, or a wiki markup).
But what people usually really want to ask is why one would need a specific language to write business processes. Why a general purpose language like Java, C#, Ruby, Python or Perl wouldn’t fit the bill. Why one would want to learn a new language.
The first thing to realize, if you haven’t already, is that programming languages are made for people to write or read, not for machines. Otherwise we would all program in assembler or poke our way in hexadecimal. So a language that makes writing (maintaining, reading, generating, …) a given program significantly easier is usually worth the upfront effort. At least if it’s been well designed. Even so-called general purpose languages all have their sweet spot and pain factors.
That being clarified, let’s see with an example how the need for a Business Process Language (BPL) would arise and what would be so different about it that it would motivate a specific language.
A Use Case
Say that you want to develop the service I mentioned in my last post, to guide people through the process of buying a home, from financing to finding an agent to the end of escrow. You want to develop this service as a Ruby on Rails website, where people can see a clear outline of what to expect with approximate dates, browse apartments and houses based on their criteria (maybe partnering with other services), select banks from offers that are automatically made to them, etc. You also want to remind them by e-mail or SMS when a deadline approaches for example.
The raw services that provide each or these functionality will be either implemented by you or by a partner you communicate with. The communication channel doesn’t really matter for now. On top of that you’re going to need some sort of glue that will implement what obviously look like a long-living, non trivial process. That process can change from one day to the other based on new legislation, new partnerships or evolution of your business where you’d provide additional functionalities.
As your web site is mostly a Rails application, you decide to implement that process using Ruby, which is also pretty good at gluing things together. Your first task is going to be implementing the primitives to invoke your backend services or your partners’ services. Your services are most likely going to be RESTful Rails services and your partners might do SOAP. Now that you have that you can implement your first naive script, doing those calls and implementing the process logic, including timers, loops, conditions, etc.
Now there are obvious problems here. The overall process can last several weeks, you can’t afford to lose all that data if you have a server failure. Or if you have to restart your application. Or upgrade. So you’re going to have to add some sort of persistence, the idea being that any of those process executions can survive a restart.
Adding persistence in your script is actually non trivial work. You need to find places where you can “snapshot” the execution in the script and resume from there. So far you hadn’t made those places explicit so you’ll probably need to rewrite your process to make them more obvious and then add more code to handle the saving and restoring of the process state. Knowing the exact position in the script is not enough because you have conditions and iterations, so you need to know exactly what was the path that leads you to where a process is currently executing and what is the current value of the variables used by your process.
Another problem arises when you start thinking of failure scenarios. Say that a user selects a mortgage that he likes from all the offers that were made to him. But since the offer, the loan percentage has increased. You only discover that when you actually try to lock the loan with the bank, which refuses it. So now you need to “go back” in your process, notify your user and possibly cancel a few steps that happened in the middle (like notifying the seller). And there are multiple places in your overall process where similar business failures can happen.
Also asynchronous interactions are actually not so trivial. To get loan offers from banks you invoke all the ones you have a contract with and they guarantee a reply within 6 hours. So you have to wait for and collect all those replies. If you have thousands of users, you can’t have thousand of processes physically waiting and locking resources (memory mostly), your data center will explode before you know it.
By now it should be clear that the naive Ruby script encoding your business process is evolving toward a full blown, homegrown kitchen sink. And I haven’t even brushed up the surface of what could go wrong.
That kitchen sink is what most applications where a direct need for business processes tooling (and a programming language is a tool in my book) hasn’t been identified end up with.
Business Process Languages and Runtimes
The requirements that influence the writing and execution of business processes trickle down at the language and runtime level. I’m going to introduce here what are the design impacts on a business process language. In later posts, I’ll probably address how those are handled in SimPEL and also how Apache ODE supports the runtime requirements.
What you should expect from a Business Process Language (BPL) is:
- Conditionals, loops (alternatively recursion) and variables.
- Native high level process specific constructs.
- At least implicit support for persistable continuations.
- Long-living transactions.
The first point just guarantees a minimal level of expressiveness.
The second point means that BPLs usually have language keywords or constructs relevant to the domain. Simple things like process waiting. And more complex ones like asynchronous interactions or parallel processing (two branches of execution happening at the same time).
The third point guarantees that the whole state and the current execution step can be suspended and saved at any point in time in your process. As illustrated in my previous example, you need to be able to pause and resume execution pretty much at any point. Practically, the BPL usually constrains when those pauses happen (which doesn’t mean that the runtime should be similarly constrained).
Finally, the support of long-living transactions requires language-level mechanisms to deal with the failure of long-living transactions. It usually requires some error handling primitives (like throw and try/catch) and the notion of a unit of work that makes rollbacking possible.
Note that I haven’t defined anything really groundbreaking, most existing BPLs cover all or most of the points that I’ve listed.
Concluding Remarks
By now, you should have realized what motivates the use of a language specialized for business processes and have some ideas of what to expect from one. Hopefully that will help you identify situations where a BPL could be a good fit.
In this post I’ve only been talking about executable business process languages. You’ve probably heard of BPMN, which is strictly about modeling. Just like in many other problem space, there’s a wide spectrum of possible languages or notations which address different levels of abstraction. Take a typical Java application for example, a whole lot of languages have usually been used before its final execution. Plain English for specifications. UML for design. The internal representation of Java constructs that an IDE uses (its AST). Java for the application (it doesn’t end here). Bytecode that gets fed in the virtual machine. The VM internal representation. And finally machine code. All those different levels exist for a reason, they all address a different degree of abstraction. Some need to be public and standardized (English, UML, Java, Java bytecode), others don’t.
The fallacy is that a single language or notation can handle all those different levels of abstraction or detail. Standard high level notations are good and needed. Standard lower level programming languages are good and needed. And even the standardization of bytecode level representations for process runtimes could be good and needed, to encourage a strong runtime ecosystem.
There’s a lot of work left, I’m off coding now…
Posted in Uncategorized | No Comments »