Domain Model Purity emphasizes separating representation from identity and keeping domain logic free from infrastructure concerns.
Separate Representation from Identity
- Is an
EmailAddressjust astring? No. - Is a
CustomerIdjust aninteger? No. Can you add twoCustomerIds together? No.
While CustomerId may be represented by an integer internally, in domain modeling we create wrapper types:
F# example:
type EmailAddress = EmailAddress of string
type PhoneNumber = PhoneNumber of string
type CustomerId = CustomerId of integerC# example:
public readonly struct Name
{
public Name(string value)
{
_value = value;
}
private readonly string _value;
public string Value => _value;
}Domain Logic Free from Infrastructure
Pure Domain
public class Order
{
public void Submit()
{
// Pure domain logic - no database, no email, no infrastructure
if (!_lines.Any())
throw new InvalidOperationException("Cannot submit empty order");
Status = OrderStatus.Submitted;
AddDomainEvent(new OrderSubmitted(Id));
}
}Infrastructure Concerns Separated
// Infrastructure layer
public class OrderRepository
{
public void Save(Order order)
{
_dbContext.SaveChanges(); // Database concern
}
}
public class OrderSubmittedHandler
{
public void Handle(OrderSubmitted @event)
{
_emailService.SendConfirmation(@event.CustomerId); // Email concern
}
}Key Considerations
- Domain model purity and the current time
- Domain model purity and lazy loading
- Separation of domain logic from infrastructure concerns
Related Concepts
- Value Objects - Wrapper types
- Entities - Pure domain objects
- Domain Driven Design - Overall pattern context