Backend · Architecture ·
[DDD Start 실전] 주문-결제 시스템 설계 및 테스트
🚀 DDD Start 실전: 주문-결제 시스템 예제 #
이번 글에서는 DDD Start를 기반으로 실제 주문(Order) - 결제(Payment) 시스템을 설계하고,
테스트 케이스까지 포함한 실전 예제를 다룹니다.
DDD 입문자뿐만 아니라 실무 개발자에게도 바로 적용 가능한 가이드입니다.
1️⃣ 단계별 DDD Start 요약 #
| 단계 | 설명 | 예제 적용 |
|---|---|---|
| 🟢 도메인 언어 정리 | 개발자 + 도메인 전문가가 같은 용어 사용 | Order, Customer, Product, Payment |
| 🟡 도메인 분리 | 핵심(Core) / 지원(Supporting) / 범용(Generic) | Core: Order, Supporting: Payment, Generic: Logging |
| 🔵 Bounded Context 정의 | 각 컨텍스트별 책임 정의 | 주문 Context, 결제 Context, 배송 Context |
| 🟣 모델링 | 엔티티, 값 객체, 도메인 서비스 설계 | Order, OrderItem, PaymentService 등 |
| 🟠 구현 | 도메인 중심 구조 기반 코드 작성 | src/domain/… 구조로 구현, 테스트 포함 |
2️⃣ 도메인 모델링 #
2.1 Order 엔티티 #
1public class Order {
2 private final OrderId id;
3 private final Customer customer;
4 private final List<OrderItem> items = new ArrayList<>();
5 private OrderStatus status = OrderStatus.PENDING;
6
7 public Order(OrderId id, Customer customer) {
8 this.id = id;
9 this.customer = customer;
10 }
11
12 public void addItem(Product product, int quantity) {
13 items.add(new OrderItem(product, quantity));
14 }
15
16 public void confirm() {
17 if (items.isEmpty()) throw new IllegalStateException("주문 아이템이 없습니다.");
18 status = OrderStatus.CONFIRMED;
19 }
20
21 public OrderStatus getStatus() {
22 return status;
23 }
24}2.2 값 객체(Value Object) #
1public class OrderItem {
2 private final Product product;
3 private final int quantity;
4
5 public OrderItem(Product product, int quantity) {
6 this.product = product;
7 this.quantity = quantity;
8 }
9}2.3 도메인 서비스 #
1public class PaymentService {
2 public PaymentResult pay(Order order, PaymentMethod method) {
3 if (order.getStatus() != OrderStatus.CONFIRMED) {
4 throw new IllegalStateException("결제 전 주문만 결제 가능합니다.");
5 }
6 return new PaymentResult(order.getId(), true);
7 }
8}3️⃣ 코드 구조 예시 #
src/
├── domain/
│ ├── order/
│ │ ├── Order.java
│ │ ├── OrderItem.java
│ │ └── OrderStatus.java
│ ├── payment/
│ │ ├── PaymentService.java
│ │ └── PaymentResult.java
│ └── customer/
│ └── Customer.java
├── application/
│ └── OrderApplicationService.java
└── infrastructure/
├── repository/
└── external/📌 핵심: 도메인 중심 구조 유지, 테스트와 애플리케이션 로직은 분리
4️⃣ 테스트 케이스 예제 #
1import org.junit.jupiter.api.Test;
2import static org.junit.jupiter.api.Assertions.*;
3
4class OrderTest {
5
6 @Test
7 void 주문_생성_및_확인() {
8 Customer customer = new Customer("홍길동");
9 Order order = new Order(new OrderId("1"), customer);
10 order.addItem(new Product("상품A"), 2);
11
12 order.confirm();
13 assertEquals(OrderStatus.CONFIRMED, order.getStatus());
14 }
15
16 @Test
17 void 결제_실패_주문_미확인() {
18 Customer customer = new Customer("홍길동");
19 Order order = new Order(new OrderId("2"), customer);
20 PaymentService paymentService = new PaymentService();
21
22 Exception exception = assertThrows(IllegalStateException.class, () -> {
23 paymentService.pay(order, PaymentMethod.CARD);
24 });
25
26 assertEquals("결제 전 주문만 결제 가능합니다.", exception.getMessage());
27 }
28}5️⃣ 실무 팁 #
- 📝 작게 시작: 핵심 도메인부터 Aggregate 정의
- 📝 Bounded Context 유지: Context 간 책임 명확히
- 📝 Ubiquitous Language: 팀 공통 용어로 설계
- 📝 테스트 기반 개발: 도메인 로직부터 검증
- 📝 점진적 확장: 결제, 배송, 할인 등 기능은 후속 확장
6️⃣ 요약 #
- DDD Start = 도메인 주도 설계 시작 단계 프로세스
- 실전 적용: 작은 핵심 도메인 모델링 → Bounded Context → 서비스 구현 → 테스트
- 목표: 도메인 중심 설계로 확장 가능하고 유지보수 쉬운 코드 구조 확보
💡 결론: DDD Start는 단순 설계 철학이 아니라, 실무에서 바로 적용 가능한 도메인 중심 설계 가이드입니다.
Advertisement