Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Techniques for dealing with anemic domain model

I've read some of the questions regarding anemic domain models and separation of concerns. What are the best techniques for performing/attaching domain logic on anemic domain objects? At my job, we have a pretty anemic model, and we're currently using "helper" classes to perform the database/business logic on the domain objects. For example:

public class Customer
{
    public string Name {get;set;}
    public string Address {get;set;}
}

public class Product
{
    public string Name {get;set;}
    public decimal Price {get;set;}
}

public class StoreHelper
{
    public void PurchaseProduct(Customer c, Product p)
    {
         // Lookup Customer and Product in db
         // Create records for purchase
         // etc.
    }
}

When the app needs to do a purchase, it would create the StoreHelper, and call the method on the domain objects. To me, it would make sense for the Customer/Product to know how to save itself to a repository, but you probably wouldn't want Save() methods on the domain objects. It would also make sense for a method like Customer.Purchase(Product), but that is putting domain logic on the entity.

Here are some techniques I've come across, not sure which are good/bad:

  1. Customer and Product inherit from an "Entity" class, which provides the basic CRUD operations in a generic fashion (using an ORM maybe).
    • Pros: Each data object would automatically get the CRUD operations, but are then tied to the database/ORM
    • Cons: This does not solve the problem of business operations on the objects, and also ties all domain objects to a base Entity that might not be appropriate
  2. Use helper classes to handle the CRUD operations and business logic
    • Does it make sense to have DAOs for the "pure database" operations, and separate business helpers for the more business-specific operations?
    • Is it better to use non-static or static helper classes for this?
    • Pros: domain objects are not tied to any database/business logic (completely anemic)
    • Cons: not very OO, not very natural to use helpers in application code (looks like C code)
  3. Use the Double Dispatch technique where the entity has methods to save to an arbitrary repository
    • Pros: better separation of concerns
    • Cons: entities have some extra logic attached (although it's decoupled)
  4. In C# 3.0, you could use extension methods to attach the CRUD/business methods to a domain object without touching it
    • Is this a valid approach? What are pros/cons?
  5. Other techniques?

What are the best techniques for handling this? I'm pretty new to DDD (I'm reading the Evans book - so maybe that will open my eyes)

like image 265
Andy White Avatar asked Mar 04 '09 07:03

Andy White


People also ask

What is an anemic domain model?

The Anemic domain model is a programming Anti-pattern where the domain objects contain little or no business logic like validations, calculations, rules, and so forth. The business logic is thus baked into the architecture of the program itself, making refactoring and maintenance more difficult and time-consuming.

Are Anemic Domain Models bad?

Why is Anemic Domain Model harmful? One could say that the Anemic Domain Model is not going along with Object-Oriented Design. The separation of logic into other class is just not correct in OOD approach. But it is not the primary reason why Anemic Domain Model is harmful.

What is rich domain model?

A Rich Domain Model is the technical part when applying DDD, it envolves the building blocks like Entity, Value Objects and Aggregate Root. The goal is to build a ubiquitous language between developers and stakeholders using the a vocabulary that describes the business rules.

How do you describe the domain model?

The domain model is a representation of meaningful real-world concepts pertinent to the domain that need to be modeled in software. The concepts include the data involved in the business and rules the business uses in relation to that data. A domain model leverages natural language of the domain.


3 Answers

In order to avoid anemic model, refactor your helper classes:

Logic like:
"Customer.PurchaseProduct(Product product, Payment payment)",
"Customer.KillCustomer(Person killer, Weapon weapon)"
should exist right into "Customer" domain object.

Logic like:
"Customer.IsCustomerAlive()"
"Customer.IsCustomerHappy()"
should go to specifications.

Logic like:
"Customer.Create()",
"Customer.Update()"
obviously should go to repositories.

Logic like:
"Customer.SerializeInXml()"
"Customer.GetSerializedCustomerSizeInBytes()"
should go to services.

Complex constructors should go to factories.

That's how i see it. I would be glad if someone could comment my understanding of DDD approach.


Edit:

Sometimes - anemic domain model shouldn't be avoided.

Edited my answer to add that DDD isn't about picking up and dropping patterns.
DDD is about way we think.

like image 81
Arnis Lapsa Avatar answered Sep 21 '22 16:09

Arnis Lapsa


Martin Fowler has written a lot about domain models, including anemic domain models. He also has brief descriptions (and UML class diagrams) of many design patterns for domain models and databases that might be helpful: Catalog of "Patterns of Enterprise Application Architecture".

I would suggest looking at the Active Record and Data Mapper patterns. From the description of your problem, it sounds like your helper classes contain both domain/business rules and database implementation details.

The Active Record would move the helper's domain logic and database code into the other domain objects (like your Entity base class). The Data Mapper would move the helper's domain logic into the domain objects and the database code into a separate map object. Either approach would be more object-oriented than procedural-style helper classes.

Eric Evans' "Domain Driven Design" book is excellent. It gets a bit dry, but is definitely worth it. InfoQ has a "Domain Driven Design Quickly" mini-book that is a good introduction to Evans' book. Plus "Domain Driven Design Quickly" is available as a free PDF.

like image 37
Chris Peterson Avatar answered Sep 22 '22 16:09

Chris Peterson


I've always thought of the anemic domain model as an anti pattern. It's clear that a customer will purchase products, that ability can be generised by an interface implementation

Interface IPurchase
      Purchase(Product);

, so a any of your domain objects can then implement that as required. In that way you can introduce functionality to your domain objects - which is exactly where it should be.

like image 30
MrTelly Avatar answered Sep 18 '22 16:09

MrTelly