Architecture & System Design › Domain-Driven Design
Domain Service
Domain logic that doesn't belong to any one entity.
Also known as: domain service, domain services, DDD service
A Domain Service holds domain logic that fits no single entity or value: multi-entity operations (transfer between accounts), calculations spanning concepts (pricing across catalogue and promotions), and policies over collections. Stateless, side-effect-free, named from the language — services for behaviour homeless elsewhere, not dumping grounds.
entity logic: order.ship() (owns its transition)
domain service: PricingService.quote(cart, customer) (spans concepts, no home)
Services complement entities (which own their invariants) and application services (which orchestrate use cases, infrastructure and transactions). The three levels keep responsibilities crisp: entities decide for themselves, domain services compute across, application services coordinate with the outside.
The classic mistakes:
- Everything-service (anemia). Logic that belongs on entities migrating to services hollows the model. Entities first; services for the genuinely homeless.
- Stateful services. Conversational state in “services” recreates stateful session bugs. Domain services stateless; state lives in entities and callers.
- Infrastructure in domain services. Database calls, HTTP clients and queue publishes belong in application/infrastructure layers. Domain services compute purely.
- Application logic masquerading. Orchestration (load, call, save, publish) labelled “domain” drags infrastructure into the model. Orchestrate outside; compute inside.
- Static-method dumping grounds. Util classes accumulating unrelated functions signal missing concepts (entities, values) more than service needs. Find the homes first.
- Services calling servicesin chains. Deep service-to-service cascades obscure flow and duplicate orchestration. Coordinate in application services; keep domain services leaf-level.
- Naming from implementation.
OrderManager,PaymentUtil,CommonServicedescribe nothing domain-meaningful. Name from the language (PricingService,RiskAssessor).
How to place logic: entity-owned first, domain service for cross-concept computation, application service for orchestration. Services fill gaps in the model — they don’t substitute for one.