우아한테크코스 - 애프터코스 1회차

주노·2022년 12월 8일
0
post-thumbnail

서론

코치와 수다타임에서 이전 기수의 프리코스 문제를 풀어보면 도움이 될거라는 말을 듣고 5시간동안 몰입해서 풀어보기로했다.

뭔가 프리코스라기엔 애매한 감이 있으니 애프터코스라고 하자. 주문하신 우테코 애프터 코스입니다...?

풀게된 문제는 미션 - 자판기 문제다.

자세한 서론은 우아한 테크코스 프리코스 후기에 작성했다.

본 내용은 5시간이라는 제한시간을 두고 허둥지둥 구상한 것을 정리한 내용입니다.
개인적으로 보고 반성하려고 작성한 내용이니 따끔한 피드백이 생각나신다면 그대로 키보드에 손을 올려 댓글로 작성해주시면 감사히 받겠습니다.

🚀 기능 요구사항

반환되는 동전이 최소한이 되는 자판기를 구현한다.

  • 자판기가 보유하고 있는 금액으로 동전을 무작위로 생성한다.
    • 투입 금액으로는 동전을 생성하지 않는다.
  • 잔돈을 돌려줄 때 현재 보유한 최소 개수의 동전으로 잔돈을 돌려준다.
  • 지폐를 잔돈으로 반환하는 경우는 없다고 가정한다.
  • 상품명, 가격, 수량을 입력하여 상품을 추가할 수 있다.
    • 상품 가격은 100원부터 시작하며, 10원으로 나누어떨어져야 한다.
  • 사용자가 투입한 금액으로 상품을 구매할 수 있다.
  • 남은 금액이 상품의 최저 가격보다 적거나, 모든 상품이 소진된 경우 바로 잔돈을 돌려준다.
  • 잔돈을 반환할 수 없는 경우 잔돈으로 반환할 수 있는 금액만 반환한다.
    • 반환되지 않은 금액은 자판기에 남는다.
  • 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 해당 부분부터 다시 입력을 받는다.
  • 아래의 프로그래밍 실행 결과 예시와 동일하게 입력과 출력이 이루어져야 한다.

우선 해당 요구사항을 순차적으로 정렬하고 각각의 역할에 따라 분배할 필요가 있다.

자판기 생각하기

지하철에서 한번쯤은 봤을법한 자판기가 생각났다.
수리기사 아저씨가 자판기를 열고 내부를 수리하는 모습이 떠올랐고, 그때 본 자판기의 동전투입구 부분을 생각하며 자판기 내부에서 일어나는 일들을 생각했다.

다음과 같은 시나리오가 머리에서 떠올랐다.

시나리오

수리기사 아저씨가 잔돈반환기에 잔돈을 넣었다.
이후 수리기사 아저씨는 물품을 채워넣고 자판기 문을 닫았다.

천원짜리 지폐 두장을 들고있던 어린 아이가 음료수를 사려고 자판기에 돈을 넣는다.

물품을 사기위해 버튼을 누르자 칠성사이다 하나가 땡그랑 떨어진다.
그래도 자판기의 불이 계속 들어와있어 아무거나 눌렀는데 비락식혜가 나왔다.

이제 넣은 돈으로는 더이상 살수있는 물품이 없었기 때문에, 자판기가 잔돈을 짤랑짤랑 내뱉었다.


👨‍🔧 수리기사 아저씨의 행동

정확히 일치하지는 않지만 수리기사 아저씨의 행동으로부터 다음과 같은 요구사항들을 도출할 수 있다.

  • 아저씨가 물품을 채워넣었다.
    - 상품명, 가격, 수량을 입력하여 상품을 추가할 수 있다.

  • 😎 안보이는 부분
    - 상품 가격은 100원부터 시작하며, 10원으로 나누어떨어져야 한다.

  • 수리기사 아저씨가 처음에 자판기에 잔돈을 넣었다.
    - 자판기가 보유하고 있는 금액으로 동전을 무작위로 생성한다.

  • 😎 안보이는 부분
    - 투입 금액으로는 동전을 생성하지 않는다.

🙋 아이의 행동

마찬가지로 아이의 행동으로부터 다음과 같은 요구사항들을 도출할 수 있다.

  • 아이가 음료수를 사기 위해 자판기에 2천원을 넣었다.
    - 사용자가 투입한 금액으로 상품을 구매할 수 있다.

자판기의 행동

자판기의 행동으로부터 다음과 같은 요구사항들을 도출할 수 있다.

  • 잔돈을 내뱉었다.
    - 남은 금액이 상품의 최저 가격보다 적거나, 모든 상품이 소진된 경우 바로 잔돈을 돌려준다.

  • 😎 안보이는 일들
    - 잔돈을 돌려줄 때 현재 보유한 최소 개수의 동전으로 잔돈을 돌려준다.
    - 지폐를 잔돈으로 반환하는 경우는 없다고 가정한다.
    - 잔돈을 반환할 수 없는 경우 잔돈으로 반환할 수 있는 금액만 반환한다.
    - 반환되지 않은 금액은 자판기에 남는다.

