0

Let's say you've an anemic domain model (ADM):

public class Employee
{
    public Employee() 
    {
        _roles = new List<Role>();
    }

    private IList<Role> _roles;

    public Guid Id { get; set; }
    public string Name { get; set; }

    public IList<Roles> Roles { get { return _roles; } }
}

public class EmployeeManager
{
    public Employee GetByName(string name) 
    {
        Contract.Requires(name != null);

        return repositoryOfEmployeesInstance.GetByName(name);
    }

    public void AddEmployee(string name) 
    {
        Contract.Requires(name != null);

        // The unique identifier will be generated by the OR/M behind the scenes...
        repositoryOfEmployeesInstance.Add(new Employee { Name = "Matias" });
    }
}

Later, in some other place, you've this code:

Employee some = new EmployeeManager().GetByName("Matias");
some.Roles.Add("Principal");

Now, in addition to the domain model, there's an aspect called DomainValidationAspect which validates the new employee just before it's going to be persisted in the Repository implementation.

The whole ValidateEmployeeAspect can validate an Employee either when one it's added or updated, which is the case of adding a role. It is responsible of loading Employee's domain rules and verifying them. Domain rules are implemented using the specification pattern.

Finally, everything happens in a domain transaction.

Right, it's seems to be an anemic domain model from the point of view of object-oriented programming, but what about aspect-oriented programming.

So the question is...

...may a domain-driven design be anemic just because:

  • ...in this case, Employee roles are added using the collection interface?
  • ...absence of behaviors in Employee from the point of view of pure object-oriented programming?

Some words

My opinion is it's true that aspect-oriented programming has the drawback of hiding a lot of details in the main flow of the domain (or any other layer), but a bird-eye on the concept behind an object-oriented plus aspect-oriented approach would map to a rich domain model rather than an anemic domain model.

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • 1
    Aspects might be a good call for logging or error handling, but are you sure they are the most efficient way to implement entity validation ? Besides, in a rich domain model, there's much more to entities than validation... What about the specific domain methods you could need ? Will you place them in an aspect as well ? – guillaume31 Jan 11 '13 at 13:18
  • @guillaume31 No, I wouldn't implement a domain method in an aspect but in a domain manager class. – Matías Fidemraizer Jan 11 '13 at 13:25
  • With managers that contain persistence logic **plus** every domain method specific to their entity, I don't know if your domain model is anemic, but it sure suffers from *ancillary object hypertrophy* :) – guillaume31 Jan 11 '13 at 14:18
  • From my understanding, anemic domain is considered an anti-pattern because it organizes code in a way that does not take full advantage of the benefits offered by OOP. See martinfowler.com/bliki/AnemicDomainModel.html. As long as you know the cons of your approach and believe them to be acceptable, then you should do what is right for you. At end end of the day, it all comes down to whether you are achieving your desired benefits at a cost that is worth it to you. – Aaron Hawkins Jan 11 '13 at 14:36
  • @AaronHawkins I know the whole article. By the way, I tend to think that there're many ways of taking full advantage of OOP and one could be my approach, which takes advantage of AOP for some things that would be directly implemented in the domain object. Well, really this could end in a very long discussion... I know. – Matías Fidemraizer Jan 11 '13 at 14:44
  • In an attempt to make this a short discussion, I will make the main point that seems to stand out. You said, "[AOP] has the drawback of hiding a lot of details in the main flow of the domain (or any other layer)". IMHO, modelling these aspects (real-world-obj - programming-language-obj) is one of the largest advantages of OOP. – Aaron Hawkins Jan 11 '13 at 15:29
  • @AaronHawkins I'm agreed. In my case, I don'f find AOP style of programming a drawback, but it can turn into one for novice, less experienced programmers, or for ones having less level of abstraction skills in their mind. But in terms of "OOP advantage", I'm sure that it's a good point. – Matías Fidemraizer Jan 11 '13 at 15:42

2 Answers2

3

