Designing Clean Application Services in DDD: Principles & Best Practices
This article explains how application services act as a façade for domain models, outlines key design principles, shows practical Go/Java implementation patterns, discusses transaction propagation and security handling, and provides concrete best‑practice recommendations for building thin, framework‑agnostic backend services.
01 Positioning and Principles
In Domain‑Driven Design, an application service is the façade of the domain model. It simplifies external calls and prevents domain logic from leaking outside the model.
Key principles for building application services:
Each business method maps one use case.
Each method is wrapped in its own transaction.
The service does not contain business logic; input validation is performed by callers.
The service should not depend on specific frameworks or technical details.
Security concerns such as permission checks are better placed in cross‑cutting aspects or middleware.
02 Implementation of Application Service
From a layered architecture perspective, the application layer sits beside the domain layer. Create an application (or app) package parallel to domain and place one service struct per use case.
A typical service definition includes repository or domain‑service interfaces as fields, a constructor that receives the same types, and methods that implement the use cases.
Example (illustrated in the images):
Method parameters should follow these rules:
The first parameter is always context.Context to keep the service stateless.
When there are only one to three simple parameters, place them directly in the signature.
For more complex input, wrap the parameters in a DTO (Command/Query) that is immutable and contains no domain‑model objects.
Never expose domain entities or value objects as parameters; this would force callers to understand internal model details.
When an IDL (e.g., protobuf or Thrift) request matches the use case, it can be used directly, but the service should still avoid leaking domain types.
Return values follow a similar philosophy:
Simple results (e.g., an ID) can be returned as primitive types.
When multiple fields are needed, use a DTO that aggregates the data without containing domain objects.
A DPO (Domain Payload Object) can be used when the response must reference domain objects internally while keeping the fields private.
Directly returning domain entities is discouraged; instead, map the needed data into a DTO/DPO.
03 Transaction and Security
DDD recommends one transaction per business use case, which translates to one transaction per application‑service method. In Java this is often achieved with @Transactional. In Go, developers usually manage transactions manually (e.g., using Gorm’s Begin, Commit, Rollback).
To support transaction propagation in Go, a TransactionManager and a custom TransactionContext are introduced. The manager provides a Transaction method that creates or reuses a transaction based on the current context, enabling REQUIRED‑style propagation.
Security (authorization) should be handled outside the application service, typically in middleware or aspect layers, keeping the service focused on orchestration.
04 Conclusion
Application services provide a thin, framework‑agnostic layer that coordinates domain models without exposing their internals. Follow the principles and best‑practice checklist below to keep services clean and maintainable.
Never use domain models as method parameters or return types.
For ≤3 simple parameters, place them directly in the signature.
For complex input, use Command/Query DTOs.
For complex output, prefer DPO or DTO.
If an IDL request matches the use case, it can be used directly, but keep response assembly separate.
Wrap each use case in its own transaction and consider propagation needs.
Delegate authorization to middleware or aspects.
The next article will explore domain events and how they interact with application services.
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.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
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.
