DTOs & Boundaries
intermediate12 min readLesson 107 of 180
Behavior-carrying domain models vs presentation-shaped DTOs, and explicit mapping between them.
DTOs vs domain models
A domain model carries business behavior; a DTO (Data Transfer Object) is a plain data shuttle between layers:
// domain — knows the rules
public record Account(String id, int balanceCents) {
public Account withdraw(int amount) {
if (amount > balanceCents) throw new InsufficientFundsException();
return new Account(id, balanceCents - amount);
}
}
// DTO — crosses the layer boundary, no behavior
public record AccountView(String id, String balance) {}
Rules of thumb:
- internal layers pass domain objects; boundaries expose DTOs
- the mapping function is explicit (
toView(Account)) — never expose mutable domain internals by accident - DTO fields are presentation-shaped (
"1,234.00"), domain fields are computation-shaped (int cents)
Small apps can skip DTOs; the discipline matters when the API shape and the internal model want to evolve at different speeds.