Workflows design

I have worked, over the last two decades, on many state-based such as:

    graph LR;
    Cart[In cart] -->|Pay| Pending;
    Pending -->|Cancel| Canceled;
    Pending -->|Accept| Processing;
    Pending -->|Reject| Rejected;
    Pending -->|Expires| Rejected;
    Processing -->|Process| Done;

Cancel/Accept/etc. are actions/methods/functions/handlers/endpoints which sets and/or persist.

Even when it works well, it often comes with a tracking issue.

There are, as far as I know, two practices to deal with it.

The idea is to design events only, letting the status be a simple consequence, called a projection, of it.

Which would change our above example to:

    graph LR;
    CartCreated --> OrderPaid;
    OrderPaid --> OrderCanceled;
    OrderPaid --> OrderAccepted;
    OrderPaid --> OrderRejected;
    OrderPaid --> OrderExpireed;
    OrderAccepted --> OrderProcessed;

But it usually comes with "infrastructure", at code-level, costs and complexity.

Which is a way to regroup all stakeholders on a same board to align around a vision.

It comes with a rainbow of post-its:

  • Event: fact, what happened
  • Command: request/intent
  • Aggregate: coherent unit
  • View: decision data
  • Policy: business rule
  • Issues
  • Processes: external systems

But it has many strong assumptions:

  • The ability to regroup the right stakeholders
  • The ability for everyone to understand the workshop formalism
  • The leadership to drive, there are many point of view we have to reconcile:
    • Developers: how things are done
    • Users: how things are used
    • Experts: how things should be
  • The courage to throw the post-its at the end of the workshop: these workshops exist to come up with a shared understanding, not with direct, ready-to-code events

Even with a huge effort, we may encounter two problems:

  • An update in the logic which makes some events lose their meaning
  • An unplanned transition

The first problem can be solved by adding an Event-Carried State Transfer, which is an event added before or after an event batch, to track the state used by the end user to act on the entity.

The second problem is more disappointing.

Even on thoroughly explored domain, at some point, a user will request to set the status out of the regular transitions.

There are two ways to deal with it:

  • Resisting: letting users suffer, using existing transitions, like a make map
  • Accepting: adding admin tooling or a dedicated StatusForced event