1

We have a aggregate root as follows.

@AggregateRoot
class Document {
    DocumentId id;
}

The problem statement given by the client is "A document can have multiple document as attachments"

So refactoring the model will lead to

//Design One
@AggregateRoot
class Document {
    DocumentId id;

    //Since Document is an aggregate root it is referenced by its id only
    Set<DocumentId> attachments;

    attach(Document doc);
    detach(Document doc);
}

But this model alone won't be sufficient as the client wants to store some meta information about the attachment, like who attached it and when it was attached. This will lead to creation of another class.

class Attachment {
   DocumentId mainDocument;
   DocumentId attachedDocument;
   Date attachedOn;
   UserId attachedBy;

   //no operation
} 

and we could again refactor the Document model as below

//Design Two
@AggregateRoot
class Document {
    DocumentId id;
    Set<Attachment> attachments;

    attach(Document doc);
    detach(Document doc);
}

The different possibilities of modeling that I could think of are given below.

  1. If I go with design one then I could model Attachment class as an aggregate root and use Events to create them whenever a Document is attached. But it doesn't look like an aggregate root.
  2. If I choose design two then Attachment class could be modeled as a value object or an entity.
  3. Or If I use CQRS, I could go with design one and model Attachment as a query model and populate it using Events.

So, which is the right way to model this scenario? Is there any other way to model other what I have mentioned?

msmani
  • 730
  • 1
  • 7
  • 24

1 Answers1

1

You might find in the long term that passing values, rather than entities, makes your code easier to manage. If attach/detach don't care about the entire document, then just pass in the bits they do care about (aka Interface Segregation Principle).

attach(DocumentId);
detach(DocumentId);

this model alone won't be sufficient as the client wants to store some meta information about the attachment, like who attached it and when it was attached.

Yes, that makes a lot of sense.

which is the right way to model this scenario?

Not enough information provided (the polite way of saying "it depends".)

Aggregate boundaries are usually discovered by looking at behaviors, rather than at structures or relationships. Is the attachment relationship just an immutable value that you can add/remove, or is it an entity with an internal state that changes over time? If you change an attachment, what other information do you need, and so on.

VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
  • I passed Document instead of DocumentId because the Document cannot be attached if it is already attached to another Document, for that validation only I am passing Document. The attachment class itself immutable, it can be added or removed but no behaviour. Can you suggest now? – msmani Nov 22 '17 at 14:29
  • 2
    If a document can only be attached to one other document, you may find success in invert your logic a bit and rather than a parent document containing a collection of its attached documents, have each document contain a reference to its 'parent' document. This will allow you to satisfy your business requirement of each doc can only have one parent. As for finding all the child documents of a given document, that is what views are for (Remember, You don't need to use your domain entity objects all the time, views are your friend) – Joe Nov 23 '17 at 05:14
  • @Joe Thanks, interesting suggestion – msmani Nov 23 '17 at 06:32