I'm learning Domain-Driven Design (DDD) and studying different architecture patterns, and I’ve come across two seemingly conflicting design philosophies around domain modeling.
1. Rich Domain Model approach
In this approach, we:
- Encapsulate both state and behavior inside the domain model.
- Move validation and other domain-specific operations into the value objects and entities themselves.
- Keep domain services clean by containing only high-level business orchestration.
Example:
public class Money {
private final BigDecimal amount;
private final String currency;
public Money(BigDecimal amount, String currency) {
if (amount.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Amount cannot be negative");
}
this.amount = amount;
this.currency = currency;
}
public Money add(Money other) {
validateSameCurrency(other);
return new Money(this.amount.add(other.amount), this.currency);
}
private void validateSameCurrency(Money other) {
if (!this.currency.equals(other.currency)) {
throw new IllegalArgumentException("Currency mismatch");
}
}
}
This keeps logic closer to the data and improves readability and cohesion.
2. Anemic Domain Model approach (common in enterprise apps)
In practice, many teams (including mine) use plain POJOs for entities — they only hold state:
- Entities and value objects are data holders.
- Validation, transformations, and business logic live in service or utility classes.
This tends to make entities simpler to serialize, test, and use with frameworks like Spring/Hibernate, but can lead to “anemic” domain models that violate OO principles.
3. Functional Approach
On the other hand, Functional Programming (FP) promotes algebraic data types (ADTs) and pure functions to represent and transform domain data:
- Data is immutable.
- Logic is separate and expressed as functions over data.
This aligns more with the anemic model philosophy, but offers stronger guarantees via immutability and type safety.
My Question:
From a software architecture and clean code perspective — particularly in modern systems (Java/Spring, or even FP-influenced architectures):
- Should we design rich domain models that encapsulate validation within entities/value objects?
- Or is it better to keep entities as POJOs and centralize validation logic in service or function layers?