반응형
1️⃣ 서비스란 무엇인가?
스프링에서 흔히 말하는 "서비스 클래스"는 비즈니스 로직을 담는 계층으로 알려져 있지만,
실제로는 역할에 따라 두 가지 종류로 나뉨.
- 도메인 서비스: 비즈니스 규칙의 핵심 로직 담당
- 애플리케이션 서비스: 로직을 조합하고 실행 흐름을 관리
이 둘을 구분하지 않으면,
서비스는 점점 비대해지고 결국 "모든 걸 하는 슈퍼 클래스"가 되어버림.
2️⃣ 도메인 (Domain) — “비즈니스의 중심 객체”
도메인은 주문, 결제, 배송, 상품 같은
비즈니스의 핵심 개념을 직접 표현하는 객체.
즉, 실세계의 규칙과 제약이 녹아 있는 코드.
@Entity
public class Order {
private OrderStatus status;
private Money totalPrice;
public void complete() {
if (status != OrderStatus.PENDING) {
throw new IllegalStateException("이미 완료된 주문입니다.");
}
this.status = OrderStatus.COMPLETED;
}
public boolean canCancel() {
return status == OrderStatus.PENDING;
}
}
✅ 특징
- 스스로 상태를 관리.
- 자신의 규칙을 스스로 지킴.
- 외부 로직이 아니라 "객체 내부"에서 일관성을 유지함.
⚠️ 나쁜 예시
order.setStatus(OrderStatus.COMPLETED); // ❌ 도메인 무력화
3️⃣ 도메인 서비스 (Domain Service) — “여러 도메인의 협업 로직 담당”
도메인 서비스는 "비즈니스 규칙"이 여러 도메인에 걸쳐 있을 때 등장함.
즉, 하나의 엔티티가 담당하기에는 부자연스러운 로직을 외부로 분리한 것.
@Service
public class DiscountPolicyService {
public Money calculateDiscount(Order order, Customer customer) {
if (customer.isVip()) {
return order.getTotalPrice().multiply(0.1);
}
return Money.ZERO;
}
}
✅ 특징
- 비즈니스 규칙이지만 "상태"는 없음.
- 도메인 객체 간 협력 조정자 역할
- 단일 도메인에 넣기 어려운 로직을 분리
⚠️ 주의
- DB 트랜잭션, 외부 API 호출, 흐름 제어는 여기에 넣지 말 것
- 도메인 서비스는 비즈니스의 룰만 다뤄야 함.
4️⃣ 애플리케이션 서비스 (Application Service) — “흐름과 트랜잭션 관리자”
애플리케이션 서비스는 "비즈니스 절차"를 조합하고 실행하는 상위 계층.
즉, 유즈케이스 단위로 동작을 관리하는 오케스트레이터.
@Service
@RequiredArgsConstructor
public class OrderApplicationService {
private final OrderRepository orderRepository;
private final DiscountPolicyService discountService;
private final PaymentService paymentService;
@Transactional
public void completeOrder(Long orderId, Long customerId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(OrderNotFoundException::new);
Customer customer = findCustomer(customerId);
Money discount = discountService.calculateDiscount(order, customer);
order.applyDiscount(discount);
order.complete();
paymentService.pay(order);
}
}
✅ 특징
- 트랜잭션 경계(@Transactional)를 관리.
- 도메인 서비스와 엔티티를 조합해 유즈케이스를 완성.
- 외부 시스템 호출, 이벤트 발행 등 조정 역할 수행.
⚠️ 주의
- 비즈니스 로직을 직접 구현하지 말 것.
- 단순히 "흐름을 조립"하는 역할에 집중.
5️⃣ 세 가지의 차이점 정리
| 분류 | 역할 | 주요 행동 | 예시 |
| 도메인 | 비즈니스 로직 처리 | - 도메인 역할을 수행 - 다른 도메인과 협력 |
User, Product, Coupon |
| 도메인 서비스 | 비즈니스 "연산" 로직 처리 | - 도메인 협력을 중재 - 도메인 객체에 기술할 수 없는 연산 로직을 처리 |
PriceManager |
| 애플리케이션 서비스 | 애플리케이션 "연산" 로직 처리 | - 도메인을 저장소에서 불러옴 - 도메인 서비스를 실행 - 도메인을 실행 |
ProductManager |
반응형
'Java & Spring Boot' 카테고리의 다른 글
| 🧪 테스트 피라미드와 구글의 테스트 철학 (0) | 2025.12.10 |
|---|---|
| 🔄 순환 참조, 왜 생기고 어떻게 끊어야 할까 (0) | 2025.11.28 |
| 🧩 이펙티브 자바 item 56. 공개된 API 요소에는 항상 문서화 주석을 작성하라 (0) | 2025.10.24 |
| ⚙️ 이펙티브 자바 item 48. 스트림 병렬화는 주의해서 사용하라 (0) | 2025.10.22 |
| 🧩 이펙티브 자바 item 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라 (0) | 2025.10.21 |