Reference to another aggregate vs. sub-entity - domain-driven-design

Let's assume we have three aggregates:
Employee
Evaluation
Contract
Both Evaluation and Contract are referencing Employee (using an AggregateReference or the ID itself).
The problem is that both Evaluation and Contract very regularly need specific properties of the Employee for their business-concerns for example the name.
That would mean, that in most cases when loading Evaluations or Contracts i would also need to load the referenced Employee (at least parts of it).
This is very costly, especially when iterating over collections of Evaluations and Contracts.
Another possibility would be to design "EvaluationEmployee" and "ContractEmployee" as sub-entities under their respective aggregate-root.
This would solve the problem, because they are now part of the aggregate and spring-data-jdbc would load them together with the aggregate-root.
But now we have another problem: Employees don't have back references to Evaluation and Contract (actually it's the other way round).
And there are a few indicators for Employee rather being an aggregate than an Entity: for example Employees are never deleted, when i delete Evaluations or Contracts.
Is there better way to model this?

I solved my problem by creating two new Entities: "EvaluationEmployee" and "ContractEmployee". Because Spring Data Jdbc needs back-references to work properly, i created a View for each of those Entities with an added back-reference to Evaluation and Contract respectively. This works because i don't need to write the Employees (i only read them).

Related

Relationship between concepts in DDD

I'm developing a budgeting app using Domain Driven Design. I'm new to DDD and therefore need a validation of my design.
Here are the concepts I came up with:
Transaction - which is either income or expense, on annual or monthly or one-off etc. basis.
Budget - which is the calculated income, expenses and balance projection, divided into occurrences (say e.g. 12 months over the next year, based on the Transactions).
I made the Transaction the Entity and Aggregate Root. In my mind it has identity, it's a concrete planned expense or income that I know I'll receive, for a concrete thing, and I also need to persist it, so I can calculate the budget based on all my transactions.
Now, I have an issue with the Budget. It depends on my concrete list of Transactions. If one of the Transactions gets deleted, the budget will need to be re-calculated (seems like a good candidate for a domain event?). It's a function of my identifiable transactions at any given time.
Nothing outside the Aggregate boundary can hold a reference to anything inside, except to the root Entity. Which makes me think the budget is the Aggregate Root as it cannot be a ValueObject or Entity within the Transaction.
What's confusing is that I don't necessarily need to persist the budget (unless I want to cache it). I could calculate it from scratch on request, and send it over to the client app. 2 different budgets could have the same number of occurrences, incomes, expenses and balances (but not Transactions). Perhaps an argument for making it a ValueObject?
So, my questions is - what is the Budget?
Domain context vs Aggregate
First element you get wrong is a point of details about DDD semantics. If there is only one object in your "aggregate", then it is not an aggregate. An aggregate is a structure made of multiple (2+) objects, with at least one being an entity and called the aggregate root. If a TransactionRpository returns a Transaction object that has no value object or entity, then Transaction is an entity but not an aggregate nor an aggregate root. If a BudgetRepository returns a Budget entity that includes a Transaction object, then Budget and Transaction form an aggregate, Budget being the aggregate root. If Budget and Transaction are returned from different repositories, then they form different contexts.
Context being the generic concept that can either be an aggregate or an entity.
Contexts are linked to use cases
Second element you get wrong is that you are trying to design your domain model outside of your use cases context. Your application clearly manipulates both concepts of Budget and Transactions, but does your application handles uses cases for both (budget management and transaction management) ? If yes, are these uses case different in a way that implies different domain constraints ?
If your application only handles Budget management, or both but they share their business constraints, then you only need a single context, that manipulates both concepts in a single aggregate. In that situation, Budget is probably your root aggregate, and it's up to your mode and use cases to tell whether the Transaction is a value object or you need to access them by Id.
If your application handles uses cases for both, with different business constraints, then you should split your domain in two contexts, with two different models, one for the Budget management use cases, the other for the Transaction management use cases.
Polysemic domain model
The third element you get wrong, is that you are trying to build a single, unified, normalized domain model. This is wrong because it introduces very complex structures, and a lot of business rules that are irrelevant to your business cases. Why would you need to manipulate the Budget domain model when the use case does not need knowledge of the Budget concept or linked business rules ?
If your application has use cases for both concepts, you need two models. The Budget management model should not use the Transaction management model. However, that does not implies that the Budget model is not allowed to manipulate the Transaction concept and vice versa. It only means you must write another model for that. You could have a Budget context that manipulates Budget and BudgetTransaction models, and Transaction context that manipulates Transaction and TransactionBudget models. These models can map to the same RDBMS tables with different columns, relevant to their use cases, implementing relevant business rules.
This is called writing a polysemic domain model.
Conclusion
So, my questions is - what is the Budget?
It is not possible to answer definitely your last question, as the answer depends on the use cases your application handles. However, you mention the following constraint:
If one of the Transactions gets deleted, the budget will need to be re-calculated
This seems a very good argument in favor of making your application as a single context application, based on an aggregate with Budget being the aggregate root and Transaction being an entity in the aggregate.
If you don't need to, try to refrain from splitting these two concepts in different contexts, unless you have very good reasons to do so: they manipulate excluding columns, they manipulate excluding business rules, you are interested in deploying these two in different bounded contexts, different services, as they would scale differently, etc ...
Having business constraints that span accross multiple contexts implies a complex implementation based on domain events, 2-phase commits, saga pattern, etc ... It's a lot of work, you should balance that work with the benefits you expect in return.

