Actual difference between Value Objects and Entities. DDD - domain-driven-design

Domain-Driven Design, I'm trying to figure out what the difference some kind of mathematically and not intuitively. In my current project, we have some kind of payment transfers between banks.
In this system, the bank is carried not like a physical building but an abstract bank. It has BankCode for sure, country and Bank Name. And the question is: Is the bank should be an entity or value object. I intuitively feel that it should be entity, but some people say that it could be like a value object.
As I know, entities MIGHT have the same attributes but still be different. On the other hand, value objects must not have an identity, they should be the same in case all attributes are the same, they should answer what they are, not who or which they are. Please If I'm wrong - correct me.
In the system, banks are not changing during any flow, like another Value object Country or Currency, probably we could say, that banks with the same bank code, name, and country are the same banks. As well as we can say that Country with the same country code (ISO format) is the same. But still, for me, I feel like they are entities. Could someone prove where I'm wrong, and give mathematic proofs that they should be either Value object or Entities.
Currently, I end up with that: "The one difference between Entity and Value Object is the entity can contain the all same attributes and still be different, the Value Object can't", like transaction and people can have same amounts and goods, same names, but still be different, and like address should be the same if the country, city, and house number are the same. Please correct me, and maybe there are more differences

The classic example difference between the two, is based on the context (as DDD always is), so lets go for it...
Classic Example: An airplane flight (allocated seat or any seat)...
Entity
Each seat has a number, and you allocate a passenger a specific seat (Seat: 10 E)
Value Object
The plane has a number of seats, and you give a passenger 1 (or more) seat(s), on the plane (non specific, sit anywhere).
The key question is, do you care about the individual entity (a seat) or just the total number of available seats?
You can see the DDD - context separation here, even if you allocate seats, not every context is going to care. If I'm doing a capacity piece, I don't care about the entities, I just want to know
var unused = available - used.
Your initial Question
Simple Answer
It's an entity
Deeper Answer
It depends on the context.
And then...
In some contexts it may be a Domain Model in itself, like your context.
If I want to move money from Bank1 and Bank2 then, I'm going to do...
// Both domain models
Bank sendingBank = _bankStore.Get(fromBank.Id);
Bank receivingBank = _bankStore.Get(toBank.Id);
_moneyTransfer(sendingBank, receivingBank, amount);
Or alternatively
Calling code
Customer customer = _customerStore.Get(customerId);
var balanace = customer.GetBalance();
Entity Version: Customer
public class Customer {
public Bank {get; private set;}
public Decimal GetBalance () {
return this.Bank.GetBalance();
}
}
Value Object Version: Customer
public class Customer {
public Balance {get; private set;}
public Customer (..., decimal bankBalance) {
this.Balance = bankBalance;
}
}

Is the bank should be an entity or value object
A prior question to ask is: do you need to model the bank?
In particular, do you control the rules by a which a bank changes? Or are you just managing a local cache/repository of information that is provided to you by some other authority (in the same way that country code information is provided to us by the ISO 3166 Maintenance Agency).
An important principle in domain driven design is to take the care to ensure that you are modeling the thing that you are supposed to be modeling.
we could say, that banks with the same bank code, name, and country are the same banks. As well as we can say that Country with the same country code (ISO format) is the same. But still, for me, I feel like they are entities.
Yes. Banks are certainly entities. So are countries.
But they are real world entities. Your domain model doesn't own them. What you have in your data store is locally cached information about those entities.
For example, the ISO-3166-1 standard is a living document; it was changed as recently as 2020-03-02 (a correction to the full names for MK). A given country code and date gives you a fixed identifier. Because country codes are reserved for 50 years, the country code alone is unambiguous for non trivial time periods.
The token MK is certainly a value object. The lookup table that says token MK means North Macedonia is an entity. But... it is a stable entity, so in some contexts we might be able to treat it as fixed.
(That's a general property of standardized identifiers - standards are worthless if they aren't adopted, so the change management policies are designed to make things easy for adopters).
Unless you are yourself doing work for ISO 3166/MA, though, it isn't your entity. The information you have is just a copy.
My guess is that's true of your bank codes as well.
Part of the point of domain driven design: that if we do the work to make sure that we really understand the actual business problem that we are trying to model, then our subsequent implementation will be well aligned with what we want, and easy to change in the face of new requirements.
Which is to say, you really need to make sure you understand "bank" in the context of your domain to determine if it is an entity or a value object.

