DDD Aggregates and value objects

You could have it using the same value object. But only do this if the aggregate roots exist in the same bounded context and hence has the same meaning for both aggregates. If the aggregates exist in different bounded contexts, then have 2 separate ones and duplicate. Leaking one bounded context's concerns into another is what Eric is trying to fight.

To most, the concerns of entity vs. value object boil down to people having issues with duplication of data. We have been so trained to think in 3rd normal form of a single canonical model. DDD fights the inevitable complexity that that brings by forcing duplication where it's needed and allowing concepts that were once thought to be one into many.

Hope this helps


A Value Object is an object that describes some characteristic or attribute but carries no concept of identity.

Since it does not have conceptual identity you can not 'reference' or 'have link' to it. You can only 'contain' it. Let's say you have a User and user has Age. Age is a value object. If John is 25 years old and Jane is also 25 they do not 'reference' the same Age. Jonh's Age is simply equal to Jane's Age. So if your Address is indeed a Value Object then you are not violating any Aggregate boundaries. Your aggregate roots simply have equal addresses. Even if you technically have java/c# reference to Address it does not matter because Value Object are immutable most of the time.

It is hard to answer your question though without knowing what domain you are working on. But generally Address does not necessarily have to be a Value Object. Eric Evans mentions in his book that Postal Service and Delivery Route domains will treat Address as an Entity. Electrical Company that sends out technicians need to realize that two service calls from '123 Elm St' are actually coming from the same address and it only needs to send one technician. Address or 'Dwelling' is an Entity in this case.


Aggregates are only concerned with DATA MODIFICATION. No two aggregate should be allowed to modify the same data. Since a Value Object is immutable, it prevents this scenario from ever happening. Therefore it is totally fine for two or more aggregates to share the same Value Object as it is a read only data structure and an Aggregate does not care about the read model.

Address a = new Address("1111 ABC Ave.");
person.setAddress(a);
letter.setAddress(a);

person.getAddress().change("2222 XYS Ave.") // THIS IS ILLEGAL SINCE Address is a VO (immutable)

The above will never happen for Address, and so it's not dangerous to share, because nothing you do to the Address of person will ever have an effect on letter, so letter is still protecting it's own invariants.

If Address is made into an entity, then you wouldn't be able to use the same Address in both Entities, since the above code would make letter vulnerable to changes performed on person, and that would break the boundary, and it would prevent letter from being in control of it's invariants.

This is the whole point of Aggregate Roots, it's too model things in a way that limit side effects. If you define very clear modification boundaries, the code will be easier to work with and you'll prevent potential harmful unexpected impact.


I'll add one more thing. As it was mentioned in another answer, you want different Bounded Context to have a different Address type. The reason for that is that the details you need of an Address in one context are not necessarily the same as what you need in another. So by having two Address type, one for each context, you isolate the needs of one from the needs of the other.

Say for shipping you need:

Address
{
    Number;
    Unit;
    Street;
    State;
    Country;
    PostalCode;
}

But for location you need:

Address
{
    Number;
    Unit;
    Latitude;
    Longitude;
}

DDD will say, call them both Address, but bound them to different context. So even though in the language they are all talked about as an Address, their specific data and behavior might be different based on the context you are talking about. What you must absolutely not do is create a kind of MonsterAddres that would contain all possible data and behavior of all contexts in your domain and have this be the Address type used in all contexts.

Note that, we are talking about the model in your application, it's ok to store all data of addresses in a Monster Address Table, but when modeling your App, you should separate that into logical bounded context that maps to your domain and the ubiquitous language it employs.