DDD Aggregates vs Entities

What to do with an object that has two dependencies:
Let's say we have three objects: client, company and a contract.
Contract needs a client and a company to exist.
Naturally, business wise, the contract belongs more to the client than it does to the company, however the companies provides the contract to the client.
For now, I have all three as a separate aggregate root. Because you should be able to quickly query the existing contracts for a specific company as well. If contract would be an entity under the client aggregate root, I'd need to query all the clients which have a contract of X company and then return a flattened list of those contracts. Which seemed a bit odd?
Secondly, contract itself has a lot of entities, with more entities below them.
To explain the hierarchy in a simple way:
Contract aggregates contains a list of entity A, entity A has multiple items of entity B and entity B has multiple items of entity C. So it's a deep structure, which all have to be exposed through the aggregate above it.
If I'd put the contract aggregate root as an entity below client, my client aggregate needs to carry all those extra methods for what's below contract as well. And soon I'll end up with almost everything under the same aggregate.
So my question is: what questions can I ask myself to answer this kind of issue? There's probably no right or wrong, but there should be some guidelines on how to deal with an issue like this?
Thanks!
what questions can I ask myself to answer this kind of issue?
Here is how Eric Evans defined AGGREGATE
An aggregate is a cluster of associated objects that we treat as a unit for the purpose of data changes.
"Change" is the important idea here; in designing our aggregate boundaries, we don't particularly care about data that appears in the same report (read-only view), we care instead about what data needs be to considered when making changes.
See also Mauro Servienti: All our aggregates are wrong.

DDD: It's correct to use Domain Events to guarantee invariants consistency? Do I have alternatives?

In my domain model I have the project entity (which is also aggregate root) which has products entity as child. One of the invariants of my domain model is that I can't have two products with the same code children of the same project (but is ok if the project is different).
My products are composed by parts which also has a similar rule (every part must have unique code within the same product) so parts are child of products because I need to ensure that rule. Children of product are also the activities that I need to do to create it because I'm describing a production tracking system.
Now, activities can have subactivities which can be assigned to factory area and so on.
Substantially what I have is that all entities starts from project just because I need to ensure one invariant(=business rule) but is not the best solution because every time I need to retrieve an entity I need to fill all the project (which can have 2000+ products).
What can I do to split that preserving my invariant but also freeing me to load a specific activity (or product) without retrieving all products of my project every time I need a child entity?
Should I need to split the Entities in several AggregateRoots, maintaining in the project a list of ProjectProductValueObject(string code) and use Domain Events in Aggregate's constructor to fire something like ProductCreatedEvent which try to create and add a new ProjectProductValueObject in my project using the AddProduct(ProjectProductValueObject product) method which contain my business rule and throws an exception if that's not satisfied? Is that ok and compliant to DDD principles?
Do I have other alternatives?
I have the feeling that you're overcomplicating the model.
From your description I've understood that:
Projects are root entities that can contain a list of
AssignedProduct, that is another root entity that contains a binding between the project (its id, see as a value object) and the product (I see it also as a value object)
So on with object and assigned object
In this way you've several Products that could be assigned to several Projects, but only the ones stored in AssignedProduct are valid. To avoid multiple assignments is just a matter of checking if the same couple of objects are already bound together.
If this doesn't match your model, ignore it.

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.

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.

Resources