Anemic Model
Someday I fall into a trap and use this anemic model where I should not.
I know that hiding implementation is important.
Therefore the anemic model which has all properties available by getters and setters is not a good solution, because any programmer can call any setter and change the state of the object. Such a Class does not have any business logic, all logic is in other classes like Services or Helpers (therefore named "anemic").
Stability
It is effortless and you may ask why this is a problem.
Let's say you need to set variable is available when some condition is true (e.g. stockQuantity > 50)
If you used this setter you need to write code like this
public function changeAvaiblity() {
if (stockQuantity > 50) {
$product->setAvaible(true);
}
...
// Product class
public function setAvaibility(bool $avaible): void {
$this->avaible = $avaible;
}
but how do you ensure that this condition will be covered in another part of the system?
Maybe some programmers did not go too deep and hack your solution
...
$product_service->changeAvaiblity();
...
$product->setAvaibility(true);
As you see setters can be run at any time and change state.
Better solution
So I avoid setting via public setter but I use a private method. But there is a catch here.
Imagine I will get new business requirements, there I wrote a new function but forgot to call the function setAvaibility(true)
and my state of the object is not correct.
Use the constructor to set an initial state
The best solution is to use a constructor to set the initial state and simply to avoid to situation where the state of the object is not correct.
Rich domain model
This action is a part of the Rich domain model where we create our models to avoid creating objects in incorrect states.
The purpose of the rich domain model is to create consistent classes, all variables and public interfaces of the class are consistent, and present domain logic.
To archive that, we can use e.g. Value Objects which can guard our rules.
We expose business logic methods not states of objects.
So we use
public function isAvailableForSale(): bool {
if (stockQuantity > MINIMUM_STOCK_VALUE) {
$product->avaible = true;
}
return $this->avaible;
In the Rich domain model, we expose behaviors. For my little example, behavior is 'Is Product available for sale' but this could be any other question
There is one more point for using rich domain models.
Testing the Rich domain model is much easier than testing the Amenic model.
When we use the Anemic model
We use them as DTOs (Data Transfer Objects) because we want only to read data and send it through e.g. in RestApi, or to send data between layers of our application or for Database entities.
Conclusion
If you need simply DTO, you can create The Anemic model.
But if there is more logic and it is not a simple CRUD you should use The Rich domain model to lean your logic on stable behaviors/contracts which are easy to test and help you to avoid introducing your objects in an incorrect state and make logic and application more consistent.
Top comments (0)