Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What Belongs to the Aggregate Root

This is a practical Domain Driven Design question:

Conceptually, I think I get Aggregate roots until I go to define one.

I have an Employee entity, which has surfaced as an Aggregate root. In the Business, some employees can have work-related Violations logged against them:

Employee-----*Violations

Since not all Employees are subject to this, I would think that Violations would not be a part of the Employee Aggregate, correct?

So when I want to work with Employees and their related violations, is this two separate Repository interactions by some Service?

Lastly, when I add a Violation, is that method on the Employee Entity? Thanks for the help!

like image 493
jlembke Avatar asked May 07 '09 18:05

jlembke


People also ask

What is the aggregate root?

Aggregate Root is the mothership entity inside the aggregate (in our case Computer ), it is a common practice to have your repository only work with the entities that are Aggregate Roots, and this entity is responsible for initializing the other entities. Consider Aggregate Root as an Entry-Point to an Aggregate.

How do you find the aggregate root?

One good way of identifying the aggregate root is to use the "delete" test. In your domain if you delete the root, what is deleted with it? This way you can identify domain object ownership, which is a trait of Aggregates.

What is an aggregate DDD example?

Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate.

How do you identify aggregates?

Write out the numbers in the group. In the example, assume the student's respective scores were 45, 30 and 10. Add together all the numbers in the group. In the example, 45 plus 30 plus 10 equals an aggregate score of 95.


3 Answers

After doing even MORE research, I think I have the answer to my question.

Paul Stovell had this slightly edited response to a similar question on the DDD messageboard. Substitute "Customer" for "Employee", and "Order" for "Violation" and you get the idea.

Just because Customer references Order doesn't necessarily mean Order falls within the Customer aggregate root. The customer's addresses might, but the orders can be independent (for example, you might have a service that processes all new orders no matter who the customer is. Having to go Customer->Orders makes no sense in this scenario).

From a domain point of view, you can even question the validity of those references (Customer has reference to a list of Orders). How often will you actually need all orders for a customer? In some systems it makes sense, but in others, one customer might make many orders. Chances are you want orders for a customer between a date range, or orders for a customer that aren't processed yet, or orders which have not been paid, and so on. The scenario in which you'll need all of them might be relatively uncommon. However, it's much more likely that when dealing with an Order, you will want the customer information. So in code, Order.Customer.Name is useful, but Customer.Orders[0].LineItem.SKU - probably not so useful. Of course, that totally depends on your business domain.

In other words, Updating Customer has nothing to do with updating Orders. And orders, or violations in my case, could conceivable be dealt with independently of Customers/Employees.

If Violations had detail lines, then Violation and Violation line would then be a part of the same aggregate because changing a violation line would likely affect a Violation.

EDIT** The wrinkle here in my Domain is that Violations have no behavior. They are basically records of an event that happened. Not sure yet about the implications that has.

like image 135
jlembke Avatar answered Sep 29 '22 11:09

jlembke


Eric Evan states in his book, Domain-Driven Design: Tackling the Complexity in the Heart of Software,

An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes.

There are 2 important points here:

  1. These objects should be treated as a "unit".
  2. For the purpose of "data change".

I believe in your scenario, Employee and Violation are not necessarily a unit together, whereas in the example of Order and OrderItem, they are part of a single unit.

Another thing that is important when modeling the agggregate boundaries is whether you have any invariants in your aggregate. Invariants are business rules that should be valid within the "whole" aggregate. For example, as for the Order and OrderItem example, you might have an invariant that states the total cost of the order should be less than a predefined amount. In this case, anytime you want to add an OrderItem to the Order, this invariant should be enforced to make sure that your Order is valid. However, in your problem, I don't see any invariants between your entities: Employee and Violation.

So short answer:

I believe Employee and Violation each belong to 2 separate aggregates. Each of these entities are also their own aggregate roots. So you need 2 repositories: EmployeeRepository and ViolationRepository.

I also believe you should have an unidirectional association from Violation to Employee. This way, each Violation object knows who it belongs to. But if you want to get the list of all Violations for a particular Employee, then you can ask the ViolationRepository:

var list = repository.FindAllViolationsByEmployee(someEmployee); 
like image 27
Mosh Avatar answered Sep 29 '22 10:09

Mosh


You say that you have employee entity and violations and each violation does not have any behavior itself. From what I can read above, it seems to me that you may have two aggregate roots:

  • Employee
  • EmployeeViolations (call it EmployeeViolationCard or EmployeeViolationRecords)

EmployeeViolations is identified by the same employee ID and it holds a collection of violation objects. You get behavior for employee and violations separated this way and you don't get Violation entity without behavior.

Whether violation is entity or value object you should decide based on its properties.

like image 41
Yuriy Avatar answered Sep 29 '22 11:09

Yuriy