In your case, bank should be an Entity as each bank has a unique BankCode to identify it. Even if at this point your system doesn't update banks, it doesn't mean that it won't be possible in the future.
If some attribute of the bank changes, for example, it's main office address (just made it up...) of whatever else you got changes, the code that uniquely identifies it will remain the same, hence the same bank, but with a different main office address.
This bank BankCode: 1234, Location: US Texas and this bank after a change in the Location attribute BankCode: 1234, Location: US Colorado is still the same thing.
Giving a mathematical definition is difficult because mathematics is about values.
This kind of uniqueness based not on attributes but on some kind of Identity that remains the same as it changes is closer to how the real world works, so it's difficult to give non-intuitive definitions of it.
Here's a good example of a ValueObject from math. Let's say you model a 3D math library with vectors and matrices. Vector and Matrix are ValueObjects.
Let's say that we have two vectors:
v1 -> x = 1, y = 2, z = 3
v2 -> x = 1, y = 2, z = 3
You do have two vectors, but from a math point of view, they are identical i.e. represent the same thing and are equal. The same applies to matrices.
Let's have a transformation T (translation for example). In math what you have is:
v3 = T (v1, v2)
You get a brand new vector when you apply this transformation. This brand we vector may have the same coordinates as v1 and v2 as a result so they will be equal, but you do not change v1 or v2.
Let's say you get a hair cut and let's say that this is a transformation too. If this true in the real world?
You2 = T(Hairdresser, You1)
No, it's not. It' still you with a different hair cut, you do not create a different you when you apply the transformation.
A good example of when a concept can be both a value and an entity depending on the system is when modeling Money. In your case when you make bank transfers, you transfer money between accounts. In this case, Money is a ValueObject because you do not case to differentiate between 5$ and 5$, it's still the same amount.
Let's say you go to a store to buy a drink, This drink is 5$. If you have two Banknotes of 5$, it doesn't matter which one you use to pay because they represent the same amount.
On the other hand, each Banknote has a serial number. The two 5$ Banknotes will have different serial numbers making them unique and different, so they are Entities.
If your system tracks Banknotes then you model it as an Entity. If not, you model it as a ValueObject.
Do vectors and matrices have serial numbers on them or any kind of Identity? Your car (if you have one) does. If you go to a parking lot with lots of cars and you have two cars yours and some else's car, that are exactly the same, do you care which one you take? Well, it's better to take yours, otherwise, it stealing and it's against the law and someone won't be happy about it.
Let's take our vectors again and the transformation T.
T(v1, v2), T(v2, v2), and T(v1, v1) all give the same result because these two vectors are equal and we do not care which one we use.

Maybe, i could explain the question at another aspect. Entity usually has a identify, but what does the identity used to do? I think it used to trace the entity state changing. Why we should trace the state changing? Because the entity is referenced by other context/object according identify.
That's why we said that it depends on the specific context/case. For some context, we don't care the state changing, it will be Value Object, otherwise it will be Entity.
The Address often regarded as Value Object. You entered your address on a shopping website, the address will not be refered by your family members when they logging in the same the system, even if all of you have the same address.
But when you browsing, modifing or deleting the address entered before, it must be a Entity, becuase it is referred by Address Editor and Address Book with identify.
When an Adress used by an order, it will be an Object Value or Entity depends on the Address should be changed when Address Book changed.

Related

ddd - How to properly identify Value Objects?

