EP6: Entities vs Value Objects: Which one is better?
Deciding whether something should be an entity or a value object can be tricky even for developers experienced in domain-driven design. In this issue, I'll clarify the differences so we understand these concepts once and for all! Let's get started!
Entities and Value Objects as Classes
Entities and Value Objects represent tangible and intangible concepts within an application. In object-oriented languages like Java or C#, they both are classes with properties and behavior. But what’s the difference?
Entities
Entities have a unique identity that is defined by identifiers. This means that each instance is distinct, even if their attributes are identical. Two people with the same first name and last name are not the same person. A unique identifier, like a user ID or a social security number, distinguishes them.
Entities are also mutable. Their state can change while their identity remains constant. For instance, the price of a product can be updated multiple times, but its unique identifier, such as a stock keeping unit, remains the same.
Value Objects
Value Objects are defined solely by their attributes and have no identifiers. Two Value Objects with the same attributes are considered equal and are conceptually the same. For example, the color white is defined by its red, green, and blue values all being 255. No matter how many instances of this object exist, they all represent the same color.
Value Objects are also immutable, ensuring that once they are created, their state cannot be altered. This immutability guarantees that the equality of value objects remains consistent over time, preventing accidental changes that could lead to subtle bugs and inconsistencies in the system.
In a nutshell, entities have identity and are mutable, while value objects have only attributes and are immutable.
Why do we need to distinguish between Entities and Value Objects?
Even though we've clarified the theoretical difference, it might still be unclear why this distinction exists and when to use each construct. Let’s cover this point before diving into a code example.
The reason why we distinguish between entities and value objects is to make our domain model more expressive, simpler and safer.
Entities come with inherent complexities. We need to define and create their unique identifiers, allow their state to be modified, while ensuring consistency with the business rules over their entire lifetime.
Value Objects, on the other hand, are easier to maintain. Without identity to manage, their immutability guarantees consistency. Once created, their state cannot be changed, making them thread-safe. They also promote side-effect-free functions, returning new instances without altering the originals. This makes the code more predictable, reliable, and easier to test.
This is why we should prefer Value Objects to Entities whenever possible.
Code Example
Let’s see this in practice. Imagine we are modeling a bare metal server in the context of an infrastructure as a service provider.
The class above is a simplified version of the server entity. As you can see, this class lacks readability, and its constructor is already messy. Just imagine how complex it would become if we had to add all the necessary logic to keep its state consistent with the business invariants whenever an instance is created or modified.
Now, we can see the same class refactored to use Value Objects. Not only have we improved its readability, but all invariants are now validated in the relevant classes. For instance, we enforce specific formats for the entity identifier, server code and resource name in their own constructors, while also ensuring they are never null.
By placing the logic where it belongs, we are able to reuse it across the system. If we need to enforce standard identifiers and resource names for all our entities, we can simply reuse the same value objects, as demonstrated in this network entity.
When should we use Entities?
This is why we should use entities only for those elements of our domain that require unique identity and state management. We can then enrich the model with immutable value objects, which help group related attributes and enforce business rules consistently across the entire system with ease.
Whether something deserves to be an entity or not in our domain depends on the business requirements. A delivery address is typically modeled as a value object associated with a user or account in an e-shop system. However, the same address might be modeled as an entity in a logistics or public government system. For instance, we might need to know how many residents live at a particular address.
Conclusion
I hope you enjoyed this issue! If you have questions, just leave me comment or write me an email. Don’t forget to help me by liking and sharing this article or the video below, so that everyone can learn something new!