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?
Probably not; the samples you provide suggest that you are designing an Anemic Domain Model. You might also want to review Tell, Don't Ask.
My view: big vs small is really an evaluation of the size of the data model controlled by the entity, rather than by the number of different methods you have that act upon that data model.
For example, if you have a single integer field, and 100 methods that need to lock that field (typically: while changing it), then you are going to end up with a single entity with 100 methods.
On the other hand, if you have two fields, and 100 methods that need to lock either field A or field B, but no method needs to lock both fields, then your entity is "too big", and you should consider using two entities instead.
The analysis metaphor that I use is that of a connected graph - draw an edge between each pair of values that need to be locked at the same time, then separate the graphs so that you can lock each without locking any of the others.
It's somewhat common to analyze a concept like "Customer" and discover that what you have are many disconnected graphs that all share the same lock. Those are entities that you should consider breaking up.