How to Communicate Between Bounded Contexts Without REST API

Architecturedomain-driven-design

Question:

  • If I have to fetch an entity from another Bounded Context in order to map it to something in this Bounded Context, how would I go about doing that?
  • Do I call the foreign Bounded Context's Application Layer? Perhaps I need a new "Query" Application Layer for such queries?
  • Do I call foreign Bounded Context's repositories?
  • Do I call foreign Bounded Context's Domain model directly?

Domain model (please note two separate Bounded Contexts):

  • CustomerContext.Customer – this is the complete Customer model.
  • ConsentContext.Person – a scaled-down, heavily transformed version of multiple instances of CustomerContext.Customer. Rules guiding this transformation reside in ConsentContext.Person. Person never references ˙Customer` directly, no dependency here.
  • Please note: these two entities most definitely belong to separate Bounded Contexts. Customer is what the business works with on a daily basis. Consent Person is heavily transformed due to legal and business requirements and has a different structure altogether. Customer is merely a data source, so Person can create itself using internal business logic.

Application Layer:

  • ConsentContext.ApplicationService – implements use cases. As part of those use cases it fetches ConsentContext.Person through some PersonRepository.

Repos:

  • ConsentContext.PersonRepository has to get in touch with the CustomerContext and retrieve the CustomerContext.Customer and map to a new Person. This is where I am coming up short – what do I call from here? CustomerContext's Application Layer? CustomerContext's repositories? CustomerContext's Domain model directly?

Other:

  • Both Bounded Contexts run in the same process, I am not using a REST API.
  • I am targeting Customer/Supplier relationship.

Best Answer

I’m going to sidestep the discussion of whether there really are two bounded contexts, and address the question of how they can share data. Before doing that, however, I have to point out that you are doing yourself a disservice by having 2 bounded contexts in the same process. From Microsoft’s definition

Bounded contexts are autonomous components, with their own domain models and their own ubiquitous language. They should not have any dependencies on each other at run time and should be capable of running in isolation. However they are a part of the same overall system and do need to exchange data with one another.

A big advantage of bounded contexts is their independence from one another. If one goes down, the other should survive and be able to keep functioning. This also helps in scalability by allowing deployment on different servers if the app gets more popular than expected.

Note that 2 process spaces doesn’t have to mean 2 servers. They can both share the same hardware but should have as little coupling between them as possible, meaning no coupling in code.

Along the coupling idea, we have this from Eric Evans

Code reuse between BOUNDED CONTEXTS is a hazard to be avoided.

All of the options provided above violate this guidance.

So your question has to do with the final sentence of the Microsoft definition of a Bounded Context. These are your options in order of preference

Each context can cache the information in needs from the other contexts. This is done via an event queue or message queue that all contexts share, and as important aggregates change they inform other interested contexts. Julie Lerman has a good discussion of it here. If you want to stick with a single piece of hardware, the message queue can also run on that hardware, though that would introduce some scalability and durability concerns.

Second option is to add an API. I know you say you don’t have one, but APIs can be deployed as part of the context so they are little extra work. They can also be locked down to only accept requests from localhost using CORS rules.

Third option is a shared database, but now we’re coupling the contexts so this is a dangerous road. If you MUST do this, at least make the tables in separate schemas so the developer is aware they are breaking the wall between the contexts.

I would avoid all three of the options you have listed. It’s not hard to imagine requirements changing in one context that conflict with the rules in another. After all, that’s why you separated them into separate contexts to begin with.

Related Topic