When to Apply Domain Services in DDD: Finding the Right Place for Business Logic
The article explains that domain services are not optional in DDD but become necessary when aggregate roots cannot contain certain business rules, such as those requiring external data, batch processing, or rules that don’t belong to a single aggregate, and outlines principles for their proper use.
In DDD projects you inevitably encounter logic that does not fit into an aggregate root, leading many to claim that domain services are optional and that the aggregate root can handle most business logic.
That view is wrong: an aggregate root is a closed computation unit that only maintains its own state and does not access the database or invoke external interfaces.
Real‑world business rules often need data from a database, other micro‑services, or external systems, so such responsibilities should not be placed inside the aggregate root.
Putting the logic into an application service works at the beginning of a project, but as the domain grows the application service becomes increasingly bloated, while the domain model becomes thin, causing DDD to degenerate back into a traditional three‑layer architecture.
Therefore, when an application service starts to shoulder many domain rules, the stable rules should be moved down to domain services, which are an inevitable layer once DDD is truly applied.
In the author’s experience, domain services typically handle three kinds of responsibilities: (1) domain calculations that depend on external data; (2) batch business rules that do not fit within an aggregate root; and (3) domain rules that cannot be assigned to any single aggregate root.
These responsibilities belong in the domain layer rather than the application layer.
A crucial principle is that domain services must not call each other; allowing mutual calls quickly turns the domain layer into a spider‑web of dependencies, indistinguishable from the Service layer of a traditional architecture.
Cross‑aggregate or cross‑module coordination should be delegated to application services, which handle process orchestration, while domain services focus solely on business rules.
Domain services can call other micro‑services, but only through an anti‑corruption layer: they should depend on gateway interfaces defined in the domain layer, with concrete implementations placed in the infrastructure layer, avoiding direct dependencies on RPC frameworks such as Dubbo or Feign.
In summary, domain services exist not to make DDD look more formal but to provide a proper home for logic that cannot fit into aggregate roots yet belongs to domain rules. The author adheres to two principles: domain services must exist, and they must not invoke each other. When application services become bloated and the domain model thin, it usually signals that domain services are needed.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
samdeepthink
Knowledge Planet: Old Dock's Tech Chronicles Zhihu: SamDeepThinking A technical manager who still codes heavily on the front line. From junior developer to tech lead, then tech manager, now leading the whole front‑ and back‑end development team—leveling up along the way. I have some insights on programming, career development, and tech management.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
