Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DDD referencing child entities across bounded contexts

Say I have a "Directory" bounded context with 2 aggregate roots. Company and Person. Company has a collection of child entities "Position" that hold the IDs of a person aggregate with some extra value data.

All good.

Now we go and add a "Article" bounded context with an aggregate root JobAriticle. This needs a Contact value object which is mapped from a company position.

So knowing that you should only reference aggregate roots what should I do? Assume there are invariants on the Company to Position relationship so I don't want to split the aggregate. Is it OK to map a Position through the anti corruption layer with both the company and position ids? Or do I need to try and break apart the company aggregate.

like image 480
Magpie Avatar asked Nov 06 '16 21:11

Magpie


1 Answers

If Position is a meaningful concept in the Ubiquitious Language of the "Article" bounded context then Position should be either a ValueObject or Entity in the "Article" bounded context.

If you're saying that Contact is the meaningful concept in the "Article" bounded context, but that it needs to somehow correlate with a Position in the "Directory" bounded context, then you need to think about what is the purpose of that correlation:

  • Do you need to verify that a position exists before creating a contact on a JobArticle?
  • Is there some shared data that will be kept in sync between a Position and a Contact?
  • What happens if a Position is archived/deleted or otherwise rendered out of service - do you have to do something to all the contacts?

If you need to verify that a Position exists before creating an associated Contact, then implicitly Position plays a role in the responsibilities of the Article context - so I would be tempted to create a new Position entity in the Article context and keep it in sync.

Either way, to correlate something in the Article context with a corresponding entity in the Directory context, you could create a ValueObject in the "Article" context called PositionCorrelation which would have two properties:

  1. CompanyId (globally unique)
  2. PositionId (locally unique within a company)

The rule that aggregates should only reference other aggregate roots doesn't mean that you can't also provide information with which to identify entities within the aggregate. It just means that if you want to interract with the other entity, you should do it via the aggregate root, which means you must at least have the aggregate root Id. If you then use a local Id to ask the Company to do something to one of it's positions, that's fine.

But - be aware, that by following this approach, you are introducing the term "Position" into the "Article" bounded context, which may introduce a name collision if the word "Position" means something else in the "Article" context - e.g. perhaps it means the position within an article (paragraph number etc.). If this is the case, you need to think carefully about what to call the cross-context identifier.

One approach could be that if Position has a one to one map with Contact, then you could have your two properties be:

  1. CompanyId
  2. CompanyContactId

And when keeping in sync at the Anti-Corruption layer (ACL) when integrating between the contexts, define CompanyContactId and PositionId (local within Company) values as being synonomous. This keeps each UL internally consistent and defines the correlation between the two in an ACL.

like image 61
Chris Simon Avatar answered Oct 02 '22 13:10

Chris Simon