요구 사항
요구사항은 과제 진행 요구 사항, 기능 요구 사항, 프로그래밍 요구 사항 세 가지로 구성되어 있었다.
과제 진행 요구 사항
- 기능을 구현하기 전 README.md에 구현할 기능 목록을 정리해 추가한다.
- Git의 커밋 단위는 앞 단계에서 README.md에 정리한 기능 목록 단위로 추가한다.
- Angular JS Git Commit Message Conventons를 참고해 커밋 메시지를 작성한다.
기능 요구 사항
구매자의 할인 혜택과 재고 상황을 고려하여 최종 결제 금액을 계산하고 안내하는 결제 시스템을 구현한다.
- 사용자가 입력한 상품의 가격과 수량을 기반으로 최종 결제 금액을 계산한다.
- 총구매액은 상품별 가격과 수량을 곱하여 계산하며, 프로모션 및 멤버십 할인 정책을 반영하여 최종 결제 금액을 산출한다.
- 구매 내역과 산출한 금액 정보를 영수증으로 출력한다.
- 영수증 출력 후 추가 구매를 진행할지 또는 종료할지를 선택할 수 있다.
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다.
- Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리한다.
재고 관리
- 각 상품의 재고 수량을 고려하여 결제 가능 여부를 확인한다.
- 고객이 상품을 구매할 때마다, 결제된 수량만큼 해당 상품의 재고에서 차감하여 수량을 관리한다.
- 재고를 차감함으로써 시스템은 최신 재고 상태를 유지하며, 다음 고객이 구매할 때 정확한 재고 정보를 제공한다.
프로모션 할인
- 오늘 날짜가 프로모션 기간 내에 포함된 경우에만 할인을 적용한다.
- 프로모션은 N개 구매 시 1개 무료 증정(Buy N Get 1 Free)의 형태로 진행된다.
- 1+1 또는 2+1 프로모션이 각각 지정된 상품에 적용되며, 동일 상품에 여러 프로모션이 적용되지 않는다.
- 프로모션 혜택은 프로모션 재고 내에서만 적용할 수 있다.
- 프로모션 기간 중이라면 프로모션 재고를 우선적으로 차감하며, 프로모션 재고가 부족할 경우에는 일반 재고를 사용한다.
- 프로모션 적용이 가능한 상품에 대해 고객이 해당 수량보다 적게 가져온 경우, 필요한 수량을 추가로 가져오면 혜택을 받을 수 있음을 안내한다.
- 프로모션 재고가 부족하여 일부 수량을 프로모션 혜택 없이 결제해야 하는 경우, 일부 수량에 대해 정가로 결제하게 됨을 안내한다.
멤버십 할인
- 멤버십 회원은 프로모션 미적용 금액의 30%를 할인받는다.
- 프로모션 적용 후 남은 금액에 대해 멤버십 할인을 적용한다.
- 멤버십 할인의 최대 한도는 8,000원이다.
영수증 출력
- 영수증은 고객의 구매 내역과 할인을 요약하여 출력한다.
- 영수증 항목은 아래와 같다.
- 구매 상품 내역: 구매한 상품명, 수량, 가격
- 증정 상품 내역: 프로모션에 따라 무료로 제공된 증정 상품의 목록
- 금액 정보
- 총구매액: 구매한 상품의 총 수량과 총 금액
- 행사할인: 프로모션에 의해 할인된 금액
- 멤버십할인: 멤버십에 의해 추가로 할인된 금액
- 내실돈: 최종 결제 금액
- 영수증 항목은 아래와 같다.
- 영수증의 구성 요소를 보기 좋게 정렬하여 고객이 쉽게 금액과 수량을 확인할 수 있게 한다.
구현하기
음.... 이번 과제는 제대로 구현해내지 못했다.
내가 생각을 너무 깊게 한 것 같다. 우선 코드를 작성하기 전에 모든 예외 사항에 대해 생각하고 이건 어떤 객체의 책임일까, 객체를 어떻게 나누는게 맞을까... 등등 코드를 구현하기 보다는 고민을 하는 곳에 시간을 더 많이 쏟았다.
브랜치를 따로 파서 스파게티 코드라도 만들어보고 난 후에 main 브랜치에서 객체를 나누고 책임을 생각하고... 리팩토링을 했어야했다.
프로모션 기간 내에 포함된 경우가 아닐 때는 사용자에게 안내 후 구매할 것인지 Y/N으로 물어보는 게 좋겠지? 그런데 이러면 테스트 코드에 통과될려나? 입력을 처리할 때 `trim()`을 이용해서 좀 널널하게 통과되게 한다고 치면, `[물-2]` 이것뿐만 아니라 `[물 - 2]`도 통과되게 하는게 일관성을 가지고 처리하는 거겠지? 이걸 따로 객체로 빼는 게 좋을까? 그렇다고 하면 이 파일은 어디에 위치하는 게 적절할까? 구매할 때의 과정이 너무 길어서 `service` 계층에서 다 처리하는 건 좀 아닌 것 같은데 객체를 만들어야하나? 그럼 무슨 객체를 만드는 게 적절하지? 네이밍은 뭐가 적절하지?
위에처럼 하루 종일 고민했고, 코드를 짜기 전에 웬만한 것들은 다 정하고 들어가려고 했다. 3주차까지의 미션도 그래왔고, 별 문제 없이 끝냈기 때문에 이 방법이 괜찮다고 생각했었다. 하지만, 4주차는 이때까지와 달리 구현해야할 기능들이 좀 더 복잡했었다. 또 저번 주차를 끝내고 한 다짐이 이번 주차는 TDD를 완벽하게 해내자! 였고 그랬기에 객체에 대해 더 많이 생각을 했었다. 그게 문제였던 것 같다.
그외에도 한꺼번에 모든 기능을 구현하려고 했던 게 문제인 것 같다. 프로모션 적용 가능 상품에 대해 고객이 해당 수량만큼 가져오지 않았을 경우와 같은 예외 사항은 우선 미뤄두고, 기본 기능부터 구현한 후 차근차근 추가해 나갔어야했다...
아무튼... 마지막 주차에 제대로 구현하지 못한 게 너무 아쉬웠지만, 코드 리뷰를 통해 많은 것을 배워나갈 수 있었다. 이제 이때까지 배운 거를 정리해서 하나씩 올려야겠다!
'우아한테크코스' 카테고리의 다른 글
[우아한테크코스] 프리코스 3주차 코드 리뷰 후기 (0) | 2024.11.07 |
---|---|
[우아한테크코스] 프리코스 3주차 회고 (0) | 2024.11.06 |
[우아한테크코스] 프리코스 2주차 코드 리뷰 후기 (0) | 2024.10.31 |
[우아한테크코스] 프리코스 2주차 회고 (0) | 2024.10.31 |
[우아한테크코스] 프리코스 1주차 코드 리뷰 후기 (1) | 2024.10.30 |