Ivan  avn
Ivan avn

Reputation: 77

A problem with understanding aggregates and aggregate roots in Domain Driven Design (DDD)

I've stumbled upon a problem: "I can't split my domain models into aggregate roots".

I'm a junior developer and novice at DDD. I really want to understand it, but sometimes it's really confusing.

From this point I want to describe my domain briefly.

My poject dedicates to provide users opportunity to create any kind of documents by themselve. Users can create a new type of document. Each new type consists of its attributes. Then a user of this application can create a concrete document based on its type. User can also send the document for approval. An approval flow is different for each types.

So, we have the following models:

  1. DocumentType/ DocumentTemplate - acts as a template based on which concrete documents are created. It has one to many relationship with Document.
  2. DocumentsAttribute - represents an attribute of document. It has many to many relationship with DocumentType.
  3. AttributeValue - when a concrete document is created, It looks at its type and creates values for attributes, which has its type. Many to many relationship with Document and Attribute.
  4. Document - represents a concrete document that is created by users.

There are others models but I don't think that they make sense.

As you understand, here I apply Entity Attribute Value (EAV) pattern of data model. You can see a diagram that shows relationships in the database.

And my problems are:

I have a lot of entities in my model besides I have described.

I think that Document is definitely an aggregate root in my Domain. Because such things as ApprovalProcess which is aggregate cannot live out of it.

Here is the first question:

ApprovalProcess consists of its steps. Each step is an entity since it is mutable. A step has its state that can be changed. ApprvalProcess's state depends on its steps. Here we have a business invariant: "ApprovalProcess can be approved only if all its steps is approved".

I think that it is an aggregate root because it has the business invariant and contains entities that cannot live out of it. And we don't want to allow to have direct access to its steps in order to keep ApprovalProcess consistent.

Am I mistaken that ApprovalProcess is an aggregate root? May it is just an aggregate? Can one aggregate root exist within another one as it's part? Does it mean that ApprovalProcess is just aggregate because Document is responsible for access to its parts? But when ApprovalProcess's step is approved, Document delegates an operation to ApprovalProcess.

For example:

Document doc = new Document(...);
doc.SendForAooroval(); //ApprovalProcess is created.

doc.ApproveStep(int stepId); // Inside the method Document delegates responsibility for approvement to ApprovalProcess.

Or I should leave Document and ApprovalProcess separately. Hence Document is going to refer to ApprovalProcess by Identity. And we have the following scenario:

Document doc = documentRepository.Get(docId);
doc.SendForAooroval();// A domain event "DocumentCreatedEvent" is raised.

DocumentCreatedEventHandler:

ApprovalProcess approvalProcess = new ApprovalProcess(event.DocId); // ApprovalProcessCreatedEvent is raised

approvalProcessRepository.Add(approvalProcess);
approvalProcessRepositroy.UnitOfWork.Save(); //commit 

But if ApprovalProcess's state changes, Document's state also changes. ApprovalProcess is approved then Document is also approved. Another word ApprovalProcess is kind of part of Document's state. Only thanks to it we can know that Document is approved.

And the biggest problem that I'm experiencing:

DocumentType is also an aggregate root. It consists of its attributes and ApprovalScheme. I haven't mentioned ApprovalScheme yet on purpose to keep my explanation as simple as possible. ApporvalScheme consists also from some entities. It's just an approval flow for DocumentType. ApprovalProcess is created according to ApprovalScheme of DocumentType which has Document. ApprovalScheme cannot exist without DocumentType. One to one relationship.

Document refers by identity to its DocumentType. Is it correctly?

At the begining of this task I thought that DocumentType should be a part of Document.

DocumentType has many Documents but in my domain It doesn't make sense. It doesn't represent the state of DocumentType. DocumentType can be marked as deleted but can't be deleted.

Document and DocumentType are two different aggregate roots. Am I right?

Thank you so much If you read it. Thank you a lot for you attention and help! Sorry for my terrible English.

Upvotes: 2

Views: 733

Answers (1)

choquero70
choquero70

Reputation: 4754

Am I mistaken that ApprovalProcess is an aggregate root? May it is just an aggregate? Can one aggregate root exist within another one as it's part?

These questions doesnt make any sense to me. An aggregate is a group of entities and value objects, where one of the entities is the parent of the group. The aggregate root is the parent entity of an aggregate. A particular case is when the aggregate is just an entity. The entity alone is an aggregate and the entity is the aggregate root of course.

I think that I would try to model your problem from another point of view: as a state machine.

I see ApprovalProcess as a flow a document follows, not as an entity. I don't know the flow diagram of the process, but I guess that what you call "steps" would be the "states" a document can have during the process, and you have transitions between steps, so that first when you create a new document, it is at a starting step, and through the lifetime of the document, it pass from a step to another, till it reaches a final step (e.g. document approved).

So the document entity would have behaviour that changes its a state.

For example, in Java you can implement the state pattern (a state machine) with enums.

Upvotes: 3

Related Questions