Implementing Service Layer
1. Defining Service Responsibilities
| Responsibility | Detail |
|---|---|
| Use case orchestration | Coordinate domain + repos |
| Transaction boundary | Begin/commit per use case |
| Validation (cross-aggregate) | Beyond DTO format |
| Authorization checks | Method-level security |
| Event publishing | Domain events post-commit |
2. Implementing Service Interfaces
Example: Interface + impl
public interface OrderService {
Order place(PlaceOrderCommand cmd);
Order get(OrderId id);
}
@Service
public class DefaultOrderService implements OrderService { ... }
Note: Skip interface if there's only one impl and no proxy/AOP need — Spring proxies work on classes too (CGLIB).
3. Implementing Service Transaction Boundaries
| Rule | Detail |
|---|---|
| Boundary at use case | Service method = one transaction |
| No tx in controllers | Keep web layer thin |
| No tx in repos | Repository inherits ambient tx |
| Read-only flag | @Transactional(readOnly = true) |
4. Implementing Service Composition
Example: Compose services
@Service
public class CheckoutService {
private final OrderService orders;
private final PaymentService payments;
private final InventoryService inventory;
@Transactional
public CheckoutResult checkout(Cart cart) {
inventory.reserve(cart);
var order = orders.place(toCommand(cart));
var receipt = payments.capture(order, cart.payment());
return new CheckoutResult(order.id(), receipt.id());
}
}
5. Implementing Service Dependencies
| Direction | Allowed |
|---|---|
| Service → Repository | Yes |
| Service → Domain | Yes |
| Service → Service | Yes (acyclic) |
| Service → Controller | Never |
| Domain → Service | Never |
6. Implementing Service Error Handling
| Strategy | Detail |
|---|---|
| Throw domain exceptions | Translated by global handler |
| Result types | For expected outcomes |
| Wrap external errors | Don't leak vendor exceptions |
| Log with context | correlation ID, inputs (no PII) |
7. Implementing Service Input Validation
| Layer | Validates |
|---|---|
| Controller | Format (Bean Validation on DTO) |
| Service | Cross-field, cross-aggregate |
| Domain | Invariants in entity/value object |
8. Implementing Service Output Transformation
| Approach | Detail |
|---|---|
| Return domain | Map at controller boundary |
| Return DTO | Map inside service |
| Mapper component | Reusable, testable |
9. Designing Service Granularity
| Too coarse | Too fine |
|---|---|
| God service (everything) | One method per service |
| Hard to test | Wiring nightmare |
| Many actors | No abstraction |
Note: One service per use case family (e.g., OrderService) is typically the sweet spot.
10. Understanding Service vs Repository Separation
| Service | Repository |
|---|---|
| Business workflow | Persistence |
| Multiple repos/services | One aggregate |
| Tx boundary | Tx participant |
11. Implementing Application Services
| Trait | Detail |
|---|---|
| Layer | Application |
| Knows about | Use cases, transactions, security |
| Doesn't have | Business rules (those belong to domain) |
12. Implementing Domain Services
| Trait | Detail |
|---|---|
| Layer | Domain |
| Stateless | Pure business operations |
| Use when | Logic doesn't fit a single entity |