DDD How to fetch a list of value objects - domain-driven-design

I have a domain model
Customer - Aggregate root - because an order can't exist without a customer
Order - entity
OrderStatus - value object
In my form I need a list of all OrderStatuses.
Should I fetch an empty customer entity(AR) from repository with an empty order entity which is containing a list of all OrderStatuses? This is awkward.

Well, it always depends on your problem domain, but lacking further info, I would say you probably need to break your modeling a little bit.
Even though an Order can't exist without a Customer, it will not be a child entity under the Customer AR. You need to introduce the notion of Bounded Contexts.
Customer would be the AR of one BC, while Order would be the AR of its own BC.
In that case, you would reference Customer from Order with a CustomerId property (not with an object reference) because they belong to different contexts, and as such they could even live in separate microservices, in separate databases.
You see where I'm going: it makes no sense to fetch an empty Customer, with an empty Order (or list of Orders) just to reach a list of Order Statuses.
Even if Order and Customer did belong to the same BC, OrderStatus is Reference Data, and would be better represented by an enum type (or better, with the Enumeration Pattern).
Have a look at this additional info:
Reference data as code
Entities, Value Objects, Aggregates and Roots

Related

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.
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:
CompanyId (globally unique)
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:
CompanyId
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.

DDD Which is the root Aggregate root?

Lots of examples like order and order lines makes sense, like:
Order is an AR that contains OrderLines
Customer is an AR that contains Orders.
Question is, what is the AR that contains Customer?
I guess it can be something like "shop".
So, shop.AddCustomer(customer)...
but, how to get shop?
If it's an AR (entity) it has an id, so shop.GetById(shopId). If I only have one shop, how does this work with persistence?
Should I have a table (shops) with one line?
Shop is an in-memory object with a collection of Customers?
You got that wrong there. Aggregates do not contain other aggregates! They can only reference them by ID.
An aggregate is a group of entities and value objects that are closely related. The aggregate forms a consistency boundary around them. The Aggregate Root is the root entity in that aggregate that is globally addressable. So in your example with Order and OrderLines, Order could indeed be the AR.
Customer on the other hand, would only reference Orders by ID if it is a separate aggregate.
To retrieve an aggregate, you typically use a Repository. You load an aggregate through the repository by specifying the ID of the aggregate, or some other suitable search parameter.

Few confusing things about globally accessible Value Objects

