Kent Beck의 TDD 원칙에 따라 작은 단위부터 시작하여 점진적으로 구현합니다. 각 테스트는 Red → Green → Refactor 사이클을 따릅니다.
- [✅] 정액 할인 쿠폰이 상품 가격에서 할인 금액을 차감한다
- [✅] 정액 할인 금액이 상품 가격보다 크면 0원이 된다
- 정액 할인 적용 후 최종 금액은 음수가 될 수 없다
- 정률 할인 쿠폰이 상품 가격의 N%를 할인한다
- 정률 할인 시 원 단위 절사 처리를 한다
- 정률 할인에 최대 할인 금액 제한이 있으면 초과하지 않는다
- 100% 할인 쿠폰은 상품을 0원으로 만든다
- 최소 구매 금액 미달 시 쿠폰 적용이 불가능하다
- 최소 구매 금액을 정확히 충족하면 쿠폰 적용이 가능하다
- 최소 구매 수량 미달 시 쿠폰 적용이 불가능하다
- 할인 적용 전 금액 기준으로 최소 구매 조건을 검증한다
- 쿠폰은 고유한 쿠폰 코드를 가진다
- 쿠폰은 이름과 설명을 가진다
- 쿠폰은 유효 시작일시와 종료일시를 가진다
- 유효 기간 시작 전 쿠폰은 사용할 수 없다
- 유효 기간 내 쿠폰은 사용할 수 있다
- 유효 기간 만료 후 쿠폰은 사용할 수 없다
- 발급 후 N일 유효 쿠폰은 발급일 기준으로 만료일이 계산된다
- 쿠폰은 총 발급 가능 수량을 가진다
- 발급 가능 수량이 소진되면 추가 발급이 불가능하다
- 사용자당 발급 제한이 있으면 중복 발급이 불가능하다
- 이미 발급받은 쿠폰은 다시 발급할 수 없다
- 특정 상품 ID에만 적용되는 쿠폰을 생성할 수 있다
- 대상 상품이 아니면 쿠폰 적용이 불가능하다
- 대상 상품이면 쿠폰 적용이 가능하다
- 여러 상품 ID 중 하나라도 포함되면 쿠폰 적용이 가능하다
- 다중 상품 목록에 없는 상품은 쿠폰 적용이 불가능하다
- 특정 카테고리의 상품에만 쿠폰을 적용할 수 있다
- 하위 카테고리 포함 옵션이 켜져 있으면 하위 카테고리 상품도 적용된다
- 하위 카테고리 포함 옵션이 꺼져 있으면 정확히 일치하는 카테고리만 적용된다
- 특정 브랜드의 상품에만 쿠폰을 적용할 수 있다
- 브랜드가 일치하지 않으면 쿠폰 적용이 불가능하다
- 브랜드와 카테고리 조건을 AND로 결합할 수 있다
- 조합 조건을 모두 만족해야 쿠폰이 적용된다
- 쿠폰 1개로 동일 상품 여러 개에 할인을 적용할 수 있다
- 쿠폰 1개당 상품 1개만 할인하도록 제한할 수 있다
- 장바구니 총액에 정액 할인을 적용할 수 있다
- 장바구니 총액에 정률 할인을 적용할 수 있다
- 최소 주문 금액 미달 시 장바구니 쿠폰 적용이 불가능하다
- 장바구니 할인 금액이 상품 가격 비율에 따라 분배된다
- 분배 시 소수점은 원 단위로 절사된다
- 절사로 인한 나머지 금액은 가장 비싼 상품에 할당된다
- 분배된 할인 금액의 합은 총 할인 금액과 정확히 일치한다
- 특정 카테고리 상품만 장바구니 쿠폰 대상에 포함할 수 있다
- 제외 상품 목록에 있는 상품은 할인 계산에서 제외된다
- 필터링 후 남은 상품 금액이 최소 주문 금액 미달이면 적용 불가능하다
- 최소 주문 금액 계산 시 배송비는 제외된다
- 할인 금액 계산 시 배송비는 제외된다
- 하나의 주문에 하나의 쿠폰만 적용할 수 있다
- 여러 쿠폰을 동시에 적용하려고 하면 예외가 발생한다
- 사용자가 적용할 쿠폰을 명시적으로 선택할 수 있다
- 여러 쿠폰 중 할인 금액이 가장 큰 쿠폰을 자동 선택한다
- 정액 할인 금액이 같으면 먼저 만료되는 쿠폰을 선택한다
- 상품 쿠폰 적용 후 장바구니 쿠폰을 순차 적용할 수 있다
- 순차 적용 시 할인 순서를 명확히 정의한다
- 순차 적용 결과가 중복 불가 정책보다 유리한지 비교한다
- 사용자에게 쿠폰을 발급할 수 있다
- 발급된 쿠폰은 미사용 상태로 시작한다
- 이미 발급된 쿠폰은 다시 발급할 수 없다
- 발급 시 발급 일시가 기록된다
- 미사용 쿠폰을 사용 처리할 수 있다
- 사용된 쿠폰은 사용 일시가 기록된다
- 이미 사용된 쿠폰은 다시 사용할 수 없다
- 쿠폰 사용 시 주문 ID가 연결된다
- 사용자의 사용 가능한 쿠폰 목록을 조회할 수 있다
- 만료된 쿠폰은 사용 가능 목록에서 제외된다
- 이미 사용된 쿠폰은 사용 가능 목록에서 제외된다
- 주문 전체 취소 시 사용된 쿠폰이 복구된다
- 복구된 쿠폰은 미사용 상태로 변경된다
- 쿠폰 사용 이력은 감사 목적으로 유지된다
- 만료된 쿠폰의 유효기간 연장 정책을 적용할 수 있다
- 쿠폰이 적용된 상품만 취소 시 쿠폰이 복구된다
- 쿠폰이 적용되지 않은 상품만 취소 시 쿠폰은 유지된다
- 부분 취소 시 환불 금액이 정확히 계산된다
- 상품 부분 취소 시 해당 상품에 분배된 할인 금액이 환불된다
- 부분 취소 후 남은 금액이 최소 주문 금액 미달이어도 쿠폰은 유지된다
- 부분 취소 후 환불 금액과 남은 주문 금액의 합이 원래 금액과 일치한다
- 한정 수량 쿠폰의 동시 발급 요청을 올바르게 처리한다
- 발급 가능 수량을 초과하는 발급 요청은 실패한다
- 동시성 상황에서 중복 발급이 발생하지 않는다
- 동일 쿠폰의 동시 사용 요청은 하나만 성공한다
- 이미 사용 중인 쿠폰은 다른 주문에서 사용할 수 없다
- 장바구니 조회 시 적용 가능한 쿠폰 목록을 빠르게 제공한다
- 쿠폰 적용 미리보기 결과를 캐싱할 수 있다
- 캐시된 결과의 TTL이 적절하게 설정된다
- 사용자 쿠폰 조회 쿼리가 인덱스를 활용한다
- 쿠폰 사용 이력 조회 쿼리가 효율적으로 실행된다
- 새로운 쿠폰 정책을 생성할 수 있다
- 기존 쿠폰 정책을 수정할 수 있다
- 쿠폰 정책을 비활성화할 수 있다
- 쿠폰 정책 목록을 조회할 수 있다
- 쿠폰별 발급 수량을 조회할 수 있다
- 쿠폰별 사용률을 계산할 수 있다
- 기간별 쿠폰 사용 통계를 조회할 수 있다
- 관리자가 사용된 쿠폰을 수동으로 복구할 수 있다
- 관리자가 만료된 쿠폰의 유효기간을 연장할 수 있다
- 관리자가 특정 사용자에게 쿠폰을 직접 발급할 수 있다
TDD 원칙 준수:
- 각 테스트는 하나의 작은 기능만 검증합니다
- Red → Green → Refactor 사이클을 엄격히 따릅니다
- 테스트 이름은 "무엇을", "어떤 상황에서", "어떻게 동작하는지" 명확히 표현합니다
구현 순서:
- Phase 1-3: Domain 로직 (비즈니스 규칙, 외부 의존성 없음)
- Phase 4-7: Application 로직 (Use Case, 도메인 조합)
- Phase 8-9: Infrastructure 계층 (동시성, 성능, 영속성)
- Phase 10: 관리자 기능 (부가 기능)
리팩토링 타이밍:
- 중복 코드가 3번 이상 반복되면 즉시 추상화
- 메서드가 5줄 이상이면 Extract Method 검토
- 클래스가 200줄 이상이면 책임 분리 검토
Kent Beck의 조언:
"Make it work, make it right, make it fast." 먼저 동작하게 만들고, 그 다음 올바르게 만들고, 마지막에 빠르게 만들어라.