3

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?

Rakshi
  • 6,796
  • 3
  • 25
  • 46
Lucian
  • 78
  • 6
  • 1
    My first piece of advice when considering the domain model is to forget about persistence, it muddies the waters. If you have a piece of logic that spans entities, the answer may be a higher-level aggregate root or a domain-level "service". – Adam Houldsworth Jun 04 '14 at 10:39
  • So, logic that relates just to the current instance need to be put in the entity, but the one that depends on the outer context, needs to stay out. True? – Lucian Jun 04 '14 at 11:22
  • In this case it looks like the logic relates to child entities of this entity, so should be managed by this entity also. A parent is responsible for it's children (unfortunately ;-) – Adam Houldsworth Jun 04 '14 at 11:44

1 Answers1

6

I was trying to find a clear and simple example of what an anemic domain really means

It's in fact really easy to go from an anemic domain model to a rich one.

  1. Set all property setters to private and then add methods if you want to change state of a model.
  2. Evaluate all Law of Demeter violations and add methods where suitable.

Eventually you will have a correct model.

In your case I would encapsulate that logic inside TaskData as your TaskStateCalculator violate Law of Demeter

public class TaskData
{
    public Guid InternalId { get; private set; }

    public string Title { get; private set; }

    public string Details { get; private set; }

    public TaskState ExplicitState { get; private set; }

    public IEnumerable<TaskData> InnerTasks { get; private set; }

    public TaskState GetState()
    {
        if (!InnerTasks.Any())
            return ExplicitState;

        if (InnerTasks.All(x => this.GetState(x) == TaskState.Done))
        {
            return TaskState.Done;
        }

        if (InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
        {
            return TaskState.InProgress;
        }

        return TaskState.Default;
    }       
}

another 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

jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • Why still the `taskData` parameter on method `GetState`? You're basing the result of the method on the parameter and the current (`this`) object. – Maarten Jun 04 '14 at 10:33
  • Point 1 seems like a strange way of stating it. Public property setters often are the appropriate way of changing a model's state. I agree that you should start with them private until you have a good reason to make them public, though – Ben Aaronson Jun 04 '14 at 10:33
  • @BenAaronson: It's to challenge the developer. 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. – jgauffin Jun 04 '14 at 10:39
  • 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. – jgauffin Jun 04 '14 at 10:43
  • @jgauffin Yeah that I agree with when a change involves multiple properties. But if there's extra logic needed to change a single proprety, that can go in the property's setter. Could you also explain how the law of demeter led you to that specific refactoring? Going by LoD alone, wouldn't a simpler refactoring be to have `TaskStateCalculator`'s `GetState` take the collection of inner tasks as their parameter? – Ben Aaronson Jun 04 '14 at 10:44
  • @BenAaronson If the situation were that a single property can be changed and it leaves the model valid, then there is little difference. The only meaningful difference is discipline. You can change a property `Surname = "Houldsworth"` or you can have a method for it such as `ChangeSurname("Houldsworth")`. The functional difference is nothing, the **expressive** difference is that you are asking the model to change its state based on a request, thus responsibility *appears* to be the models. Expressiveness is higher priority than implementation in a good domain model. – Adam Houldsworth Jun 04 '14 at 10:48
  • Law of Demeter told me that something was wrong. Then I had to come up with a better solution. As the logic seems to belong in the class itself (as it operates on the class state) it seemed like the better solution. Then again, if I had the whole project I might have come up with a different solution. – jgauffin Jun 04 '14 at 10:48
  • @AdamHouldsworth Fair enough, though I think the expressive difference depends on your background. Because of the prevalence of properties in C#, it's natural to think of every access of a property as asking the class to execute a get or set method on it – Ben Aaronson Jun 04 '14 at 10:53
  • 1
    @BenAaronson True, but the other assumption with properties is that the backing code is lightweight, and the assumption with domain entities is that they manage validity - both of which are implementation details and the responsibility of the entity. Implementation details can change in future so coding a reliance on them is a risk. This is where the argument for the main difference being discipline comes in. Though as with everything, there are times when anaemic models are perfectly good design choices, not everything needs a 100% true DDD approach. – Adam Houldsworth Jun 04 '14 at 10:57
  • If _TaskStateCalculator_ would be refactored to: `public TaskState GetState(TaskState explicitState, IEnumeration innerTasksData)` -- the **LoD** would not be broken anymore. In that case, would it still be needed to move the logic inside _TaskData_? – Lucian Jun 04 '14 at 11:13
  • And what about the second question? Adam Houldsworth was suggesting to put that kind of logic inside an outer class, like a service. So, logic that relates just to the current instance need to be put in the entity, but the one that depends on the outer context, needs to stay out. True? – Lucian Jun 04 '14 at 11:18
  • I usually try to follow a rule that says: If you need to operate on more than one domain entity use a service. In this case you need to use more than one TaskData = use a service. This is of course something one have to decide from case to case. – jgauffin Jun 04 '14 at 11:27
  • @Lucian I wasn't quite suggesting that, but situations where entity boundaries are crossed might be due to needing to relocate the aggregate root. Cohesion between logically separated entities can be handled by services at the domain layer. – Adam Houldsworth Jun 04 '14 at 11:46