Quotes are from DDD: Tackling Complexity in the Heart of Software ( pg. 150 )
a)
global search access to a VALUE is often meaningles, because finding a
VALUE by its properties would be equivalent to creating a new instance
with those properties. There are exceptions. For example, when I am
planning travel online, I sometimes save a few prospective itineraries
and return later to select one to book. Those itineraries are VALUES
(if there were two made up of the same flights, I would not care which
was which), but they have been associated with my user name and
retrieved for me intact.
I don't understand author's reasoning as for why it would be more appropriate to make Itinierary Value Object globally accessible instead of clients having to globally search for Customer root entity and then traverse from it to this Itinierary object?
b)
A subset of persistent objects must be globaly accessible through a
search based on object attributes ... They are usualy ENTITIES,
sometimes VALUE OBJECTS with complex internal structure ...
Why is it more common for Values Objects with complex internal structure to be globally accesible rather than simpler Value Objects?
c) Anyways, are there some general guidelines on how to determine whether a particular Value Object should be made globally accessible?
UPDATE:
a)
There is no domain reason to make an itinerary traverse-able through
the customer entity. Why load the customer entity if it isn't needed
for any behavior? Queries are usually best handled without
complicating the behavioral domain.
I'm probably wrong about this, but isn't it common that when user ( Ie Customer root entity ) logs in, domain model retrieves user's Customer Aggregate?
And if users have an option to book flights, then it would also be common for them to check from time to time the Itineraries ( though English isn't my first language so the term Itinerary may actually mean something a bit different than I think it means ) they have selected or booked.
And since Customer Aggregate is already retrieved from the DB, why issue another global search for Itinerary ( which will probably search for it in DB ) when it was already retrieved together with Customer Aggregate?
c)
The rule is quite simple IMO - if there is a need for it. It doesn't
depend on the structure of the VO itself but on whether an instance of
a particular VO is needed for a use case.
But this VO instance has to be related to some entity ( ie Itinerary is related to particular Customer ), else as the author pointed out, instead of searching for VO by its properties, we could simply create a new VO instance with those properties?
SECOND UPDATE:
a) From your link:
Another method for expressing relationships is with a repository.
When relationship is expressed via repository, do you implement a SalesOrder.LineItems property ( which I doubt, since you advise against entities calling repositories directly ), which in turns calls a repository, or do you implement something like SalesOrder.MyLineItems(IOrderRepository repo)? If the latter, then I assume there is no need for SalesOrder.LineItems property?
b)
The important thing to remember is that aggregates aren't meant to be
used for displaying data.
True that domain model doesn't care what upper layers will do with the data, but if not using DTO's between Application and UI layers, then I'd assume UI will extract the data to display from an aggregate ( assuming we sent to UI whole aggregate and not just some entity residing within it )?
Thank you
a) There is no domain reason to make an itinerary traverse-able through the customer entity. Why load the customer entity if it isn't needed for any behavior? Queries are usually best handled without complicating the behavioral domain.
b) I assume that his reasoning is that complex value objects are those that you want to query since you can't easily recreate them. This issue and all query related issues can be addressed with the read-model pattern.
c) The rule is quite simple IMO - if there is a need for it. It doesn't depend on the structure of the VO itself but on whether an instance of a particular VO is needed for a use case.
UPDATE
a) It is unlikely that a customer aggregate would have references to the customer's itineraries. The reason is that I don't see how an itinerary would be related to behaviors that would exist in the customer aggregate. It is also unnecessary to load the customer aggregate at all if all that is needed is some data to display. However, if you do load the aggregate and it does contain reference data that you need you may as well display it. The important thing to remember is that aggregates aren't meant to be used for displaying data.
c) The relationship between customer and itinerary could be expressed by a shared ID - each itinerary would have a customerId. This would allow lookup as required. However, just because these two things are related it does not mean that you need to traverse customer to get to the related entities or value objects for viewing purposes. More generally, associations can be implemented either as direct references or via repository search. There are trade-offs either way.
UPDATE 2
a) If implemented with a repository, there is no LineItems property - no direct references. Instead, to obtain a list of line items a repository is called.
b) Or you can create a DTO-like object, a read-model, which would be returned directly from the repository. The repository can in turn execute a simple SQL query to get all required data. This allows you to get to data that isn't part of the aggregate but is related. If an aggregate does have all the data needed for a view, then use that aggregate. But as soon as you have a need for more data that doesn't concern the aggregate, switch to a read-model.

How should I enforce relationships and constraints between aggregate roots?

