4

For the purpose of separating different functionality into different classes, I have two following Aggregates:

  1. ActiveEmployee

    • AssignTask ()
    • ReassignManager ()
    • Deactivate (string reason)
  2. InactiveEmployee

    • GetReasonForDeactivation ()
    • Reinstate ()

Both aggregates share the same root, dbo.Employee.

EmployeeID servers as a primary key for both Aggregates.

The repository instantiates the first one, or the second one based on a boolean flag dbo.Employee.IsActive.

Since I follow the rule that only one aggregate can be modified in one transaction, I will never encounter a situation where I load both aggregates with same ID, ending up with InactiveEmployee with ID 3 and ActiveEmployee with ID 3 in same transaction.

Is this good DDD? Does DDD allow for having two aggregates with same root? Can we differentiate Aggregate types based on a flag?

UPDATE 1:

When I said that both aggregates share the same root, what I meant was that both Aggregates represent a row in dbo.Employee table.

In my understanding, a root of the Aggregate is the entity which is uniquely defined in our domain. It does not mean that that entity has to exist as a real class, it's identity is what matters. Every other Aggregate that wants to reference Inactive/ActiveEmployee will hold a reference to the EmployeeID, not the reference to object instance.

  • 1
    Citing DDD book An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. It is not clear for me what objects both aggregates comprise. – Dawid Pytel May 23 '15 at 20:52
  • What do you actually gain by using inheritance? Are you confusing aggregate root and object hierarchy root (parent)? From what you have shown I don't see you need inheritance – Esben Skov Pedersen May 23 '15 at 21:25
  • @EsbenSkovPedersen I'm not using inheritance, these classes do not share the same base class, nor do they inherit from one another. – omittones May 24 '15 at 11:19
  • I don't follow then. what do you mean "they share the same root"? – Esben Skov Pedersen May 24 '15 at 17:56
  • @Esben The root entity in both cases is Employee class. Both of them are persisted to the same database table. – omittones May 24 '15 at 17:59
10

You need to understand that DDD is not about primary keys, rows or tables - these are just means to implement it.

Aggregate root is usually implemented as a class, because you are expected to access all the functionality and data of the aggregate through the root. It therefore needs to have some behavior, something which primary key of the table can't have. Primary benefit of this is the encapsulation of aggregates - its logic is completely contained inside the aggregate and doesn't leak outside which greatly reduces the coupling (and as a consequence complexity) of the application.

It follows that each aggregate has its own aggregate root, so two aggregates can't have the same root (if they have, there is effectively just one aggregate).

In your case, you probably want to have two independent aggregates (ActiveEmployee, InactiveEmployee) which are backed by the same table (which is fine because it's totally out of DDD's scope). But then remember that there's actually no dbo.Employee entity in your domain model, it's just a table on a lower (persistence) layer.

  • Ok, so what is the difference between Aggregate and Aggregate Root? In my case, what is the aggregate and what is the root? – omittones May 24 '15 at 13:50
  • 1
    @omittones Aggregate root is one part (and the interface) of the aggregate. Aggregate usually contains multiple domain objects and behaviors which are "owned" by the aggregate (root). In you case, ActiveEmployee is both aggregate and the aggregate root - but the aggregate can further contain more domain objects - like EmployeePreferences, Address, TaskAssignment etc. - these are owned by the aggregate and accessed through the aggregate root. – qbd May 24 '15 at 14:07
  • 2
    That is a bit different interpretation than what Evans proposed in his book. Quote: "An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each AGGREGATE has a root and a boundary. The boundary defines what is inside the AGGREGATE. The root is a single, specific ENTITY contained in the AGGREGATE." – omittones May 24 '15 at 14:26
  • My interpretation was that Aggregate is the interface that you use to access and modify data, and that Aggregate operates on the Entity (and child Entities) contained within that Aggregate, and that Aggregate identity is tied to the root Entity identity, making that Entity a Aggregate's root. Does this make sense? I want to clarify the concepts as much as possible, in order to better communicate my questions. – omittones May 24 '15 at 14:26
  • Plus, any reference to the Aggregate in the outside of the Aggregate must be made using that Aggregates Root, and that reference must not be a reference to the object, but to the key that identifies that object. – omittones May 24 '15 at 14:29
3

If Employee is an aggregate root, it means that all the outside objects can reference only the Employee (and not the ActiveEmployee/InactiveEmployee).

Any references from outside the aggregate should only go to the aggregate root. DDD aggregate by Martin Fowler

I don't think that's your intent.
I think ActiveEmployee and InactiveEmployee are both independent aggregate roots in your example.
These two are completely different. They expose different APIs and require different handling. They do share some information (Employee table), but that aside they have no interaction with one another. They cannot substitute one another and their APIs can't be invoked without checking the Employee status first

This situation looks a lot like violation of the Liskov Substitution principle to me.

  • I don't think it's a violation because they don't inherit from the same class. There is no BaseEmployee class. You cannot pass InactiveEmployee to a method expecting ActiveEmployee. When I say Employee is Aggregate Root, in my understanding that means both Active and InactiveEmployee have EmployeeID as their primary key. Any object that wishes to hold a reference to Active/InactiveEmployee will hold only EmployeeID, not the reference to entire object. – omittones May 24 '15 at 11:17
  • That's good to know. But, aggregate root is an object, not a property. All internal objects (Active/Inactive employee in your case) should be accessible thorough the root. It looks like you're redefining the definition of the aggregate root, thus making the question invalid – DanielS May 24 '15 at 12:35
  • So you're saying that both InactiveEmployee and ActiveEmployee are roots, and that it's ok they modify the same table, because they are completely different implementation and can't exist at the same time in the same transaction. To what would outside objects hold a reference to? – omittones May 24 '15 at 12:55
  • Yes. I think it's ok. – DanielS May 24 '15 at 12:58
1

So, I think what the OP has done is create 2 Aggregate Roots called ActiveCustomer and InactiveCustomer, and in those has added a property of type Customer. This is an entity, which represents a Customer in his system.

This is where I think the confusion/issue has arisen. Effectively this has made the aggregate root a wrapper around the entity, but it should be much more.

You need to stop thinking about the database, tables, anything to do with persistence. That stuff doesn't exist in your domain. Instead, just see your ActiveCustomer and InactiveCustomer. They may have many of the same properties, but they have different behavior. So build that behavior.

When it comes to persistence, what I do is have an Infrastructure project which contains my DB access functionality, whether it be EF, NHIbernate etc. Within that you can map your objects to tables. What I have started to do is create an internal data state class within my Aggregates which is what EF maps to. So, you might have something like CustomerDataState which has all your public getters and setters and identity on it. You use your EF or NHibernate to populate that state object, which in turn sets up your aggregate. That state class isn't exposed through your aggregate, so as far as the users of the domain model are concerned they are just working with your ActiveCustomer or InactiveCustomer.

So your Active/InactiveCustomer aggregate is loaded up from or rehydrated from a CustomerDataState which can be loaded from some persistence medium.

I find the best way to work with DDD is to ignore the database, forget about it, pretend it doesn't exist. As soon as you start thinking about how your Aggregate will be persisted you have lost your way. So as soon as a thought about rows or tables pops into your head, give yourself a shake and step back.

  • The Q&A format isn't one for discussion. Posing additional questions or asking for opinions don't belong in the answer. – user40980 Feb 1 '16 at 14:09
  • Apologies. I simply wanted to add to the answer (but as I didn't have over 50 reputation) I had to add it as a new answer. My intro text was just there to explain why I am answering a post which is over 8 months old. – PendorPaul Feb 1 '16 at 15:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.