Architecture & System Design › Domain-Driven Design
Anemic Domain Model
Domain objects with data but no behavior.
Also known as: anemic domain model, anemic model, data bag model
The Anemic Domain Model anti-pattern: domain objects as data bags (getters/setters, no behaviour) with all logic stranded in services, managers or transaction scripts. It looks object-oriented (classes everywhere) while thinking procedurally — the worst of both paradigms, and DDD’s most common failure mode.
anemic: order.getStatus(); orderService.ship(order); // logic homeless
rich: order.ship(); // invariant + transition owned by the model
Anemia creeps in through frameworks (ORM entities as DTOs), layering dogma (“no logic in entities”), and habit (procedural thinking in class clothing). The costs compound: invariants unenforceable (anyone mutates anything), logic duplicated across services, and the “model” documenting nothing about actual rules.
The classic mistakes:
- Setters for everything. Public mutation of every field makes invariants impossible — validation lives nowhere enforceable. Behaviour methods replacing setters, state changed only through operations.
- Service-per-entity.
OrderService,CustomerServicemirroring entities 1:1 signal logic extracted mechanically. Services coordinate across aggregates; entities own their rules. - Framework entities as domain. ORM classes with persistence concerns doubling as the model contaminateubiquitous language with infrastructure. Separate persistence from domain (or map explicitly).
- Validation elsewhere. Constraints checked in controllers, forms or services (each differently, each incompletely) instead of constructors and operations. Validate at the model’s edge, once.
- “Logic doesn’t belong in entities” dogma. Layering rules misread as behaviour bans. Behaviour belongs with the data it constrains — that’s encapsulation, not layering violation.
- Testing services instead of models. Logic in services needs mocking-heavy integration tests; behaviour in entities unit-tests trivially. Rich models test cheaply.
- Procedural comfort. Teams thinking in steps and scripts find rich modelling unnatural at first. Pair, review and refactor toward behaviour — it’s learned, not innate.
The cure: move behaviour next to the data it guards, replace setters with operations, validate in constructors, coordinate (not implement) in services. Objects with responsibilities, not records with accessors.