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.
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.
Recently I was thinking about some issues I had in the past while attempting to design a particular domain model, lets just say Address, that can be editable with a given context but non-editable within another. My current way of thinking is that I would have both a Value Object version of the Address and an Entity for the Address perhaps attached to something like a customer account in order to derive it's identity.
Now I'm realizing that if I'm ever creating a new Address, such as when one is entered in by the user, that I most likely also need to be able to continue to edit that Address and perhaps edit any preexisting Addresses as well within that same bounded context. For this reason I could assume that within this context Address should be modeled as Entity and not a Value Object. This leads me to my main question which is that if you should always be using entities when modifying an existing set of data or creating a new data then does it ever make sense to have a Factory for creating any Value Object?
The rule that is beginning to emerge for me as I follow this line of thinking is that value objects should only be created to represent things that are either static to the application or things that have already been persisted into the database but not things that are transient within the current domain context. So the only place I should any type of creation of value objects would be when they are re-hydrated/materialized within or on the behalf of aggregate root repositories for persistent values or within a service in the case of static values. This is beginning to seem pretty clear to me however it concerns me that I haven't read anywhere else where somebody is drawing the same conclusions. Either way, I'm hoping that somebody can confirm my conclusions or set me straight.
that can be editable with a given context but non-editable within
another
Differences in mutability settings for an entity within different contexts can also be represented in the application tier. It is an operational concern, possibly involving authentication and authorization and an application service is a convenient location for this logic. The distinction between a VO and an entity does not address these concerns directly. Just because a VO should be immutable, does not mean that an entity cannot change the value of a VO that it references. For instance, a user can reference an immutable address value, however an edit operation can update the user to reference a new value. Allowing a user to edit an address in one context and not in another can be represented as permission values associated with the corresponding context.
This leads me to my main question which is that if you should always
be using entities when modifying an existing set of data or creating a
new data then does it ever make sense to have a Factory for creating
any Value Object?
It can certainly make sense to have a factory for creating VO instances. This can be a static method on the VO class or a dedicated object, depending on your preference. However, a VO should not be used to address mutability requirements of the domain model. Instead, as specified above, this should be handled at the application tier.
I have Person aggregate in which Address is part and vo , but now i have another aggregate Payment which have another VO PaymentInfo , which contains details like Creditacard number and other details, but now i need Billing Address and Shipping Address in PaymentInfo VO. Now since Address is integral to Person i cannot use that.
So what i do ,
Create separate Address Vo in Payment aggregate and use it as billing address and Shipping Address.
Move address in to separate aggregate and reference it in PaymentInfo and Person.
Create two addresses in Person itself and reference it in PaymentInfo Vo.
help me please ?
Important thing here is - value objects have no identity.
That means - they can become shared between entities easily.
With that I mean - not particular instances should be shared, but their classes, type Address instead of "UK, London street 'whatever' 16". Value object instances should never be shared (again - cause they got no identity and their state is what defines them).
So in Your place - I would make sure Address as a concept is mutually ubiquitous for person and for payment info (they must have same structure), move it into right folder/namespace so I could see that it's shared and use it for both entities.
If they aren't ubiquitous, I would rename Address as PersonAddress and create second one - PayerAddress (name might differ according to Your business You are modeling).
Quoting Jeff from provided link:
There's no problem with 2 aggregate roots referencing the same entity - they just can't reference another aggregate's internals. It is different for value objects, which are simpler. Consider how you can reference dates, like "August 20th, 2010," any number of times in your classes.
i will go with ubiquitous nature of it. Dont reference the Person address class to the billing address and the shipping address..
Two things Can be achieved easily .one is the communication benefit which you can get in the business analyst and second is the Coding will be explicit and understandable.
I have gotten so far that I understand entity objects have an ID while value object have not, but in the most common example you have the person entity that have a address value object attached to it. What is the big advantage of creating a separate address object instead of just keeping the address properties within the Person Entity?
In addition to the things already mentioned, Greg Young makes a big deal out of the fact that since they are immutable, you can validate them on creation and never worry about validation again. If the state cannot be changed, then you know it's always valid.
Value objects can be used as arguments for other methods in other classes
It can make your design clearer
It might help with performance optimization (example: fly-weight pattern)
Value objects can be reused in different entities. (example: user and location entities with address value objects.
Don't forget that "not having an id" is not the only difference between value objects and entities, being immutable is also very important.
Think of it as a reusable component. You can make it into a home address, work address without much extra effort. You can use it to decouple other systems from the person entity. Say you introduce a business entity. It will also have an adress.
Related to this subject is another important subject: composition vs. inheritance