I was trying to find a clear and simple example of what an anemic domain really means. There is a lot of theory around, and also many well answered questions. Still, I could not get a clear picture about to what extent "anemic domain" meaning really goes. Therefore, I believe it would be simpler to see a dummy practical example of an anemic domain design and than ask you how could this be evolved to a domain driven one...
So, let's say we have a data entity of type TaskData:
public class TaskData
{
public Guid InternalId { get; set; }
public string Title { get; set; }
public string Details { get; set; }
public TaskState ExplicitState { get; set; }
public IEnumerable<TaskData> InnerTasks { get; set; }
}
And there is the need of an additional property called "ActualState", which is a computed state: if the Task has inner sub-tasks, the value strictly depends of the children, otherwise, the "ActualState" is equal to "ExplicitState"
If I write this logic in a separate service class (I call them "engines") we have:
internal class TaskStateCalculator
{
public TaskState GetState(TaskData taskData)
{
if (taskData.InnerTasks.Any())
{
if (taskData.InnerTasks.All(x => this.GetState(x) == TaskState.Done))
{
return TaskState.Done;
}
if (taskData.InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
{
return TaskState.InProgress;
}
return TaskState.Default;
}
return taskData.ExplicitState;
}
}
The first question is:
Does the code above reflect an anemic domain design, even if the TaskStateCalculator service/engine is part of my Domain Layer? If yes, in order to avoid it, we'll need to move the logic inside the TaskData class (and rename TaskData to Task). Am I right?
The second question is (actually a chain of them):
What if we have a more difficult situation? Let's say there is the need for a property called ComputeSomething inside Task entity, and the logic of this property needs to access the entire Task's repository. In this case, the Task class would have a dependency on TaskRepository. Would this be ok? How would EF construct an instance of such class? What is the alternative?
It's in fact really easy to go from an anemic domain model to a rich one.
private
and then add methods if you want to change state of a model.Eventually you will have a correct model.
In your case I would encapsulate that logic inside
TaskData
as your TaskStateCalculator violate Law of Demeteranother thing is that I would probably not expose InnerTasks collection at all to the outside world (just have it as a member field). But it's hard to say as I do not know how the class is used in other scenarios.
Why private setters
Every time you have to change more than one property it's often better to describe the behavior with a method, as it's then impossible to forget to change all required properties. A method also describes better what you are trying to do than changing a set of properties.
Even if you just change a single property, that property can set the class in an invalid state as the change may not be compatible with the rest of the information in the class. Don't forget that encapsulation is one of the core principles in OOP