I am modeling my entities, and have been struggling with this for a long time. Here is my Person Entity:
Person
ID
Name
Email
Password
City
Phone
Biography
Rating
Description
I have tried to divide these properties into Value Objects, but so far I only have been able to convert them to VOs (for example, City is a VO made with a city name, and country name).
Should I try to create larger VOs, by putting together, for example, Email and Password into a Credentials VO ? Am I going too deep in the separation into VOs ?
Any help is greatly appreciated
[EDIT]
After some discussion, it appears that the best solution is to keep every property in it's own VO, except for Email and Password that should be grouped in a "Credentials" VO.
Value objects are things who's values uniquely identify them I.e. equality is done by the values, rather than an explicit property (like ID) to provide uniqueness. Two value objects are equal if all their fields are equal
When trying to identify them, follow the language the domain experts use. What words do they use when discussing People? Do they refer to credentials, or email and password?
Also look to identify groups of properties that are always used together. For example, if Password is always used alongside Email it makes sense to group them in a Credentials object, as you can then push behaviour there (i.e. Credentials.Validate())
[UPDATE]
All of the following properties are candidates for value objects depending on the invariants you need to enforce
Name
are there min / max values for names?
are there any characters not allowed?
Email
is it a valid email address
can two people have the same email address?
Password
min / max length?
required characters?
invalid characters?
Phone
is it a valid phone number?
how do you deal with international dialing codes?
Rating
is there a min and max value allowed for a rating?
how is it calculated? (is it calculated?)
Description
Biography
City
etc....
If you create Value Objects for the above concepts instead of using primitive values such as int or string, you can encapsulate your business rules inside the value objects.
You might want to combine Email and Password into a Credentials Value Object if you use the two things cohesively. i.e. login with credentials etc... You can still access Credentials.Email if you need to use the Email outside of the Credentials object.
What you have there looks suspiciously as a data structure (CRUD). In proper DDD you start with the business case like "Create Person" and then you find out the model representing the Person concept.
The model is defined by a group of components and business rules. Your components are usually VOs , because they are models representing minor concepts that can be expressed as a simple or composite value with no explicit identity and they encapsulate specific business constraints. For example, the Email VO makes sure you have a valid email value.
You should let the domain tells you if it makes sense to create bigger VO; usually you start with a VO and you discover it's made up from other VOs. Generally, we go top to down. You can see here a modelling example.
It's hard when you don't have a domain expert but you can still try to think in business cases and identify whatever specific model for each case. If you end up with mainly simple structures and some data validation rules, perhaps you have a simple enough domain to just use a CRUD approach.
Don't try to impose a particular domain model structure, you need to approach domain modeling from the use cases perspective.
Should I try to create larger VOs, by putting together, for example, Email and Password into a Credentials VO ?
You should do that only if the two tend to be used together. If they don't, leaving them along is just fine.
Note that sometimes it makes sense to extract a single property into its own value object if the number of invariants it needs to support is high enough to justify introducing a new concept. Take a look at this article for more details.
it is not always clear a concept in your domain is a value object or entity and unfortunately there are no objective attributes you could use to get to know it whether or not a notion is a value object fully it depends on the problem domain, a concept can be an entity in one domain model or a value object in another. most of times a money class is a value object but not all money objects are value object. how you can find out a value object? first of all you should check the notion of identity if it is structurally equal (it means two objects are same if objects values are same, not ids of objects), you can safety replace an instance of class which has same set of attributes. that is good sign this concept is a value object.
a good way of thinking value object is thinking if it is an integer, do you really care if integer 5 is same as 5 you used in other function? definitely not all 5 in your application are same, regardless how they were instantiated. that's make integer essentially a value object, now ask your self the object in your domain is like an integer? if answer is yes then it is a value object. also, value objects are immutable and more light weight as entities.

why we need to identify the entity and value object?

