start

  • command line start
./gradlew bootJar
java -jar build/libs/twentyninecm-0.0.1-SNAPSHOT.jar
  • IDE start

application을 실행시키면 콘솔에 명령어 설명창이 출력됩니다.
안내에 따라 주문을 진행하면 됩니다.

domain 구조

  • 실선 : 직접 참조
  • 점선 : 의존 관계

도메인구조

동시성 보장

현재 상품 재고 변화에 동시성을 보장하고 있습니다. 동시에 쓰레드에서 주문을 완료해 productstock을 변화시키려 할때 동시성 문제가 발생합니다. 동시성 문제를 보장하기 위해 먼저 stockAtomicInteger 타입으로 선언했습니다. AtomicIntegerstock의 값을 변화시킬때 할때 잠금을 걸어 다른 쓰레드에서는 동시에 수정하지 못하도록 합니다.

하지만, stockquantity 보다 적을때 예외 판단은 보장하지 못합니다.

예시) 만약 stock 이 10개이고 quantity 가 8개여서 if(stock < quantity) 조건에 걸리지 않아 stock 의 값을 변화시키려 합니다. 그런데 다른 쓰레드에서 stock 을 감소시켜 5개가 되었다면, stock 을 8개 감소시키면 5 - 8 = -3 이 됩니다. 그래서 reduceStock 메서드 자체를 syncronized 를 걸어 검증과 수정이 한쓰레드씩만 일어나도록 구현했습니다.

장바구니, 장바구니 상품 도메인을 만든 이유

상품을 선택하는 것과 주문 상품에 들어가는 것은 의미적인 차이가 있다고 생각했습니다. 고객이 상품을 담아두고 있다가, 주문을 할 때 주문상품에 들어가야 한다고 생각했습니다.

또한, 상품의 이름이나 가격이 변했을 때 주문상품에 있는 이름과 가격에는 반영이 되지 않아야 한다고 생각합니다. 극단적인 예시로 구매자가 상의를 구입했는데 판매자가 해당 상품을 하의로 바궈도 구매자의 구매목록에는 상의로 남아있어야 한다고 생각했습니다.

CartId

29CM 사이트를 보면 고객마다 상품을 담아두는 장바구니가 1개씩 기본적으로 존재합니다. 현재 과제에서는 고객을 한명으로 생각하기 때문에 장바구니 1개를 initialzer에서 미리 만들어 주었고, 이 ID를 하드코딩해서 사용했습니다. 추후 Member 객체가 생기게 된다면 그때 기본적으로 Member 마다 장바구니를 생성해주면 되도록 구현했습니다.

아쉬운점

트랜잭션을 지원하지 않음

트랜잭션을 지원하지 않습니다. 그래서 service 로직 실행중 중간에 예외가 발생한다면 rollback 이 되지 않습니다. DB를 연결하지 않아서 외부 소스에 영향을 받지 않아 예기치 않은 예외가 발생할 상황이 적다고 판단했습니다.

그럼에도 service 로직 수행중 예외가 발생하면 rollback 시키는 기능이 추가되어야 함은 인지하고 있습니다. 구현을 해야한다고 생각하면 자료구조를 쓰는 지금의 상황에서 트랜잭션을 직접 구현하는 비용보다 DB를 연동하게 될 때 Spring에서 제공하는 @Transactional 을 쓰는 것이 더 합리적이라고 생각합니다.

기능 요구사항

  • 상품을 생성한다.

    • 상품번호, 상품명, 판매가격, 재고수량
    • 예외
      • 판매가격이 음수
      • 재고수량이 음수
      • 동일한 상품번호로 등록
  • 장바구니에 장바구니 상품을 담는다.

    • 상품번호, 주문수량을 입력받는다.
    • 예외
      • CartProducts 가 null 이면 예외
      • List size가 0이면 예외
    • 장바구니 상품
      • 예외
        • quantity가 음수
        • price가 음수
  • 상품을 주문한다.

    • 한번에 여러개의 상품을 주문할 수 있다.
    • 반복적으로 계속 주문할 수 있다.
    • 주문 내역, 주문 금액, 결제 금액 (배송비 포함) 화면에 출력
    • 주문하면 장바구니를 비운다.
    • 예외
      • 주문시에 주문량보다 재고량이 작을경우 예외
      • 상품번호에 해당하는 상품이 없으면 예외
      • 주문 상품들이 null 이면 예외
      • 주문 상품들 size가 0이면 예외
      • 주문 상품 수량이 재고량보다 크면 (상품의 재고가 부족하면) SoldOutException
    • 주문 상품을 생성한다.
      • 장바구니로부터 장바구니 상품의 정보를 복사해 생성한다.
      • 예외
        • cartProductId가 null 이면 예외
        • 주문 수량이 음수
        • productId가 없으면
    • 주문 금액이 50,000원 이하일 경우 배송료 2,500 원 추가
  • 프로그램 컨트롤

    • 데이터 불러오기
    • o 입력시 상품 출력 (상품번호, 상품명, 판매가격, 재고수)
    • 주문하기
      • 상품번호 입력
      • 수량 입력
    • empty 입력 (space + ENTER) 이 되었을 경우 주문이 완료되고 결제
      • 주문 내역 출력
        • 상품 리스트
        • 주문 금액
        • 지불 금액 (주문 금액 + 배송비 - 2,500) - 주문 금액 5만원 이상시 배송비 면제
    • 다시 o, q 입력 가능 상태
    • q 또는 quit 입력시 프로그램 종료
    • 예외
      • 사용자 입력 잘못되면 예외
  • 추가 요구사항

  • 동시성 테스트

  • 동일한 상품 등록 예외

  • 패키지 정리

  • 가독성, 클린코드 확인