Usually the domain logic should be contained in the domain entity, rather than being put in specialised external classes called from the entity.
This is good to prevent that somebody comes later, changes the class with the domain logic and affects, without knowing it, the domain entity.
Example
Human {
private birth_date;
public calculateZodiac();
public calculateBadLuck();
}
The methods rely on the birth_date
and encapsulate the entity domain logic.
But what if..
in a specific context I need to save resources and I can't afford to create an instance of the domain entity but, just knowing the birth date, I want to still be able to calculate the zodiac and the bad luck?
Solutions
Domain logic in external class
I could have the logic in a Zodiac class, that gets all the needed data (in this case: a date) and returns my calculations. This is also good for separating concerns, improve readability (rather than having a huge domain entity containing the complex code for all concerns regarding Humans).
It would also be nice for being able to reuse that logic in different domain entities (e.g. Animal).
So calculateZodiac()
would instantiate a new Zodiac
, calculate()
stuff and return it.
But, as said above, this can be changed by somebody without noticing the direct side effects on the domain entity.
And it goes in the direction of an anemic domain model, that is considered an anti-pattern by Martin Fowler.
Composition
When instantiating the Human domain entity, always provide the Zodiac implementation to its constructor.
Same risk as before, but at least the dependency is explicit.
Also, after providing the Zodiac, do the same for the classes PsychopathProfile, ExpectationOfLife, ProbabilityToBeBulliedBasedOnUnfortunateName, SportivePotential, etc..
Too much stuff in the constructor, each time I instantiate. Not ideal.. 🙄
Just duplicate the code & keep integrity with unit-testing
Accept that when not working directly on the domain entity then the concern is just a different one, even if the logic should be the same.
So just take the logic from the domain entity, put it in a ZodiacFromBirthDate class and use it without a domain entity.
And to ensure that nobody comes later and breaks something, just add some tests that ensure that the Human.calculateZodiac()
method always returns the same values as ZodiacFromBirthDate.calculate()
method.
Others..
Can you come up with other solutions?
How to ensure that the domain logic is not accidentally changed, while still allowing to reuse the logic also without having a domain entity available?