재고 차감, 검증은 몇 번 해야 할까?
TL;DR: 주문 생성 시 재고 검증과 차감이 중복·분산돼 혼란스러웠다. 검증을 한 곳에 명확히 두고, 메서드 호출 방식을 통일하는 게 핵심임을 배웠다.
문제 발견
주문 생성 로직을 구현하다 보니 재고 처리 방식이 어색했다.
// Order.create()
product.validateStock(quantity) // 검증
OrderItem.of(product, quantity)
// OrderService.createOrder()
order.items.forEach {
it.product.decreaseStock(it.quantity) // 차감만
}
- Order 생성 시 검증
- OrderService에서 차감 → 검증을 두 번? 한 번? 헷갈렸다.
Product에 메서드가 3개나…
fun validateStock(quantity: Quantity) { ... } // 검증만
fun decreaseStock(quantity: Quantity) { ... } // 차감만 (VO 내부 검증)
fun decreaseStockWithValidation(quantity: Quantity) { ... } // 검증+차감
"어느 걸 써야 정답이지?" → 일관성 없는 설계의 신호
원인
- decreaseStock()은 재사용성을 위해 검증 없이 설계
- Stock VO 내부에도 검증 존재 → 검증이 두 곳에 중복
- 에러 메시지에 상품명을 넣고 싶어 Product에도 검증 추가
선택지
방식 설명 장점 단점
| 1. 검증+차감 통합 | decreaseStock()이 항상 검증 | 호출 측 부담 ↓ | VO 검증 중복 |
| 2. VO 검증만 믿기 | 엔티티 검증 제거 | 중복 없음 | 에러 메시지 제한 |
내가 선택한 방식: 2번 + 타협
// Product.kt
fun decreaseStock(quantity: Quantity) {
stock = stock.decrease(quantity.value) // VO가 검증
}
fun validateStock(quantity: Quantity) { // 상품명 포함 에러용
if (!hasEnoughStock(quantity)) {
throw CoreException(ErrorType.INSUFFICIENT_STOCK,
"재고 부족. 상품: $name (요청: ${quantity.value})")
}
}
- Order.create() → validateStock() (구체적 에러)
- OrderService → decreaseStock() (VO 검증 위임)
여전히 불편한 점
- validateStock()이 public이라 오용 가능성
- 검증 후 차감 사이 동시성 문제 (트랜잭션/락 필요)
- 메서드 2개 → 여전히 많음
배운 점
- 검증은 한 곳에 명확히 (VO or 엔티티)
- 메서드 많으면 설계 의심
- 일관성 > 완벽함
다음엔 이렇게
fun decreaseStock(quantity: Quantity) {
if (!hasEnoughStock(quantity)) {
throw CoreException(ErrorType.INSUFFICIENT_STOCK,
"재고 부족. 상품: $name (요청: ${quantity.value}, 재고: ${stock.quantity})")
}
stock = stock.decrease(quantity.value)
}
메서드 하나, 검증+차감+에러 메시지 통일
재고 차감은 단순해 보이지만, "누가 검증할까? 몇 번 할까? 어떻게 일관되게 할까?" 이 고민이 좋은 설계를 만든다.
다음엔 더 간결하게!
'Loopers 2기' 카테고리의 다른 글
| 쿠폰 중복 사용 버그, 비관적 락 한 줄로 해결하기 (0) | 2025.11.21 |
|---|---|
| Round 2 회고 (0) | 2025.11.07 |
| Round 1 회고 (0) | 2025.10.31 |