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.

samdeepthink
samdeepthink
samdeepthink
When to Apply Domain Services in DDD: Finding the Right Place for Business Logic

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Anti-Corruption LayerDDDApplication ServiceDomain Services
samdeepthink
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.