I have a couple questions regarding the relationship between references between two aggregate roots in a DDD model. Refer to the typical Customer/Order model diagrammed below.
First, should references between the actual object implementation of aggregates always be done through ID values and not object references? For example if I want details on the customer of an Order I would need to take the CustomerId and pass it to a ICustomerRepository to get a Customer rather then setting up the Order object to return a Customer directly correct? I'm confused because returning a Customer directly seems like it would make writing code against the model easier, and is not much harder to setup if I am using an ORM like NHibernate. Yet I'm fairly certain this would be violating the boundaries between aggregate roots/repositories.
Second, where and how should a cascade on delete relationship be enforced for two aggregate roots? For example say I want all the associated orders to be deleted when a customer is deleted. The ICustomerRepository.DeleteCustomer() method should not be referencing the IOrderRepostiory should it? That seems like that would be breaking the boundaries between the aggregates/repositories? Should I instead have a CustomerManagment service which handles deleting Customers and their associated Orders which would references both a IOrderRepository and ICustomerRepository? In that case how can I be sure that people know to use the Service and not the repository to delete Customers. Is that just down to educating them on how to use the model correctly?
First, should references between aggregates always be done through ID values and not actual object references?
Not really - though some would make that change for performance reasons.
For example if I want details on the customer of an Order I would need to take the CustomerId and pass it to a ICustomerRepository to get a Customer rather then setting up the Order object to return a Customer directly correct?
Generally, you'd model 1 side of the relationship (eg., Customer.Orders or Order.Customer) for traversal. The other can be fetched from the appropriate Repository (eg., CustomerRepository.GetCustomerFor(Order) or OrderRepository.GetOrdersFor(Customer)).
Wouldn't that mean that the OrderRepository would have to know something about how to create a Customer? Wouldn't that be beyond what OrderRepository should be responsible for...
The OrderRepository would know how to use an ICustomerRepository.FindById(int). You can inject the ICustomerRepository. Some may be uncomfortable with that, and choose to put it into a service layer - but I think that's overkill. There's no particular reason repositories can't know about and use each other.
I'm confused because returning a Customer directly seems like it would make writing code against the model easier, and is not much harder to setup if I am using an ORM like NHibernate. Yet I'm fairly certain this would be violating the boundaries between aggregate roots/repositories.
Aggregate roots are allowed to hold references to other aggregate roots. In fact, anything is allowed to hold a reference to an aggregate root. An aggregate root cannot hold a reference to a non-aggregate root entity that doesn't belong to it, though.
Eg., Customer cannot hold a reference to OrderLines - since OrderLines properly belongs as an entity on the Order aggregate root.
Second, where and how should a cascade on delete relationship be enforced for two aggregate roots?
If (and I stress if, because it's a peculiar requirement) that's actually a use case, it's an indication that Customer should be your sole aggregate root. In most real-world systems, however, we wouldn't actually delete a Customer that has associated Orders - we may deactivate them, move their Orders to a merged Customer, etc. - but not out and out delete the Orders.
That being said, while I don't think it's pure-DDD, most folks will allow some leniency in following a unit of work pattern where you delete the Orders and then the Customer (which would fail if Orders still existed). You could even have the CustomerRepository do the work, if you like (though I'd prefer to make it more explicit myself). It's also acceptable to allow the orphaned Orders to be cleaned up later (or not). The use case makes all the difference here.
Should I instead have a CustomerManagment service which handles deleting Customers and their associated Orders which would references both a IOrderRepository and ICustomerRepository? In that case how can I be sure that people know to use the Service and not the repository to delete Customers. Is that just down to educating them on how to use the model correctly?
I probably wouldn't go a service route for something so intimately tied to the repository. As for how to make sure a service is used...you just don't put a public Delete on the CustomerRepository. Or, you throw an error if deleting a Customer would leave orphaned Orders.
Another option would be to have a ValueObject describing the association between the Order and the Customer ARs, VO which will contain the CustomerId and additional information you might need - name,address etc (something like ClientInfo or CustomerData).
This has several advantages:
Your ARs are decoupled - and now can be partitioned, stored as event streams etc.
In the Order ARs you usually need to keep the information you had about the customer at the time of the order creation and not reflect on it any future changes made to the customer.
In almost all the cases the information in the value object will be enough to perform the read operations ( display customer info with the order ).
To handle the Deletion/deactivation of a Customer you have the freedom to chose any behavior you like. You can use DomainEvents and publish a CustomerDeleted event for which you can have a handler that moves the Orders to an archive, or deletes them or whatever you need. You can also perform more than one operation on that event.
If for whatever reason DomainEvents are not your choice you can have the Delete operation implemented as a service operation and not as a repository operation and use a UOW to perform the operations on both ARs.
I have seen a lot of problems like this when trying to do DDD and i think that the source of the problems is that developers/modelers have a tendency to think in DB terms. You ( we :) ) have a natural tendency to remove redundancy and normalize the domain model. Once you get over it and allow your model to evolve and implicate the domain expert(s) in it's evolution you will see that it's not that complicated and it's quite natural.
UPDATE: and a similar VO - OrderInfo can be placed inside the Customer AR if needed, with only the needed information - order total, order items count etc.

Root Entity reference to another root

I'm facing a typical DDD problem. It must be very basic. I have an order and customer.
A customer can create multiple orders. Customer is the root of its own aggregate. Order is the root of its own aggregate. But when a customer creates an order, we display some portion of the customer information on the order. Should Order aggregate hold reference to customer?
When it holds it then when the Order Repository gets the order, we are able to retrieve some portion of customer information as well for display. But when we involve the order in a transaction, customer also gets into it which is creating problem if the customer is also getting updated at the same time. Please advise guys ! My gut feeling says I MUST not hold reference to customer from order.
Question 2: (NEW)
Can I get and hold a reference to the Customer (from Customer Repository) for a given Order while creating an Order (using Order Factory) and safely save the Order (without updating the Customer inside in anyway, Customer is there only for information/query?) without creating contention if the same Customer is getting modified else where? Lets assume NHibernate as ORM.
A simple answer will be that you hold the ID of the customer or, if needed for your domain some ValueObject with a minimal set of information about the customer ( ID, Name ).
A more complex answer is to think about Bounded Context. See Eric Evans's presentation where he wishes he had put the BC chapter as the first chapter in the book.
The idea is that in your Customer Management Bounded Context, your Customer entity can be the AR of the Customer Aggregate and the Orders can be entities in the Customer Aggregate. In the Billing Bounded Context you can have an Order AR with a Customer entity inside.

Resources