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:
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)
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.
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.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With