In Domain Driven Design,domain objects are fall into two categories,entity and value object.It is very easy to make out which is entity,which is value object,but i don't know why we have to do that?Before the advent of DDD, we model the domain without entity and value object.After the DDD was put forwar,we use entity and value object to classify domain object, so what is the advantage of such classification?
domain objects are fall into two categories,
Actually, no, objects are a possible implementation of a domain Concept , which is basically just information, not code. A concept can be an Entity because it makes sense to identify it in a uniquely and consistent manner, regardless how it changes over time (e.g: a Customer can change their name but it's the same customer. 2 customers with the same name are not necessarily the same person).
A Value Object (a name that still reminds us that DDD started a bit too coupled to OOP) represent a Domain concept that it's just a value. Or more precisely, the business only cares about its value. If you change it, it's another value all together. Basically, 5 dollars is 5 dollars, you don't really care which is which, any of them is good enough, because only the value is important.
Another thing is, as a domain modeler you identify the nature of a concept based on how the business looks at a concept. The business tells you what they care about.
Now, that we know that a concept can be a Entity, we can select a certain instance of it (User with Id 3). You can't do that with VO, because a VO doesn't have an identity.
Even more, when we identify aggregates, most of the time, the aggregate components (other concepts) are mostly VOs, because they usually are just values (but they do respect business constraints).
So, in conclusion, we classify concepts into Entity and VO, because
The business sees them in this manner: uniquely identifiable or just value
Entities keep their identity regardless how they change (obviously the identity itself is read-only), we treat each one as unique
VO are values that can be used interchangeably, we don't care which is which as long as they represent the same value (which itself, as an implementation detail can be a complex - composite - value). Also, a VO by its nature is immutable, so we know that we can't change it without becoming another value.
Before the advent of DDD, we model the domain without entity and value object.After the DDD was put forwar,we use entity and value object to classify domain object, so what is the advantage of such classification?
You should review Chapter 5 ("A Model Expressed in Software") of the Blue Book.
Evans writes:
Defining objects that clearly follow one pattern or the other makes the objects less ambiguous and lays out the path toward specific choices for robust design.
Tracking the identity of ENTITIES is essential, but attaching identity to other objects can hurt system performance, add analytical work, and muddle the model by making all objects look the same.
... bidirectional associations between two VALUE OBJECTS just make no sense. Without identity, it is meaningless to say that an object points back to the same VALUE OBJECT that points to it. The most you could say is that it points to an object that is equal to the one pointing to it, but you would have to enforce that invariant somewhere.
My own summary would be this: recognizing that some domain concepts are entities is useful, because it encourages the designer to acknowledge that identity, continuity, and life cycle are important concerns for the entity in this domain. Similarly, recognizing that a concept is a value immediately frees you from those concerns, bringing your attention to their immutable nature and equivalence.

DDD: Classify entity/value object

I just started learning about domain driven design, and one of the few things that confuse me the most is how to determine which one should be entity, which one should be value object
I know to determine entity/value object, we need to base on the domain context, in one context, one domain object can be entity, in another, it can be value object, but still there are some situations I can't decide
.e.g. address
- In the context of a customer management application (let's just say an application to manage customers, add/delete/change status,etc of customers), address is clearly value object because here we don't need to differentiate between one address from another, 2 customers can have same address
- On the other hand, in the context of a online booking application, can I say address is an entity? because now we need to differentiate customers by their billing address (just ignore the case 2 customers having same address for the moment)
To me, address is unique itself, so it definitely already has identity. So identity of a domain object will not decide whether it's an entity or value object, if so then what will be the key factors to choose?
Another example, I have one application that list a number of areas in one country, user can choose one area, and find all the restaurants that fit their searching criteria in that area. In this case, is area a value object or entity? Currently I think it's more on an entity but still not very sure. Each area is unique also
I'm not sure whether my question is clear or not, I try my best to explain my thinking currently
I think some of your difficulties may be in the subtle meanings of some of these terms. For example, you mention "To me, address is unique itself, so it definitely has identity". In terms of how most people use "identity" in domain-driven design, your statement would probably be incorrect.
A value object's set of attributes is its definition. If you change any aspect of it, you have a completely different object. Using your address example, if you change any part of it, you get a entirely different address. It is not the same address with aspects of it changed. Your customer moved to a new address; they did not change aspects of the same address.
However, if you were a mapping application and the address itself changed, then here, the address would be a entity. In such a scenario, the city planners may want to re-number houses on the street. In that case, the SAME address is being modified. In that case, we would need to update the entity, not a value object.
Regarding your billing address example, the billing address is probably still a value entity (at least the physical address portion of it). A payment method (e.g. credit card) may be the entity in that example, and it may include other value objects (such as billing address, credit card number, etc).
You may find it helpful to see review this question and its answers as well: Value vs Entity objects (Domain Driven Design)
Hope this helps. Good luck!

Loading a Value object in List or DropdownList, DDD

I need to clarify something.
Have Person Aggreagate , 2 VOs (Country, StateProvince).
I want to load all country in my presentation layer (i am using mvc)
Evan says you only use repository (IPersonRepository) to work with root entity (it should always return just a reference to the Aggregate Root)
public interface IPersonRepository()
{
void savePerson(Person p);
void removePerson(Person p);
Ilist<Person> getPerson();
}
what i usually do to solve this :
Add in IPersonRepository this method
IList<Country> LookupCountrysOfPerson();
In Infra layer implement the Domain interfaces like this:
public IList<Person> LookupCountrysOfPerson()
{
return Session.CreateQuery("from Countrys").List<Person>());
}
My partner says im wrong.
Sometimes you have to sacrifice your domain model in order to accomplish some task
What is the best way to do this?
with code please! :)
I would say it's unlikely that you need country to be an entity. I suspect that country is nothing more than reference data, much like a person's title would be. Is there any behavior associated to country in your domain? I suspect it's just what's printed onto letters/envelops.
This question is somewhat similar to this one which I answered a while back:
Simple aggregate root and repository question
My suggestion is that you implement a Lookup service that your client can make use of and which is cached. Ignore the rules of DDD and anything to do with aggregates or repositories for this. As someone else has mentioned, this is where CQRS's ideology comes into play; the client shouldn't have to go through the domain in order to get data. The domain is purely transactional, not designed for queries.
This article explains how to build a generic lookup service for reference data for things that typically fill dropdowns in the UI (i.e. Title, Country etc)
http://wtfperminute.blogspot.com/2011/02/working-with-reference-data-lookups.html
Evans also says (pg 170) "An entity as basic as Location may be used by many objects for many reasons..."
I would also consider making Country an entity for the reasons given above. Perhaps more importantly, it is a low level object. You probably are also even supplying Country by configuration rather than through any actual domain activities. Therefore I would remove it from the Person and make it a standalone entity.
Also for this type of object you may not really need a dedicated repository, consider creating a single lookup service that provides query access for a group of similar objects of this nature.
If in your domain country is actually a VO (you don't want to maintain a thread of identity in the country name was changed etc.) which is the most common scenario, I would add a specialized class in the data access layer to return a list of all countries as VOs. I would also add caching (2nd level cache in NHibernate) to the country entity and list all countries query so that I don't have to hit the DB each time.
Actually, this is where CQRS really shines. CQRS acknowledges that you don't have to go through the domain layer in order to get some data for presentation purposes. In CQRS you just grab some data.
It sounds like countries are not in fact value objects here; they have distinct identities and are important for business purposes outside of your Person objects. They should become entities, and be treated in the fashion appropriate to them.
Think of it this way: let's say some volatile country had their current dictator overthrown and got a name change. The Person object's reference to a Country should still be valid, because the Country is not defined by its attributes (i.e. the string denoting its name), but by its identity.

Please clarify how create/update happens against child entities of an aggregate root

After much reading and thinking as I begin to get my head wrapped around DDD, I am a bit confused about the best practices for dealing with complex hierarchies under an aggregate root. I think this is a FAQ but after reading countless examples and discussions, no one is quite talking about the issue I'm seeing.
If I am aligned with the DDD thinking, entities below the aggregate root should be immutable. This is the crux of my trouble, so if that isn't correct, that is why I'm lost.
Here is a fabricated example...hope it holds enough water to discuss.
Consider an automobile insurance policy (I'm not in insurance, but this matches the language I hear when on the phone w/ my insurance company).
Policy is clearly an entity. Within the policy, let's say we have Auto. Auto, for the sake of this example, only exists within a policy (maybe you could transfer an Auto to another policy, so this is potential for an aggregate as well, which changes Policy...but assume it simpler than that for now). Since an Auto cannot exist without a Policy, I think it should be an Entity but not a root. So Policy in this case is an aggregate root.
Now, to create a Policy, let's assume it has to have at least one auto. This is where I get frustrated. Assume Auto is fairly complex, including many fields and maybe a child for where it is garaged (a Location). If I understand correctly, a "create Policy" constructor/factory would have to take as input an Auto or be restricted via a builder to not be created without this Auto. And the Auto's creation, since it is an entity, can't be done beforehand (because it is immutable? maybe this is just an incorrect interpretation). So you don't get to say new Auto and then setX, setY, add(Z).
If Auto is more than somewhat trivial, you end up having to build a huge hierarchy of builders and such to try to manage creating an Auto within the context of the Policy.
One more twist to this is later, after the Policy is created and one wishes to add another Auto...or update an existing Auto. Clearly, the Policy controls this...fine...but Policy.addAuto() won't quite fly because one can't just pass in a new Auto (right!?). Examples say things like Policy.addAuto(VIN, make, model, etc.) but are all so simple that that looks reasonable. But if this factory method approach falls apart with too many parameters (the entire Auto interface, conceivably) I need a solution.
From that point in my thinking, I'm realizing that having a transient reference to an entity is OK. So, maybe it is fine to have a entity created outside of its parent within the aggregate in a transient environment, so maybe it is OK to say something like:
auto = AutoFactory.createAuto();
auto.setX
auto.setY
or if sticking to immutability, AutoBuilder.new().setX().setY().build()
and then have it get sorted out when you say Policy.addAuto(auto)
This insurance example gets more interesting if you add Events, such as an Accident with its PolicyReports or RepairEstimates...some value objects but most entities that are all really meaningless outside the policy...at least for my simple example.
The lifecycle of Policy with its growing hierarchy over time seems the fundamental picture I must draw before really starting to dig in...and it is more the factory concept or how the child entities get built/attached to an aggregate root that I haven't seen a solid example of.
I think I'm close. Hope this is clear and not just a repeat FAQ that has answers all over the place.
Aggregate Roots exist for the purpose of transactional consistency.
Technically, all you have are Value Objects and Entities.
The difference between the two is immutability and identity.
A Value Object should be immutable and it's identity is the sum of it's data.
Money // A value object
{
string Currency;
long Value;
}
Two Money objects are equal if they have equal Currency and equal Value. Therefore, you could swap one for the other and conceptually, it would be as if you had the same Money.
An Entity is an object with mutability over time, but whose identity is immutable throughout it's lifetime.
Person // An entity
{
PersonId Id; // An immutable Value Object storing the Person's unique identity
string Name;
string Email;
int Age;
}
So when and why do you have Aggregate Roots?
Aggregate Roots are specialized Entities whose job is to group a set of domain concepts under one transactional scope for purpose of data change only. That is, say a Person has Legs. You would need to ask yourself, should changes on Legs and changes on Person be grouped together under a single transaction? Or can I change one separately from the other?
Person // An entity
{
PersonId Id;
string Name;
string Ethnicity;
int Age;
Pair<Leg> Legs;
}
Leg // An entity
{
LegId Id;
string Color;
HairAmount HairAmount; // none, low, medium, high, chewbacca
int Length;
int Strength;
}
If Leg can be changed by itself, and Person can be changed by itself, then they both are Aggregate Roots. If Leg can not be changed alone, and Person must always be involved in the transaction, than Leg should be composed inside the Person entity. At which point, you would have to go through Person to change Leg.
This decision will depend on the domain you are modeling:
Maybe the Person is the sole authority on his legs, they grow longer and stronger based on his age, the color changes according to his ethnicity, etc. These are invariants, and Person will be responsible for making sure they are maintained. If someone else wants to change this Person's legs, say you want to shave his legs, you'd have to ask him to either shaves them himself, or hand them to you temporarily for you to shave.
Or you might be in the domain of archeology. Here you find Legs, and you can manipulate the Legs independently. At some point, you might find a complete body and guess who this person was historically, now you have a Person, but the Person has no say in what you'll do with the Legs you found, even if it was shown to be his Legs. The color of the Leg changes based on how much restoration you've applied to it, or other things. These invariants would be maintained by another Entity, this time it won't be Person, but maybe Archaeologist instead.
TO ANSWER YOUR QUESTION:
I keep hearing you talk about Auto, so that's obviously an important concept of your domain. Is it an entity or a value object? Does it matter if the Auto is the one with serial #XYZ, or are you only interested in brand, colour, year, model, make, etc.? Say you care about the exact identity of the Auto and not just it's features, than it would need to be an Entity of your domain. Now, you talk about Policy, a policy dictates what is covered and not covered on an Auto, this depends on the Auto itself, and probably the Customer too, since based on his driving history, the type and year and what not of Auto he has, his Policy might be different.
So I can already conceive having:
Auto : Entity, IAggregateRoot
{
AutoId Id;
string Serial;
int Year
colour Colour;
string Model
bool IsAtGarage
Garage Garage;
}
Customer : Entity, IAggregateRoot
{
CustomerId Id;
string Name;
DateTime DateOfBirth;
}
Policy : Entity, IAggregateRoot
{
string Id;
CustomerId customer;
AutoId[] autos;
}
Garage : IValueObject
{
string Name;
string Address;
string PhoneNumber;
}
Now the way you make it sound, you can change a Policy without having to change an Auto and a Customer together. You say things like, what if the Auto is at the garage, or we transfer an Auto from one Policy to another. This makes me feel like Auto is it's own Aggregate Root, and so is Policy and so is Customer. Why is that? Because it sounds like it is the usage of your domain that you would change an Auto's garage without caring that the Policy be changed with it. That is, if someone changes an Auto's Garage and IsAtGarage state, you don't care not to change the Policy. I'm not sure if I'm being clear, you wouldn't want to change the Customer's Name and DateOfBirth in a non transactional way, because maybe you change his name, but it fails to change the Date and now you have a corrupt customer whose Date of Birth doesn't match his name. On the other hand, it's fine to change the Auto without changing the Policy. Because of this, Auto should not be in the aggregate of Policy. Effectively, Auto is not a part of Policy, but only something that the Policy keeps track of and might use.
Now we see that it then totally make sense that you are able to create an Auto on it's own, as it is an Aggregate Root. Similarly, you can create Customers by themselves. And when you create a Policy, you simply must link it to a corresponding Customer and his Autos.
aCustomer = Customer.Make(...);
anAuto = Auto.Make(...);
anotherAuto = Auto.Make(...);
aPolicy = Policy.Make(aCustomer, { anAuto, anotherAuto }, ...);
Now, in my example, Garage isn't an Aggregate Root. This is because, it doesn't seem to be something that the domain directly works with. It is always used through an Auto. This makes sense, Insurance companies don't own garages, they don't work in the business of garages. You wouldn't ever need to create a Garage that existed on it's own. It's easy then to have an anAuto.SentToGarage(name, address, phoneNumber) method on Auto which creates a Garage and assign it to the Auto. You wouldn't delete a Garage on it's own. You would do anAuto.LeftGarage() instead.
entities below the aggregate root should be immutable.
No. Value objects are supposed to be immutable. Entities can change their state.
Just need to make sure You do proper encapsulation:
entities modifies themselves
entities are modified through aggregate root only
but Policy.addAuto() won't quite fly because one can't just pass in a new Auto (right!?)
Usually it's supposed to be so. Problem is that auto creation task might become way too large. If You are lucky and, knowing that entities can be modified, are able to divide smoothly it into smaller tasks like SpecifyEngine, problem is resolved.
However, "real world" does not work that way and I feel Your pain.
I got case when user uploads 18 excel sheets long crap load of data (with additional fancy rule - it should be "imported" whatever how invalid data are (as I say - that's like saying true==false)). This upload process is considered as one atomic operation.
What I do in this case...
First of all - I have excel document object model, mappings (e.g. Customer.Name==1st sheet, "C24") and readers that fill DOM. Those things live in infrastructure far far away.
Next thing - entity and value objects in my domain that looks similar to DOM dto`s, but only projection that I'm interested in, with proper data types and according validation. + I Have 1:1 association in my domain model that isolates dirty mess out (luckily enough, it kind a fits with ubiquitous language).
Armed with that - there's still one tricky part left - mapping between excel DOM dtos to domain objects. This is where I sacrifice encapsulation - I construct entity with its value objects from outside. My thought process is kind a simple - this overexposed entity can't be persisted anyway and validness still can be forced (through constructors). It lives underneath aggregate root.
Basically - this is the part where You can't runaway from CRUDyness.
Sometimes application is just editing bunch of data.
P.s. I'm not sure that I'm doing right thing. It's likely I've missed something important on this issue. Hopefully there will be some insight from other answerers.
Part of my answer seems to be captured in these posts:
Domain Driven Design - Parent child relation pattern - Specification pattern
Best practice for Handling NHibernate parent-child collections
how should i add an object into a collection maintained by aggregate root
To summarize:
It is OK to create an entity outside its aggregate if it can manage its own consistency (you may still use a factory for it). So having a transient reference to Auto is OK and then a new Policy(Auto) is how to get it into the aggregate. This would mean building up "temporary" graphs to get the details spread out a bit (not all piled into one factory method or constructor).
I'm seeing my alternatives as either:
(a) Build a DTO or other anemic graph first and then pass it to a factory to get the aggregate built.
Something like:
autoDto = new AutoDto();
autoDto.setVin(..);
autoDto.setEtc...
autoDto.setGaragedLocation(new Location(..));
autoDto.addDriver(...);
Policy policy = PolicyFactory.getInstance().createPolicy(x, y, autoDto);
auto1Dto...
policy.addAuto(auto1Dto);
(b) Use builders (potentially compound):
builder = PolicyBuilder.newInstance();
builder = builder.setX(..).setY(..);
builder = builder.addAuto(vin, new Driver()).setGaragedLocation(new Location());
Policy = builder.build();
// and how would update work if have to protect the creation of Auto instances?
auto1 = AutoBuilder.newInstance(policy, vin, new Driver()).build();
policy.addAuto(auto1);
As this thing twists around and around a couple things seem clear.
In the spirit of ubiquitous language, it makes sense to be able to say:
policy.addAuto
and
policy.updateAuto
The arguments to these and how the aggregate and the entity creation semantics are managed is not quite clear, but having to look at a factory to understand the domain seems a bit forced.
Even if Policy is an aggregate and manages how things are put together beneath it, the rules about how an Auto looks seem to belong to Auto or its factory (with some exceptions for where Policy is involved).
Since Policy is invalid without a minimally constructed set of children, those children need to be created prior or within its creation.
And that last statement is the crux. It looks like for the most part these posts handle the creation of children as separate affairs and then glue them. The pure DDD approach would seem to argue that Policy has to create Autos but the details of that spin wildly out of control in non-trivial cases.

Resources