😎 안보이는 일들?
안보이는 일들은 다른 객체들이 서로 상호작용할 때 굳이 알필요 없는 일들로 객체 설계간 private method로 둘 수 있을것이라 예상 할 수 있다.

객체 구성하기

시나리오 상으로는 다음과 같이 객체를 나눠볼 수 있었다.
자판기를 관리하는 사람, 물건을 사는 사람, 자판기

하지만 우리는 자판기의 기능을 중점으로 구현을 진행할 것이므로 자판기의 관점으로 다시 살펴보자.
잔돈 관리부, 물품 관리부, 중앙 관리부

객체지향의 객자도 모르는 초보가 짧은 안목으로 나눈 기준입니다.
피드백은 언제나 환영입니다. 🙇‍♂️

💰 잔돈 - Change

잔돈을 관리하는 객체로 다음과 같은 상태와 행동을 가진다.

상태

  • 현재 가지고있는 동전별 개수

기능

  • 현재 가지고있는 총량
  • 특정 금액을 기준으로 동전의 양 반환

📦 물품 - Product

상품을 나타내는 객체로 다음과 같은 상태와 행동을 가진다.

상태

  • 이름
  • 가격
  • 개수

행동

  • 소비 (개수가 한개 줄어든다)

Inventory

물품(Product) 리스트를 모아서 관리하는 일급 컬렉션이다.

⚙️ 자판기 - Machine

자판기를 나타내는 객체로 다음과 같은 상태와 행동을 가진다.

상태

  • 현재 남은 투입금액
  • 잔돈 (Change 객체)
  • 물품 창고 (Inventory 객체)

행동

  • 잔돈넣기 (생성자)
  • 구매금액 투입하기
  • 물품 넣기
  • 물품 구매하기
  • 잔돈 반환하기
    • 저장된 금액
    • 남은 금액을 기준으로 반환
  • 소진상태 알려주기

자판기가 너무 많은 역할을 가지는것 같은데... 뭔가 더 나누면 이해하기가 더 힘들거같아서 섣불리 분리하지는 않았다.

🛠️ 리팩토링

위에서 정의한 객체들에 대한 테스트를 먼저 작성하면서 개발을 진행하려고 노력했지만...
중간중간 시간에 쫒겨 기능을 먼저 만들어 이상적인 TDD를 하지 못했다.

위와같은 설계가 착착착 빠르게 하면 도움이 될텐데... 설계하는 연습을 좀 해야겠다.

Test Coverage

프리코스를하면서 IntelliJ에 coverage를 확인할 수 있는 기능을 알게되어 Test Coverage를 100%로 맞추도록 리팩토링을 진행했다.

(테스트하지 않는 함수가 없도록 만든다는 소리다)

IntelliJ에서 Test Coverage를 확인하는 방법은 다음과 같다.

  • test 폴더 우클릭 -> More Run/Debug -> Run 'Tests in '~~' with Coverage 클릭

코드 커버리지에 대해 더 알고싶다면?

TDD를 제대로 했다면 더 나은 Coverage를 기대할 수 있겠지...

읽기쉬운 코드

우테코를 하면서 바뀐 관점이지만 읽기 쉬운 코드를 작성하려고 최대한 노력중이다.
주로 신경쓰는 내용으로는 다음과 같은 내용들이 있다.

  • 의미있는 클래스/메소드/변수 네이밍
  • 최소한의 인자를 가지는 함수
  • 10줄이내의 메소드
  • 함수의 세로 응집도
  • 약간의(?) MVC 패턴

그 외에도 클린코드의 많은 내용들을 따르려고 노력은 하고 있으나 모두 지키기엔 아직 부족한것 같다 😅

후기

5시간이라는 시간동안 최대한 구현해보려했으나 InputView, OutputView만 남겨놓은채로 시간내에 Application Test를 통과하는 코드를 작성하지못했다.

명확한 설계를 내지못한 탓에 요구사항을 여러번 반복해서 보는 시간에 1시간가량을 소비했다.
설계가 부족한 것이 시간 부족의 가장 큰 요인이라고 생각한다.

요구사항을 보다 명확하고 빠르게 분석할 수 있도록 flowchart를 작성하거나 요구사항을 역할에 따라 분리하는 연습을 중점적으로 해봐야겠다.


추가로 앞으로 자판기에는 현금을 넣고싶지 않을거같다... 카드 찍어서 사야징

profile
안녕하세요 😆

2개의 댓글

comment-user-thumbnail
2022년 12월 9일

잘 보고 갑니다 ㅎㅎ..

1개의 답글