Question:
There is the essence of "customer" ( Customer
). The client can have 1 mobile phone number and 1 email address. The phone number, as well as the email address, can be in two states – "Not confirmed" and "Confirmed". Looking ahead, I will say that all these 4 parameters should be stored in one Customers
table in order to avoid unnecessary JOINs.
My main question is, how do I model the domain model?
The PhoneNumber
and IsPhoneNumberConfirmed
(like Email
and IsEmailConfirmed
) look like they are expressing something whole . One could define a ValueObject Communication
with two parameters Value
and IsConfirmed
. Then, the Customer
class might look like this:
public class Customer
{
public Communication Phone { get; private set; }
public Communication Email { get; private set; }
}
But what about the fact that IsConfirmed
is essentially the state of an object (which, if I'm not mistaken, contradicts the concept of ValueObject)? It would probably be convenient from the API point of view to define the Communication.Confirm()
method, which will change the IsConfirmed
state to true
. Which, again, is contrary to the concept of ValueObject (VO must be immutable after creation).
Could it be an Entity? Then these objects should be stored in separate tables in the DB? This is contrary to what I described at the beginning ("… all these 4 parameters should be stored in one Customers
table").
Maybe I made the wrong assumption that the PhoneNumber
and IsPhoneNumberConfirmed
must be part of the same entity?
Maybe the communication method must be in the customer class: Customer.ConfirmMobilePhone()
? After all, it is the client who confirms the phone, and not the phone confirms itself.
Answer:
In fact, there are many ways to design.
If you approach the question canonically, then your phone is an Entity
because it has an identity and a life cycle. At the same time, it is not at all necessary that the phone should be the root of the aggregation (although maybe, suddenly, you want to track the change of the owner of the phones). If the entity is not the root of the aggregation, then it necessarily refers to some kind of aggregate, in your case to Customer
. At the same time, it does not matter at all where this entity is stored, in a separate table or in a field at the client's. DDD
does not impose such restrictions at all. Remember non-relational databases, where all the entities of the aggregate are generally stored in one blob.
On the other hand, you can look at the phone as a characteristic of the client, which changes one of its characteristics (I have an unconfirmed phone XXX-XXX) to another characteristic (I have a confirmed phone XXX-XXX) and then your phone already has no identity or life cycle, but this is already an honest Value Object
.
In your case, the difference is not at all significant, choose any of the two and store it where it is more convenient for you.
Two more points in your text:
- Do not focus on the fact that the
Value object
not mutable, it is better that it is only a characteristic of theEntity
like color, size or maximum speed. - The fact that the phone confirms itself in OOP is generally the norm.