Anemic Domain Model: Pros/Cons

With "Anemic Domain Model" being anti-pattern, why are there so many systems that implement this?

I think there are several reasons

1. Complexity of the system

In a simple system (which is almost all the examples and sample code you find on internet) if I want to implement:

Adding product to Order

I put this function on the Order

public void Order.AddOrderLine(Product product)
{
    OrderLines.Add(new OrderLine(product));
}

Nice and super object oriented.

Now let's say that I need to make sure that I need to validate that the product exists in inventory and throw exception if it doesn't.

I can't really put it on Order any longer, since I don't want my order to be dependent on Inventory, so now it needs to go on the service

public void OrderService.AddOrderLine(Order order, Product product)
{
    if (!InventoryService.Has(product)
       throw new AddProductException

    order.AddOrderLine(product);
}

I could also pass IInventoryService to Order.AddOrderLine, which is another option, but that still makes Order dependent on InventoryService.

There is still some functionality in Order.AddOrderLine, but usually it is limited to Order scope, while in my experience there is a lot more Business Logic out of Order scope.

When the system is more then just basic CRUD, you will end up with most of your logic in OrderService and very little in Order.

2. Developer's view of OOP

There are a lot of heated discussions on the internet about which logic should go on entities.

Something like

Order.Save

Should Order know how to save itself or not? Let's say we have repositories for that.

Now can Order add order lines? If I try to make sense of it using simple English, it doesn't really make sense either. User adds Product to Order, so should we do User.AddOrderLineToOrder()? That seems like overkill.

How about OrderService.AddOrderLine(). Now it kinda makes sense!

My understanding of OOP is that for encapsulation you put functions on classes where the function will need to access class's internal state. If I need to access Order.OrderLines collection, I put Order.AddOrderLine() on Order. This way class's internal state doesn't get exposed.

3. IoC Containers

Systems that use IoC containers are usually fully anemic.

It is because you can test your services/repositories which have interfaces, but can't test domain objects (easily), unless you put interfaces on all of them.

Since "IoC" is currently lauded as solution for all your programming problems, a lot of people blindly follow it and this way end up with Anemic Domain Models.

4. OOP is hard, procedural is easy

I have a bit of a "Curse of Knowledge" on this one, but I have discovered that for newer developers having DTOs and Services is a lot easier than Rich Domain.

Possibly it is because with Rich Domain it is more difficult to know on which classes to put the logic. When to create new classes? Which patterns to use? etc..

With stateless services you just slap it in the service with closest name.


The pros:

  • You can claim it's a domain model and brag to your developer friends and put it on your resume.
  • It's easy to generate automagically from database tables.
  • It maps to Data Transfer Objects surprisingly well.

The cons:

  • Your domain logic exists somewhere else, probably in a class full of class(static) methods. Or your GUI code. Or in multiple places, all with conflicting logic.
  • It's an anti-pattern, so other developers will ask if you understand the concepts of object oriented design.

Following this, there has been a thought in my head for a very long time now. It is my belief that the term "OOP" has taken on a meaning not truly intended for it. The anagram mean "object oriented programming", as we all well know. The focus of course is on the word "oriented". It isn't "OMP", meaning "object mandated programming". Both ADM and RDM are examples of OOP. They make use of object, properties, methods interfaces and so forth. However, there is a difference between ADM and RDM in how we choose to encapulate things. They are two different things. To say that ADM is bad OOP is not an accurate statement. Maybe we need different terms for vaious levels of encapsulation instead. In addition, I never liked the term anti-pattern. It is usually assigned to something by members of an opposing group. Both ADM and RDM are valid pattern, they simple have different goals in mind, and are intended to solve different business needs. Those of us who practice DDD should, at the very least, appreciate this, and not fall to the level of others by bashing those who choose to implement ADM. Just my thoughts.