1

I am trying to learn DDD. I am modeling a property management domain and I think I have two contexts (subdomains?): a property management context and a resident context.

Let's say I have an aggregate root Apartment, that holds Floorplans and Units. Each Apartment can have many Floorplans, and each Floorplan can have many Units.

public class Apartment : IAggregateRoot // for clarity
{
    public int Id { get; }
    public Address Address { get; set; }
    public ICollection<Floorplan> Floorplans { get; set; }
}

public class Floorplan
{
    public int Id { get; }
    public int ApartmentId { get; set; }
    public string Name { get; set; }
    public int Bedrooms { get; set; }
    public int Bathrooms { get; set; }
    public ICollection<Unit> Units { get; set; }
}

public class Unit
{
    public int Id { get; }
    public int FloorplanId { get; set; }
    public string Number { get; set; }
}

Let's say in the property management context I now introduce a Resident who gets assigned to a Unit. My Unit and Resident class now looks like this:

public class Unit
{
    public int Id { get; }
    public int FloorplanId { get; set; }
    public string Number { get; set; }
    public ICollection<Resident> Residents { get; set; }
}

public class Resident // in the property management context
{
    public int Id { get; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public void UpdateBalance(...);
}

My question is now if I introduce a Resident in the resident context (that can PayRent() or UpdateProfile(), etc) they must be have a 1:1 relationship with Resident in the property management context, but I thought I cannot reference a non-aggregate root entity without going all the way through Apartment because a Resident cannot exist without an Apartment.

Is my understanding of aggregate roots incorrect? Is Resident an aggregate root in both contexts? I'm not sure how that would be modeled.

8
  • 1
    Well, what does "1:1" mean, in practice? What's the usage pattern? Is this the same user editing something about the Resident in one screen, that later on goes to a different view, and this view needs to reflect the change? Is it two remote users accessing different parts of the application at the same time, each with its own representation of the Resident, but the two affect each other? Must they be synchronized ASAP, or not? Are these (really or effectively) two different applications? Is there a central data store, or more then one? Model your aggregates to support the usage patterns. May 5, 2020 at 2:12
  • @FilipMilovanović I understand where you are coming from. I really do. But I suspect you are capable of filing in the blanks here. Many of the questions you are asking are not strictly relevant to provide guidance to a general modeling question like the one above. It is not and should not be a requirement that every poster outline their entire architecture in order to receive answers about domain modeling. Please apply the principal of charity as generously as possible when attempting to understand questions. The first 6 words of this post are "I am trying to learn DDD". May 5, 2020 at 15:57
  • "Many of the questions you are asking are not strictly relevant to provide guidance to a general modeling question like the one above" - actually, they are. (Also, I didn't expect for you to explain the entire system - they are meant to be questions that you should ask yourself when designing. Explore those topics in your domain and let what you learn guide you.) How you design your aggregates and whether or not to pursue the ideas you're currently considering depends entirely on these considerations. May 5, 2020 at 17:43
  • You don't create good aggregates by mechanistically following a set of rules - you put them into your design so that they can solve a problem for you (limit dependencies, make a group of collaborating objects cohesive, enforce invariants, enable specific usage patterns, control the complexity of storing and reconstituting objects, etc.). May 5, 2020 at 17:44
  • E.g., your Apartment class (as presented in your question) is not acting like an aggregate root - in that it's just a tree of objects, and that's not the same thing; it doesn't encapsulate what's within the aggregate, and it doesn't provide an interface to support operations on the aggregate. So it's not a DDD aggregate, even though it's designated as one, which makes other considerations superfluous, because they don't really give you any benefits if you don't have a proper aggregate root. May 5, 2020 at 17:51

1 Answer 1

3

The most critical piece of information a practitioner of DDD needs to understand and, frankly, the biggest stumbling block I see here in this tag, is that DDD is about modeling the functional requirements of a system. That is, DDD asks us to take a perspective that focuses on the behaviors of our system and let the data that supports these behaviors become an implementation detail.

In your question above I see lots of "this has that", and not a lot of "this does that". I don't mean to say that your model is necessarily incorrect, rather, that you are approaching your system in a way that leads to exactly the problem you have outlined above. When you only focus on the data within a system (I'm guessing your domain model closely resembles your physical model) it almost always leads to "overlapping" concerns.

In this case we should partition our Resident vertically according to behavior (though sharing an ID). Ask yourself, Why does Resident in the Property Management Context need to have FirstName and LastName fields? Are these pieces of data consequential in terms of the use cases present within the context? Does UpdateBalance or RentUnit require a name? Probably not. On the other hand, the Resident in your Resident Context does need these fields if it is to be made responsible for updating this information.

And to be clear, a Resident (that is an entity with FirstName and LastName fields) can absolutely exist without an apartment. I'm sitting right here. Always be on the lookout for artificial constraints. I may not be renting from you (yet!), but that shouldn't prevent your system from knowing of my existence. Maybe Person or Customer is a better name than Resident in this case (as the latter carries an implication with it).

To summarize, your model requires two entities (Person and Resident) in two contexts (Resident and Property Management) that share an identifier from your persistent data store - each responsible for carrying-out and enforcing the particular behaviors relevant to their existence (updating different fields). Whether these map to the same physical database table is an implementation detail.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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