DTO
Boundary-shaped data carrier with no obligation to own domain behavior.
DTOs, entities, and value objects often look similar at first glance because they all hold data. Their design role is different. DTOs move data between boundaries. Entities carry identity and lifecycle. Value objects represent concepts defined by their attributes rather than by identity.
If an order request DTO starts acquiring domain behavior, or if a shipping address becomes a mutable entity without identity reason, the codebase loses modeling clarity fast. Keeping these object roles distinct improves architecture and makes refactoring safer.
DTOs are usually boundary-facing and shaped for serialization, requests, responses, or integration. Entities live in the domain or persistence model and carry identity across time. Value objects represent concepts such as money, address, or quantity and are usually best kept immutable. The more complex the domain becomes, the more valuable these distinctions are.
Boundary-shaped data carrier with no obligation to own domain behavior.
Identity-bearing object whose lifecycle matters across time.
Concept object defined by attributes and usually safest as immutable.
| Type | What defines it | Typical role |
|---|---|---|
| DTO | Boundary and transport needs | Requests, responses, external integration |
| Entity | Identity and lifecycle | Domain core objects such as Order or Customer |
| Value Object | Meaningful attributes | Money, Address, Quantity, TaxRate |
package org.javaomnibus.reference;
public record PlaceOrderRequest(String customerId, List<String> productIds) {}
public final class Order {
private final OrderId id;
private final List<OrderLine> lines;
public Order(OrderId id, List<OrderLine> lines) {
this.id = id;
this.lines = lines;
}
}
public record Money(BigDecimal amount, Currency currency) {}