domain-driven-designbounded-contexts

What's wrong with multiple entities in multiple bounded contexts pointing to the same identity?


Following this answer from different question I've been somewhat shocked with the following statement:

An aggregate in one BC would be represented either by an id or as a value object in another BC. Only a single BC should be the system of record of any aggregate.

What I do agree with, is the fact, that only one BC should be the owner of the given identity (the initiator of that identity presence in the whole system). But what is confusing to me, is the statement, that every other BC should represent the same concept only as a read only value object with just the subset of the attributes of the entity from BC that owns the given identity (no extra attributes related to consuming BC).

Using a Customer as an example, what's wrong with representing it as an entity in multiple BCs with different attributes in each BC (especially, when there's some BC related, user editable config, which wouldn't make sense in another BC at all), but sharing the same identity? I tought, that this is the essence of the bounded context definition - to represent the same concept (same real world identity) in different domains with the behavior and attributes only related to that given domain. Am I missing something? Is it better to use single BC for CustomersManagement with all possible attributes (user editable config) that all other BCs could use?


Solution

  • I may be stating some obvious bits here, but please bear with me as I put it all together.

    The following statement refers only to the aggregate itself, not the identity:

    An aggregate in one BC would be represented either by an id or as a value object in another BC. Only a single BC should be the system of record of any aggregate.

    The main concept here is that a particular aggregate root has a single system of record. This idea isn't unique to domain-driven design. Traditionally, a database record would also only have a single source of truth.

    When it comes to the identifier of an aggregate, or record, it can literally be anything unique.

    If you have a Customer then the system of record is probably your CRM system and any and all changes related to data that is maintained by the CRM system should only ever be changed there. If you need to have a Customer in your own, say, Orders BC then you'll have either only the CustomerId or a Customer value object that contains some minimal data that is, still, maintained in the CRM system. You wouldn't ever make changes to the data in your BC that is maintained in the CRM system; else they are immediately out of whack, and trying to replicate data back up-stream isn't only painful, but it is usually not a good idea (multiple conflicting updates from downstream systems, for instance). If you only have the customer id then you'd need to ask the CRM system, probably via and API of sorts, for any additional data. That is a design choice. Copies of data would need to kept up-to-date and messaging / event-driven architectures are useful here.

    Now, if you'd like to relate any data to a particular customer in your own BC then you are creating a new aggregate in your BC that is related to the customer, but your BC is the system of record for that data. How you end up relating it is, again, a design choice. Let's go with a CustomerProfile in your Orders BC where you have some BC-specific data such as customer level (Gold, Silver, Bronze, etc.). You could have the Id of that profile simply be the same id from the CRM system, or you could map it. Perhaps there are different profiles based on some type and the profile has its own id but still also has a CustomerId that it is linked to.

    This is something that isn't uncommon and is a form of a weak reference that one typically finds across systems. For instance, you receive an Invoice from a supplier and you register it in your system. You'll probably have your own invoice with all relevant data which includes an ExternalReference where you'd store the InvoiceNumber received from the supplier.

    To answer you question as to whether there is anything wrong with having your own Customer in different BCs, there isn't necessarily anything wrong with it as long as it fits into the ubiquitous language of the domain experts. I've used the example of a seat in a stadium. The Finance BC maintains the asset register and keeps track of depreciation. The Maintenance BC cares about work orders and general maintenance of the seat. The Events BC cares about booking the seat for events. Each of these have their own view of the physical seat and they have different behaviours, and chances are that they are not event called Seat in any of the BCs. The Finance folks would call it an Asset, the Maintenance folks would perhaps call it Component, and the Events folks may call it a BookableItem (such as a seat, or a bicycle, or a VIP suite). However, when the maintenance department removes a seat for repairs it will need to publish an event notifying any interested parties. The Events BC would then mark that seat as Unavailable. All these BCs would need to know about the seat and have a common identifier, probably the one in the asset register.

    I hope I understood your question/concern correctly.