Reputation: 159
I am familiar with DDD and the concept of Entity.
According to DDD, Entity is an object fundamentally defined by its identity.
Say, in my project, I have identified that an Account
is an Entity. So in code, this would be represented by a class with an identifier field, something like
class Account {
private Id id
private AccountStatus status
...
}
Since this is an entity, all its fields can change over its lifetime except the Id
.
My question is, what is the best way to model this in code in terms of state change and object equality.
Since an entity's state changes over time, should the class be modelled as a mutable class or should it be immutable with a new reference created with every state change?
Since an Account
is identified solely based on its Id
, should the equals method only compare object's identifier? What are the potential problems with considering all OR no fields.
Upvotes: 1
Views: 264
Reputation: 57397
I would suggest that you review Clojure's epochal time model. Stuart Halloway's 2010 talk Perception and Action details the epochal time model.
The entity is, in a sense, a mutable reference to immutable state.
In an object oriented style, we might do something like
Entity {
MutableRef<State> mutableRef;
void change (...) {
State current = mutableRef.get()
State next = someFunction(current, ...)
mutableRef.set(next)
}
}
(We don't, typically, because in the Java lineage of OO the common practice is to manipulate mutable values).
My question is, what is the best way to model this in code? I see two approaches,
Since this is an entity, conceptually, all its fields can change so the model should support mutation(setters) and equality defined only on Id field.
Model this as a Value Object, i.e immutable, final fields, equality defined over all fields and on mutation, create and return a new object.
If, in the language of your business, you describe an account as a thing that changes over time, you probably want to use an entity model.
That doesn't necessarily mean "setters"; the more common style is that mutators should be written in the language of the business. We tell the entity what to do
account.close()
and its the entity's job to understand how that action affects the underlying data structure.
As for identity, here is a more recent remark by Evans:
I have come to believe that an entity shouldn't even have an equality operation
The video clip appears to be taken from a module the 2014 Pluralsight course Domain-Driven Design Fundamentals, by Julie Lerman and Steve Smith.
Upvotes: 1
Reputation: 726
Usually, Entities and ValueObjects are mutually exclusive concepts for a given case. Different domains also care differently about different concepts and one such concept might be a ValueObject in a given Domain and an Entity in another given Domain.
One such example is Money as a concept. For an E-Commerce context, Money is probably a ValueObject since the domain will care only about its Value and not its persistent Identity (for such system, 2 instances of 10 USD will be the same and you will not care about naming them apart).
For the Federal Bank (or whatever is the Entity that prints Money) treats Money in a totally different fashion. This Domain actually labels individual bills with serial numbers and care a great lot about the history of every single bill (when was it printed, which was the model, probably also where was it printed). As such, this domain will probably model Money as an Entity.
These differences will also affect how equality is handled.
For a ValueObject, equality is usually defined on "2 instances having the same value" so, you're probably better matching every value field in order to establish equality. The Money instance "10 USD" is equal to the other Money instance "10 USD", but its different to the Money instance "10 EUR" (their FaceValue property is the same, but their Currency is not so you can't use them interchangeably).
Now, for an Entity, you care about the identity of a given instance for its whole lifetime (as a concept, not as an instantiation). So, if you have a Money instance with Serial Number 1234 and properties "10 / USD / NearMint" and it becomes damaged, it changes and keeps its Serial Number 1234, but its properties are updated to "10 / USD / Stained". Its still the very same bill and for all accounts it should respond to equality comparers as true.
Just to finish this long answer, the "setter" part is also domain dependent. Usually, ValueObjects shouldn't change their internal states. But Entities should only change their internal states based on the domain rules. In the money example, probably makes absolutely no sense to be able to chance the FaceValue or Currency of a given bill even when its an entity. How ever, its state NearMint -> Stained -> Damaged -> etc probably can evolve over time. Also, you should probably consider not using always straight setters and instead create domain meaningful methods in your entities to better express the ubiquitous language when handling state transitions.
Upvotes: 0