domain-driven-designaggregateaggregateroot

What is an Aggregate Root?


No, it is not a duplication question. I have red many sources on the subject, but still I feel like I don't fully understand it.

This is the information I have so far (from multiple sources, be it articles, videos, etc...) about what is an Aggregate and Aggregate Root:

So with all that in mind, lets get to the part where I get confused:

in this site it says

The Aggregate Root is the interface to the external world. All interaction with an Aggregate is via the Aggregate Root. As such, an Aggregate Root MUST have a globally unique identifier within the system. Other Entites that are present in the Aggregate but are not Aggregate Roots require only a locally unique identifier, that is, an Id that is unique within the Aggregate.

But then, in this example I can see that an Aggregate Root is implemented by a static class called Transfer that acts as an Aggregate and a static function inside called TransferedRegistered that acts as an AR.

So the questions are:

  1. How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that its a function. what does have a globaly unique identifier is the Domain Event that this function produces.
  2. Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function of the Aggregate class itself?
  3. In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier), then how can we interact with this Aggregate? the first article clearly stated that all interaction with an Aggregate is by the AR, if the AR is an event, then we can do nothing but react on it.
  4. Is it right to say that the aggregate has two main jobs:
    • Apply the needed changes based on the input it received and rules it knows
    • Return the needed data to be persisted from AR and/or need to be raised in a Domain Event from the AR

Please correct me on any of the bullet points in the beginning if some/all of them are wrong is some way or another and feel free to add more of them if I have missed any!

Thanks for clarifying things out!


Solution

  • Keep in mind that Mike Mogosanu is using a event sourcing approach but in any case (without ES) his approach is very good to avoid unwanted artifacts in mainstream OOP languages.

    1. How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that its a function. what does have a globaly unique identifier is the Domain Event that this function produces.

    TransferNumber acts as natural unique ID; there is also a GUID to avoid the need a full Value Object in some cases.

    There is no unique ID state in the computer memory because it is an argument but think about it; why you want a globaly unique ID? It is just to locate the root element and its (non unique ID) childrens for persistence purposes (find, modify or delete it).

    Order A has 2 order lines (1 and 2) while Order B has 4 order lines (1,2,3,4); the unique identifier of order lines is a composition of its ID and the Order ID: A1, B3, etc. It is just like relational schemas in relational databases.

    So you need that ID just for persistence and the element that goes to persistence is a domain event expressing the changes; all the changes needed to keep consistency, so if you persist the domain event using the global unique ID to find in persistence what you have to modify the system will be in a consistent state.

    You could do

    var newTransfer = New Transfer(TransferNumber); //newTransfer is now an AG with a global unique ID
    var changes = t.RegisterTransfer(Debit debit, Credit credit)
    persistence.applyChanges(changes);
    

    but what is the point of instantiate a object to create state in the computer memory if you are not going to do more than one thing with this object? It is pointless and most of OOP detractors use this kind of bad OOP design to criticize OOP and lean to functional programming.

    1. Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function of the Aggregate class itself?

    It is the function itself. You can read in the post:

    AR is a role , and the function is the implementation.

    An Aggregate represents a single unit of work, meaning it has to be consistent. You can see how the function honors this. It is a single unit of work that keeps the system in a consistent state.

    1. In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier), then how can we interact with this Aggregate? the first article clearly stated that all interaction with an Aggregate is by the AR, if the AR is an event, then we can do nothing but react on it.

    Answered above because the domain event is not the AR.

    4 Is it right to say that the aggregate has two main jobs: Apply the needed changes based on the input it received and rules it knows Return the needed data to be persisted from AR and/or need to be raised in a Domain Event from the AR

    Yes; again, you can see how the static function honors this.

    You could try to contat Mike Mogosanu. I am sure he could explain his approach better than me.