简体   繁体   中英

ddd - How to separate bounded contexts and share events?

I am actually reading a book called "DDD in PHP", to help me understand the Domain Driven Design. So far everything is good, but I struggle to understand how to implement one specific topic without coupling Bounded Contexts: Domain Events

Let's say I have to BCs :

  • Payments : Handles generation of invoices, sending them to the customers, etc
  • Orders : Handles the creation of orders, their state, etc.

When an Order is placed, an OrderCreated Event is dispatched. The Payments BC catches this event with a subscriber, and creates the invoice.

The problem is, If I want to perfectly separate both BCs, where should the OrderPlaced Event live, since it's used by both BCs ? Should it live outside both BCs ? In both of them ? What if I want to deploy the Invoices module as a standalone, without having access to the Orders module, and its OrderPlaced event definition, would it cause some fatal errors ?

Thank you in advance for the answers !

The problem is, If I want to perfectly separate both BCs, where should the OrderPlaced Event live, since it's used by both BCs ? Should it live outside both BCs ? In both of them ?

I would store the event in the context that owns it, ie the Orders context. How do you intend on separating the contexts? is it a physical / network boundary separation, or just conceptual?

What if I want to deploy the Invoices module as a standalone, without having access to the Orders module, and its OrderPlaced event definition, would it cause some fatal errors ?

It depends on what you are doing with OrderPlaced. If you are subscribing to it from some sort of event stream, then reacting to it inside InvoicesBC by way of converting it to an internal-to-invoices concept, then you'll probably be fine as you could just not deploy the subscriber. If your code in InvoicesBC can run without having to know about OrderPlaced then you should be fine

In general, there are a few ways to deal with this problem:

  1. Share a common definition. In C#, (not sure what the equivalent would be in PHP) in the past I've had a separate class library in the BC for the events that another BC might need (ie a MyContext.Contracts dll) that can then be referenced by other BC. These were published as internal nuget feeds (package manager stuff) so other contexts could keep themselves up to date.
  2. Weak serialization on the subscribing end. If you are subscribing to an event stream, you can deal with the raw representation it is stored in (ie JSON) rather than have some library automatically deserialize it into an object. If you go down this route, I'd suggest some "contract tests" in the publishing side that mimic what a subscriber would do. This will protect you from breaking your contracts with the outside world.

Although an answer has been accepted I would still like to add my opinion :)

They way your current BCs integrate is by subscribing directly to the messages published: Payments subscribes to OrderCreated . This style of interaction is called choreography . It isn't necessarily bad but you have to weigh the pros and cons. For instance, when you need to add a step in-between then you may have the Address BC subscribe to to the OrderCreated so that it can validate the delivery address. Now the Payments BC has to subscribe to the AdressValidated event. But then again, this event is published quite a bit since we also use it when registering customers. mmm...

Another option is to use orchestration where you explicitly store the state of the process in question. You my have an OrderProcess and a CustomerOnboardingProcess . You could then have your current BCs handle only messages within their own BC. Another process BC would then co-ordinate the messages and keep track of the state.

Two other issues one may run into with choreography are:

  • Having to wait for human intervention
  • Parallel processing where two tasks are running for the same process and one needs to bring the results back together again.

I hope that makes sense.

The question is if the Payments BC must create the invoice, because as the name suggests, it's concern should be payments and not orders or invoices .

Maybe something like this:

Orders -> 'order created' -> Payments -> 'payment done' -> Orders -> 'invoice created'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM