When things are not clear, you only need to ask the right questions.
Imagine you enter a library to borrow a book.
What would you typically do is to ask for the book by its title and author.
The library employee checks the inventory and finds two available physical copies of the book.
Can we say that those two copies represent the same thing? Yes and no.
For you as a library customer, whether the employee would give you one or the other of the available copies won’t make any difference.
In your perspective, the physical copy is a Value Object.
But as a library employee, having two copies of the same book is a complete different story. She needs to know exactly when each copy was acquired, to whom it was lended, in which bookshelf is it stored.
In her perspective, the single copy of the book is an Entity.
Every physical book copy which is acquired by the library is labeled with an entry number. The entry number is the property by which a library employee can univocally identify a physical copy.
As a customer, do you care about the entry number? Probably not.
Keeping this insight in mind, the concept of book can be modeled to specifically reflect this double perspective:
Value Object or Entity. How to choose?
Ask yourself the following questions:
- Is there any difference if I swap two objects with the same properties?
- In which part of the domain am I?
- From which point of view am I building this part of the model?
- In general, how many actors are looking at the object?
- How many different perspectives I can find?
When you have only one use case, the swapping trick is an easy one.
You should apply it in advance in order to understand if something is a Value Object or an Entity.
When there are multiple perspectives, though, things get more nuanced and you must go deeper in the understanding of your domain.
In this case, the common error that you must avoid is to define a single class modeled as an Entity.
You can recognize that kind of classes because they are stuffed it with all possible behaviors. For every use case. Performed by any actor in the game.
Refrain from modeling something like that.
Doing otherwise would be like lying. You will later see that something feels wrong in your code. That something doesn’t belong where it is.
Instead, use the opportunity to gain insights about the multiplicity of your model.
Create as many classes as many point of views of the object.
In other words, acknowledge the complexity of your domain and show it in all its glory inside your codebase.