I'm making an app, trying to stick to DDD concepts and practices. I have a rich domain model, with entities, value objects, business rules encapsulated within them, etc.
Entities don't really have too many fields and are relatively small when it comes to contained data, but the problem is, some of them got really big (as in: classes representing them) because of lots of possible interactions with those entities.
You know,
void DoThis();
int GetThat();
bool CheckForThis();
every interaction with some piece of my domain is represented by a public or internal method, each of those methods containing some business rules.
I tried to extract that logic into internal classes I call policies, so instead of
public int CalculateAmountOfCoolThingy()
{
int result = 0;
/*
Super duper complicated calculations here with 100 lines of code.
*/
return result;
}
in my entity, I have:
internal sealed class CoolThingyCalculationPolicy
{
public int CalculateAmountOfCoolThingy(MyEntity entity)
{
int result = 0;
/*
Super duper complicated calculations here with 100 lines of code.
*/
return result;
}
}
and in my entity:
public int CalculateAmountOfCoolThingy()
{
CoolThingyCalculationPolicy policy = new CoolThingyCalculationPolicy();
int result = policy.CalculateAmountOfCoolThingy(this);
return result;
}
Is this the way? Is this a good practice? Because it doesn't feel entirely right. Maybe there's some better approach?
Yes, you can encapsulate those rules in another class named domain services. But remember that you must inject the service into your domain model.
There are three attributes of a design that you should consider. The domain purity, completeness, and performance. You can't have it all at the same time.
In this article, Vladimir Khorikov talks about these three and I suggest you read it thoroughly. In the conclusion, he suggests that domain purity is more important than completeness (you can read about the reasons in the article). So I suggest that:
Another thing to consider is that moving logic to domain services is not recommended unless you have a good reason for it. Fat domain services mean thin domain models which results in anemic domain models. To manage your domain models better, consider separating them into smaller building blocks like entities and value objects. Using domain services to make smaller models feels like cheating. Because the responsibility should be on the domain model and you force it into another object. It's not a good reason to create domain services unless you want to reuse some logic or calculations.