I'm trying to design a workflow engine using a DDD approach.
Context
- (B1) Assign items to a workflow
- Invariant: depending on their types, items can only start the workflow on specific steps.
- (B2) Attach/detach items to other items
- Invariant: all items (container and elements) must be on the same step.
- (B3) Transition items from one step to another
- Invariant 1: the transition should also be applied to their children.
- Invariant 2: items inside a container can't be transitioned directly.
Clients may have several active workflows. They just know about items (or some VO representing an item). Everything should be done through a facade.
Preferred solution
So far, I designed it as a typical graph.
Workflow (AR)
holds all steps. Steps (entity)
contains the items & allowed transitions. Items (entity)
knows its parent and its children.
Pros & cons
The consistency boundary looks ok. Even though I could be changing the same workflow on different transactions, as long as the items aren't the same everything should work.
B2 and B3 may have a race condition, but it might be ok they do as the invariants kind of depend on each other.
Usually, you work on one step at the time. So loading the whole workflow seems unnecessary. Also, I can't think of a natural way of loading it with the items in the correct steps.
This solution looks fine. However, I feel something is missing.
Another things I've thought about
Create a
Associations
ARThe Associations AR would have a reference to the parent item and a collection of children items. Here I could query the workflow and check if the items are in the same step to keep B2 invariant.
However, this is a bit fragile as the entities could be transitioned on a different transaction and I'd not know it.
Step as AR
As you usually work on one Step at a time, this could be a possible solution. However, B2 2nd invariant can't be 100% enforced. Also I'd need to raise an event to perform B3.
Any thoughts/opinions about it? Thanks!