Can an aggregate have lite version of another aggregate just for read? - domain-driven-design

I have an order aggregate with Order as root having multiple OrderLine. OrderLine has "identity reference" to Product aggregate. But having only "identity reference" is not enough. I need value of "taxable" property, last "price" property for calculating price in OrderLine. In fact, in order to calculate price in OrderLine, some data from Product aggregate is needed.
How can this problem is resolved in DDD? Is it valid in DDD approach to have a lite version of Product (ProductLite) to use as read-only DTO?
-- UPDATE (thanks to #Francesc Castells)
// app service to add OrderLine
product = productRepo.Read(productId)
orderItemPrice = priceDomainService.CalculatePrice(product.price, product.tax)
order.AddOrderLine(product.ID, orderItemPrice)
orderRepo.Save(order)

Yes, this is perfectly valid. An aggregate should store all data that it needs to fulfill its purpose. This data doesn't have to always be user input, it can also come from other aggregates. There's abviously a difference between data produced by an aggregate and data consumed by it. For example, your Order consumes product prices, but it cannot change the product price and expect the rest of the system to respect that new price, as it doesn't own it.
In your scenario, I would say that once in the OrderLine, the Price is not part of the Product anymore, but part of the OrderLine itself, which could probably be defined as the price of the product the moment it was ordered or maybe the moment it was put in the shopping cart.

Related

How to express counter type entity with UML?

I would need some help with a problem we're facing in a company, trying to model every process and entity.
So far we have used an enhanced conceptual model with entities and attributes with relationships but there are some objects that don't exactly match a dimension or a fact table, and this is an entity that can be called "Shops with sales over X units". There is the entity "sales" and "shop" obviously, that would have it's representation in UML as independent entities and represent at the lower level, each sale and shop.
What we need to indicate in UML is an entity that stores the counter of shops with sales over X units, so this has some kind of behavior or conditions.
If we consider the entity, it would need date-from and date-to, and the value (counter), and creating a connection with the shop entity seems enough, but we miss the behavior that expresses "more than x sales". So the behavior could be for example: Go to the shop entity, take the 1st element and navigate to the sales entity, calculating the sales. If it's over X, then value+1, and so on.
I made a simple version of the problem. Blue boxes represent the entities already created, and the orange one is the counter that should count the shops with some constraints.
Is there any way of using some kind of UML diagram that can help us to solve this problem?
You could realize that with an association class:
ShopSales relates Shop and Sales so you can store the number of sales along with other things you might need in that conjunction. The ShopSalesStats could give you the shops by number of sales.
Another (of many) way(s) would be to just hold the count as public property of Shop and let ShopSalesStates handle the counts on all associated Shops.

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.

How to model sort order for many-to-one across two aggreagate roots

Take the domain proposed in Effective Aggregate Design of a Product which has multiple Releases. In this article, Vaughn arrives at the conclusion that both the Product and Release should each be their own aggregate roots.
Now suppose that we add a feature
As a release manager I would like to be able to sort releases so that I can create timelines for rolling out larger epics to our users
I'm not a PM with a specific need but it seems reasonable that they would want the ability to sort releases in the UI.
I'm not exactly sure how this should work. Its natural for each Release to have an order property but re-ordering would involve changing multiple aggregates on the same transaction. On the other hand, if that information is stored in the Product aggregate you have to have a method like product.setRelaseOrder(ReleaseId[]) which seems like a weird bit of data to store at a completely different place than Releases. Worse, adding a release would again involve modification on two different aggregates! What else can we do? ProductReleaseSortOrder can be its own aggregate, but that sounds downright absurd!
So what to do? At the moment I'm still leaning toward the let-product-manage-it option but what's correct here?
I have found that in fact it is best to create a new aggregate root (e.g., ProductReleaseSorting as suggested) for each individual sorting and/or ordering purposes.
This is because releaseOrder clearly is not actually a property of the Product, i.e., something that has a meaning on a product on its own. Rather, it is actually a property of a "view" on a collection of products, and this view should be modeled on its own.
The reason why I tend to introduce a new aggregate root for each individual view on a collection of items becomes clear if you think of what happens if you were to introduce additional orderings in the future, say a "marketing order", or multiple product managers want to keep their own ordering etc. Here, one easily sees that "marketing order" and "release order" are two different concepts that should be treated independently, and if multiple persons want to order the products with the same key, but using different orderings, you'll need individual "per person views". Furthermore, it could be that there are multiple order criteria that one would like to take into account when sorting (an example for the latter would be (in a different context) fastest route vs. shortest route), all of which depends on the view you have on the collection, and not on individual properties of its items.
If you now handle the Product Manager's sorting in a ProductReleaseSorting aggregate, you
have a single source of truth support for the ordering (the AR),
the ProductReleaseSorting AR can enforce constraints such as that no two products have the same order number, and you
don't face the issue of having to update multiple ARs in a single transaction when changing the order.
Note that your ProductReleaseSorting aggregate most probably has a unique identity ("Singleton") in your domain, i.e., all product managers share the same sorting. If however all team members would like to have their own ProductReleaseSorting, it's trivial to support this by giving the ProductReleaseSorting a corresponding ID. Similarly, a more generic ProductSorting can be fetched by a per-team ID (marketing vs. product management) from the repository. All of this is easy with a new, separate aggregate root for ordering purposes, but hard if you add properties to the underlying items/entities.
So, Product and Release are both ARs. Release has an association to Product via AggregateId. You want to get list of all releasesfor a given product ordered by something?
Since ordering is an attribute of aggregate, then it should be set on Product, but Releases are ARs too and you shouldn't access repository of Release in Product AR (every AR should have its own repository).
I would simply make a ReleaseQueryService that takes productId and order parameter and call ReleaseRepository.loadOrderedReleasesForProduct(productId, order).
I would also think about separating contexts, maybe model for release presentation should be in another context? In example additional AR ProductReleases that would be used only for querying.

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.

DDD How to fetch a list of value objects

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

Resources