A few points come to mind (in no particular order):

  • In Domain-Driven Design an Aggregate (here an Employee) is never allowed to be in an invalid state. It enforces its invariants itself, so there should be no need for an external validation.

  • This sound very much like CRUD to me. Why force DDD upon simple CRUD?

  • What does EmployeeManager do except just wrapping the repository methods and therefore being only yet another layer of complexity.

  • A repositoryOfEmployeesInstance sounds very artificial to me. Just like you would not call a class EmployeeClass or EmployeeManagerClass, why would you suffix an object with Instance?

    Also why append the pattern name (here Repository)? Just go ahead and call it employees. That sounds like a real thing:

    employees.GetByName(name)

    Or even better: employees.Called(name)

Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
  • Thank you for the answer. The prefixes or suffixes I've added to variables and so were only there for the explanation. Obviously, the real-world code looks like you may imagine. – Matías Fidemraizer Jan 11 '13 at 11:04
  • Ok, about **[...] is never allowed to be in an invalid [...]**. But I'm trying to show that this can be acquired using AOP or even Design-by-Contract approaches. – Matías Fidemraizer Jan 11 '13 at 11:05
  • About why forcing DDD upon simple CRUD, well this is your conclusion about my sample code. I just wanted to make a small touch of what I'm asking for. I know that DDD isn't CRUD. The repository pattern is the responsible of translating the domain into what the underlying storage understands and can store. – Matías Fidemraizer Jan 11 '13 at 11:09
  • @MatíasFidemraizer concerning your second comment: Maybe, I never tried. I'm not sure if AOP is a good fit when creating a Domain Model along the lines of DDD. AOP can be very helpful when it comes to other parts of your application (like CRUDy BCs, UI, Application Services, etc.) But for a DDD-based Domain Model I'd rather make invariant enforcement and behavior of Aggregates an explicit part thereof. – Dennis Traub Jan 11 '13 at 11:11
  • That's it. In my case, I'm using this approach in many projects and it works flawlessly. You get the best benefit of AOP: you concentrate your effort in writing the whole business and the code is more clear, so the business validation and other things are bound to the domain object declaratively or by configuration. It makes a lot of things simpler with the known drawback of hiding a lot of details that are harder to understand by someone with less abstraction skills. – Matías Fidemraizer Jan 11 '13 at 11:14
  • At the end of the day, this is why I'm asking if _this is an anemic domain model_ pattern. In my opinion, I don't think so. – Matías Fidemraizer Jan 11 '13 at 11:16
  • @MatíasFidemraizer I don't think there is such a thing as an anemic domain model *pattern*. A domain model can be considered anemic if the business objects are mainly data containers and depend on lots of services to coordinate and enforce behavior upon them. I don't think the *anemicness* of a model is a function of the excact technology you use to enforce the aggregate's consistency. – Dennis Traub Jan 11 '13 at 11:23
  • Yeah, you're right. Again, I just wanted to show an example with business validation. In my case, my domain objects don't have methods. If I want to add some user to some group I would get the user instance and access to a collection of groups and add there a new instance of group. The domain transaction, usually handled by the OR/M (so your persistent domain object will be a proxy) will handle for me the persistence of the group. I find this more "object-oriented". I've an user which has N groups. I just add a group (continues in the next comment...) – Matías Fidemraizer Jan 11 '13 at 11:27
  • (...continuation). For me, the fact that the object is "persistent" it's more an infrastructure detail rather than something about the domain itself, so I don't care if the group will be persisted or not: I just complete the transaction. – Matías Fidemraizer Jan 11 '13 at 11:28
  • @MatíasFidemraizer what you say sounds reasonable to me. Also an "anemic domain" is not a bad thing in itself. If the domain is not highly behavioral, then there's no need to force anything. – Dennis Traub Jan 11 '13 at 11:53
  • 100% agreed. And I believe, like you, that _anemic domain_ it's not always an anti-pattern. I like your answer, let's wait for other opinions, but I liked your opinion (which isn't a synonym of "we're right", but at the end of the day, everything is subjective haha) – Matías Fidemraizer Jan 11 '13 at 11:58
1

My opinion is it's true that aspect-oriented programming has the drawback of hiding a lot of details in the main flow of the domain (or any other layer)

IMO, this is the central problem of using such AOP approaches in DDD - it hides details. Now, for strictly technical domains, such as logging, this is often desirable. AOP works well for such domains because it is, in a sense, a characteristic of a technical domain itself - an extension to traditional OOP composition. DDD on the other hand targets non-technical domains - business use cases. As such, one of the goals of DDD is the distillation of domain knowledge freeing it from technical concerns as much as possible. A step toward achieving with OOP is clustering data and behavior together inside objects. Another step is moving away from technical names for behaviors to more business specific names for behaviors. This allows you to capture the surrounding business context associated with behaviors, not just the technical context.

What would be helpful for DDD is a new set of abstractions. Not a needless layer of complexity, but something that creates new semantics. As Dijkstra stated, abstractions should create new semantic levels. This can come in the form of a DSL that allows expression of domain knowledge agnostic of technical concerns. The application would then attach this DSL expressed domain to infrastructure - persistence, UI, services, etc. Creating such DSL that is both expressive and readily "attachable" is a big challenge.

To answer your question, yes your object model is itself anemic even though it is composed with richer behaviors through aspects. However, this only addresses your object model and whether an object model is anemic or not is only part of the puzzle - the object model is a tactical pattern not a strategic one.

Your goal seems to be headed in the right direction - you wish to elevate the level of abstraction beyond facilities provided by OOP alone. I just think that the drawbacks of AOP outweigh the benefits in the DDD case.

eulerfx
  • 36,769
  • 7
  • 61
  • 83