Maxim Fateev
2 min readJul 28, 2019

--

I absolutely agree that Zeebe is the only cloud-native and scalable solution in BPMN space. I’m not convinced that having a separate language for workflows like BPMN is necessary. There is a reason we don’t right complex business application and operating system kernels in JSON or XML. Existing visual languages are inferior to high level programming languages in dealing with complexity. They work well with 10 visual elements, but not with 1500. And we have programs that spawn millions line of code and still manageable.

In my opinion the main limitation of BPMN for service orchestration is that most of the complexity is not in the sequencing of operations but in arguments to them. For example Banzai Cloud UpdateClusterWorkflow flow which uses Go Cadence client is relatively simple with multiple parallel split joins and would potentially be represented by a nice BPMN diagram. But that diagram would hide all the arguments that have to be passed to activities and the non trivial ways they have to be manipulated. The strong typing of Go is also a benefit here as it catches most of the argument passing errors at compile time.
The same applies to the SAGA example you provided. It specifies only sequencing of operations and completely hides the arguments that are passed to them. Compare it to the same example written using Cadence Java Client:

    // Configure SAGA to run compensation activities in parallel
Saga.Options sagaOptions = new Saga.Options.Builder()
.setParallelCompensation(true).build();
Saga saga = new Saga(sagaOptions);
try {
String carReservationID = activities.reserveCar(name);
saga.addCompensation(activities::cancelCar,
carReservationID, name);
String hotelReservationID = activities.bookHotel(name);
saga.addCompensation(activities::cancelHotel,
hotelReservationID, name);
String flightReservationID = activities.bookFlight(name);
saga.addCompensation(activities::cancelFlight,
flightReservationID, name);
} catch (ActivityException e) {
saga.compensate();
throw e;
}

All argument passing is explicit and the whole workflow code is easy to understand. The other cool feature is unit testing. As workflow is just natural code any existing unit testing framework can be used. For example here is a unit test that uses mockito to test the correctness of a SAGA execution:

@Test
public void testSAGA() {
TripBookingActivities activities =
mock(TripBookingActivities.class);
when(activities.bookHotel("trip1"))
.thenReturn("HotelBookingID1");

when(activities.reserveCar("trip1"))
.thenReturn("CarBookingID1");
when(activities.bookFlight("trip1"))
.thenThrow(new RuntimeException(
"Flight booking did not work"));
worker.registerActivitiesImplementations(activities); testEnv.start(); TripBookingWorkflow workflow =
workflowClient.newWorkflowStub(TripBookingWorkflow.class);
try {
workflow.bookTrip("trip1");
fail("unreachable");
} catch (WorkflowException e) {
assertEquals("Flight booking did not work",
e.getCause().getCause().getMessage());
}
verify(activities)
.cancelHotel(eq("HotelBookingID1"), eq("trip1"));
verify(activities)
.cancelCar(eq("CarBookingID1"), eq("trip1"));
}

--

--

Maxim Fateev

Cofounder/CEO Temporal Technologies. Tech lead of Uber Cadence Workflow, Uber Cherami, AWS SWF and AWS SQS clustered storage.