Beachwalker
Beachwalker

Reputation: 7915

How to reference AggregateRoot internal entity data in DDD

I'm interested in the Idea of DDD but I have some questions about the concept of encapsulating and protecting the AggregateRoot internal Entities and how to reference them. I created a simple example (don't hit me if the domain design is bad, this is just an example to clarify the question).

// can be referenced from outside, is aggregate root
public class Library : AggregateRoot
{
   IList<Shelf> shelfs { get; }
}

// can be referenced from outside, is aggregate root
public class Shelf : AggregateRoot
{
   Book GetBookById(Guid Id) {...}
}

// should be accessed through Shelf, not referenced outside the context
public class Book : Entity<Guid>
{
   Guid Id { get; } // or something else uniqe, e.g. ISBN
}

// how to reference a book here?
// I think, I should not use Id because this is internal and
//only valid for Shelf Aggregate (but I can't have a second one of this book)
public class Lending : AggregateRoot
{
   // feels wrong because of passing internals from Shelf
   Guid LendedBook { get; set; }

   // should I Clone() an object with unique identity, is this allowed in DDD?
   Book LendedBook { get; set;}

   // create separate type for lending (but what should this type cointain)
   LendedBookInfo LendedBook { get; set;}
}

Hope to get a clear answer, cause most samples are only about ValueObjects (that are easy, 'cause they are copied anyway and not really referenced). I used C# style of code for my sample, but any other programming language or pseudo code is also welcome as answer.

Upvotes: 1

Views: 948

Answers (2)

Adrian Thompson Phillips
Adrian Thompson Phillips

Reputation: 7141

In DDD it's never a bad thing to model the real world. If you spoke to a Domain Expert in this domain, a librarian, they probably have terminology and workflow that could help you model your domain.

For instance they might talk about "lending a book" using a "book ticket system" and when they want to find a book by title they might look in the "title catalogue".

This might lead to a design where you have a BookTicketService class with a LendBook(lender, book) method, which might cause an entry to be recorded in the BookTicketSystem. Or a TitleCatalogueService class that has a SearchByTitle(title) method. Or when the library accepts a new book into the library, a record of it probably goes in the AccessionRegister, etc.

If you model your library using this ubiquitous language it allows other people in the library domain to pick up your software easier and most importantly, it allows software developers to talk to librarians about their requirements without talking in software development terms.

I'd Google a few things like "how to start a library" or "library glossary of terms" and try bring some of the language and processes you find into your software. People already run fully functioning libraries with tens of thousands of books and lenders. In theory all you need to do is understand how they do this, the terms they use and it should be possible to model it in software.

Upvotes: 1

theDmi
theDmi

Reputation: 18024

Your example of an external ID usage

Guid LendedBook { get; set; }

is fine. What you could do to make the model more explicit, is to create a value object BookId and use that one to reference books. The value object BookId is then a context-wide concept, i.e. not one that is local to a specific aggregate.

Apart from that, you probably don't want public setters or IList as return type in your model. But I suppose that's just an example and not really the question here.

Upvotes: 1

Related Questions