Intended Stock Management design as I understand it

I was talking to Josh yesterday and peeking at the existing code, and I wanted to write down some brief comments on the design I think we want. (It’s possible that Josh and the China team have already discussed all this, and I’m a relative outsider on this point, so take this for what it’s worth.)

  • One key purpose of the Event-driven design is for configurability and extensibility by future implementations, and much of the specific business logic should live in Event Processor(s).

  • We want a CQRS approach where the only Command is “post an event”, and the Query model looks like the actual business domain (stock card, stock card line item, etc)

  • We do not need an Event Sourcing approach. Once the events are processed and the domain model is updated, we trust the domain model. We are not interested in “complete rebuild” or in recalculating the application state from events.
    I would expect that an event minimally looks like {“type”:“Event Type”}, and all additional fields depend on the event type. For example (these are made up, I’m not a domain expert)

  • {type: “Adjustment”, stockCard: “uuid”, correctAmounts: {/* by lots */}}

  • {type: “Transfer”, product: “uuid”, fromFacility: “uuid”, toFacility: “uuid” }
    I would expect that OpenLMIS provides default processors out of the box, to handle the 80% use case, and there’s one processor java class per event type. E.g. DefaultAdjustmentEventProcessor, DefaultTransferEventProcessor.

The framework we build would compose these individual event processors together. (I would probably go with a processor chain, where one by one we ask the processors “can you handle this event?”, but we could also delegate by event type.)

If an implementation wants different behavior, they should do a custom implementation of one or more processors, and inject them into the system with some extension mechanism (probably the same as the one prototyped by the soldevelo team last year). But hopefully in many cases it’s enough for them to write a new processor for just one event type, and use default processors for the remaining event types.

(If there are some scenarios where there’s not an 80% use case, but two 50% use cases, we could provide two different processor implementations out of the box, for the implementer to choose between, using the same extension/configuration mechanism.)

Peeking at the current code, I would want to make two directional changes:

  1. introduce StockEventProcessor as an interface to represent individual handlers for a single event, and the current StockEventProcessor becomes a StockEventService or AllStockEventProcessors that does the composition of the individual processors.
  2. Logic currently in StockCardLineItem.createLineItemsFrom(StockEvent) should move to one or more individual implementations of StockEventProcessor.
    (As I said, I know you all have talked a lot more, in conversations I was not in, but hopefully this is helpful.)
···

Darius JazayeriPrincipal Architect - Global Health
Email
djazayeri@thoughtworks.com

Telephone
+1 617 383 9369

ThoughtWorks