What is the Anemic Domain Model Anti-Pattern?
Learn the Anemic Domain Model anti-pattern — why data-only entities miss the point of OOP, and how to build a rich domain model instead.
Expected Interview Answer
An Anemic Domain Model is an object design where domain classes contain only fields and getters/setters with no real behavior, while all the business logic that should operate on that data lives separately in service classes, breaking the OOP principle of keeping data and the behavior that acts on it together.
This typically emerges when a team designs entities as plain data holders (sometimes literally called DTOs or POJOs used as domain objects) and then writes a parallel set of service classes with names like OrderService or CustomerManager that pull the data out, manipulate it externally, and write it back. The domain objects end up as little more than structs with getters and setters, offering no protection against being placed in an invalid state and no discoverable behavior for a reader exploring the codebase. It is called "anemic" because it looks like a proper object model on the surface — classes, fields, encapsulation via getters/setters — but it is missing the actual substance of OOP: behavior colocated with the data it operates on. The fix is to move business logic that belongs to an entity back into that entity’s own methods, so the object can enforce its own invariants.
- Naming the pattern clarifies why logic keeps drifting into service classes
- Points directly at the fix: move behavior back onto the entity
- Improves invariant enforcement once objects own their own logic
- Makes domain rules discoverable by reading the entity itself
AI Mentor Explanation
Imagine a scorecard that only stores numbers — runs, balls faced, wickets — with absolutely no rules built in, so a separate external "rules committee" has to check every single update by hand to prevent an impossible score like negative runs. The scorecard itself can’t stop anyone from writing an invalid entry; it just holds data passively while all judgment lives elsewhere. A proper scorer, by contrast, would refuse an invalid entry on the spot because the validation logic lives with the scorekeeping itself. An anemic domain model is that passive scorecard: data with no built-in behavior, forcing every rule to live in a separate service instead of the object itself.
Step-by-Step Explanation
Step 1
Spot the symptom
Look for entity classes that are all fields, getters and setters, with zero real behavior.
Step 2
Find the misplaced logic
Locate the service classes that read and mutate that entity’s fields from the outside.
Step 3
Move behavior onto the entity
Turn setters into intention-revealing methods (e.g. withdraw() instead of setBalance()) that enforce invariants internally.
Step 4
Shrink the service to orchestration
Keep the service class only for cross-entity coordination, not single-entity business rules.
What Interviewer Expects
- A clear definition distinguishing anemic models from rich domain models
- Recognition that it is called "anemic" because it looks OOP but lacks colocated behavior
- A concrete example of moving a setter-driven rule into an intention-revealing method
- Awareness that some service-layer orchestration is still legitimate (not all logic must move)
Common Mistakes
- Claiming an anemic model is simply "using getters and setters," which is normal and fine in moderation
- Not identifying where the missing behavior should actually live
- Suggesting all logic must always be on the entity, ignoring legitimate cross-entity orchestration
- Confusing it with the God Object anti-pattern (opposite problem: too little vs. too much on one class)
Best Answer (HR Friendly)
“An Anemic Domain Model is when your data objects only hold fields and getters/setters, with no real behavior, and all the actual business rules live somewhere else in separate service classes. It looks object-oriented on the surface, but it’s missing the part where behavior lives with the data it operates on, so the fix is to move rules like validation back onto the object itself.”
Code Example
// Anti-pattern: anemic entity, all logic lives in an external service
class Account {
private double balance;
public double getBalance() { return balance; }
public void setBalance(double balance) { this.balance = balance; } // no validation
}
class AccountService {
void withdraw(Account account, double amount) {
if (amount > account.getBalance()) throw new IllegalStateException("Insufficient funds");
account.setBalance(account.getBalance() - amount); // logic lives outside the entity
}
}
// Refactored: rich domain model, entity enforces its own rules
class Account {
private double balance;
Account(double initial) {
if (initial < 0) throw new IllegalArgumentException();
this.balance = initial;
}
double getBalance() { return balance; }
void withdraw(double amount) {
if (amount <= 0 || amount > balance) throw new IllegalStateException("Insufficient funds");
balance -= amount; // rule enforced by the entity itself
}
}Follow-up Questions
- What is the difference between an anemic domain model and a rich domain model?
- Is it ever acceptable to keep some business logic in a service layer?
- How does the anemic domain model relate to encapsulation?
- How would you refactor a large service class full of setter-driven logic into a rich domain model?
MCQ Practice
1. An Anemic Domain Model is characterized by?
The defining trait is data-only entities with business logic pulled out into external service classes.
2. Why is it called "anemic"?
It superficially resembles good OOP design (classes, fields, getters/setters) but is missing real behavior.
3. The standard fix for an anemic domain model is?
Turning bare setters into methods that enforce the entity’s own rules is the standard remedy.
Flash Cards
Anemic Domain Model in one line? — Entities with only fields/getters/setters; logic lives in separate service classes.
Why "anemic"? — It looks OOP on the surface but lacks behavior colocated with its own data.
Standard fix? — Move invariant-enforcing logic back onto the entity as intention-revealing methods.
Is service-layer logic always wrong? — No — cross-entity orchestration is legitimate; single-entity rules should live on the entity.