cosmicpython / book

A Book about Pythonic Application Architecture Patterns for Managing Complexity. Cosmos is the Opposite of Chaos you see. O'R. wouldn't actually let us call it "Cosmic Python" tho.
https://www.cosmicpython.com
Other
3.39k stars 527 forks source link

Error Handling in Ch 8/9? #169

Closed xtaje closed 4 years ago

xtaje commented 4 years ago

I think there is an issue for ChangeBatchQtyCmd that is unlikely, but not impossible.. It could serve as a good segue to other topics.

The scenario looks like this:

In practice, this means that a customer's PLUSH-MICROFIBER-TOILET-SEAT would never be allocated. Exactly what happens afterwards depends on how your systems are setup (maybe an order management system notices that a product has failed to ship? Is there an audit/reconciliation business process? etc.) Or maybe you decide this scenario is acceptable given how unlikely it is, the cost when it does occur is very low, and it can be handled by human intervention (i.e., the customer will email support).

Suppose however, that your company is wildly successful, and expands into other verticals that involve managing inventory like WEAPONS-GRADE-PLUTONIUM-SAMPLE, MEDICAL-CADAVER, or 2KG-VIBRANIUM-BRICK,. All inventory must be strictly accounted for, any loss would have serious repercussions, and the above mitigation strategies are unacceptable.

The requirements have changed, and now your domain model needs to be adjusted. Possible options might include:

These could be exercises or new topics for future editions.

hjwp commented 4 years ago

can i just say how much i appreciate the SKUs? <3

pedroabi commented 4 years ago

It's looks similar to https://github.com/cosmicpython/book/issues/175

My example was about Ordering and Allocating.

pedroabi commented 4 years ago

Take a look at this post: https://lostechies.com/jimmybogard/2010/04/08/strengthening-your-domain-domain-events/

If we need to guarantee that aggregates are consistent across the model, we should dispatch synchronous events and after all of them processed we should commit the transaction.

"This pattern isn’t always applicable. If I need to do something like send an email, notify a web service or any other potentially blocking tasks, I should revert back to normal asynchronous messaging. But for synchronous messaging across disconnected aggregates, domain events are a great way to ensure aggregate root consistency across the entire model. The alternative would be transaction script design, where consistency is enforced not by the domain model but by some other (non-intuitive) layer."

pedroabi commented 4 years ago

Another great reference: https://stackoverflow.com/questions/4691710/should-domain-events-be-raised-within-or-outside-of-a-transaction

xtaje commented 4 years ago

Those are good links, but I believe the error scenario differs in some significant ways. In #175 and the los techies blog, the action spans different bounded contexts and/or different aggregates (e.g. Fee and Customer).

In the error scenario, the action is within one bounded context and on a singleProduct entity. So decoupling the reallocation using DomainEvents is not absolutely necessary, and potentially creates a small liability. IIRC CH5 actually has a reallocate example which does not use domain events. Yet another option be to use that as a handler, and introduce the idea of a ReallocationNeeded event. Or maybe you double allocate the order line, and let it get reconciled later, ... etc.

WRT the stack overflow post, I see how that solution could work, but in practice I'd be concerned about some pitfalls. Because the unit work is not yet completed, the state of the aggregates may be indeterminate. A DomainEvent that triggers a synchronous handler (which is decoupled and should be ignorant of any outstanding transactions) might get a stale read. Also, interrupting the processing of one message to start processing a different one will be incompatible with the actor model.

Based on this issue, here's a bunch of ideas on additional content worth discussing:

bobthemighty commented 4 years ago

The requirements have changed, and now your domain model needs to be adjusted.

This is the answer to the question 😂

The domain model we use in this book isn't actually from the allocation system at Made, it's from the read-side, it's the availability system and it answers questions about how much stock is available at what lead time. In that domain, if we drop a bit of data, it's a total non-issue.

We use it in the book because it's just complex enough to warrant some real modelling without being off-putting.

I left MADE before we wrote the new Allocation system, and there were a whole bunch of ways we could do it. My favourite in terms of elegance is a system where we use events to derive the model of available stock, and the model of unsatisfied orders, and write a deterministic function that maps one onto the other.

Every time anything changes, you run the whole thing again and you end up with the same orders allocated to the same lines, modulo whatever's actually changed. That's conceptually neat and realy robust to failures, because you just boot it back up and it carries on where it left off.

xtaje commented 4 years ago

We use it in the book because it's just complex enough to warrant some real modelling without being off-putting.

:metal: I had been wondering what the actual system the example was based on.

For the book, I had imagined a silly narrative where MADE is acquired by a global mega-corp in 2080, and needs to furnish a deep space research vessel. MADE's allocation service is so good that they decide to re-purpose it for ship onboard inventory, and then ...

My favourite in terms of elegance is a system where we use events to derive the model of available stock, and the model of unsatisfied orders, and write a deterministic function that maps one onto the other.

Double left fold + join!

xtaje commented 4 years ago

This is covered with sections in epilogue on footguns.