Coderoad

프리코스 4주 차를 돌아보며

2024-01-13 at 우아한테크코스 category

해당 미션은 private 저장소에 커밋하는 미션이었습니다. 따라서, 코드를 공개하지 않기로 결정했습니다.

프리코스 4주 차 미션 - 크리스마스 프로모션

이메일을 열어보고 마주한 4주 차 미션은 이전의 프리코스 미션들과 첫인상부터 완전히 달랐습니다. 이전에는 없었던 이미지를 활용한 길고 긴 요구사항들의 압박감과 private 저장소로 미션을 진행하고 제출해야하는 생소함에 미션 시작부터 막막해졌습니다.

요구사항 분석부터 난관이었다.

이번 미션의 요구사항은 이메일 형식으로 주어졌습니다. 지난 3주 간의 미션에서는 그래도 요구사항이 어느 정도 이해되고, 어떤 기능을 구현하고 어떻게 객체를 설계해야할지 감이 잡혔지만 이번 미션은 이 단계부터 많이 어려웠습니다. 요구사항을 열심히 읽어봐도 도대체 뭘 구현하길 원하는 건지 한번에 이해되지 않아서 몇번이고 읽어봤던 것 같습니다.

솔직히 말해서, 저는 기능 구현 중간에 객체 설계 자체를 완전히 갈아엎을 정도로 처음에는 요구사항을 이해하지 못했습니다. 요구사항을 읽으면 읽을 수록 머릿속이 복잡해지고, 객체의 역할과 책임은 두루뭉실해졌습니다. 대략적으로 설계도를 그려봐도 명쾌한 답이 나오지 않았습니다. 거기다 지난 3주 간의 모든 요구사항 상의 구현 제약(else문을 사용할 수 없다든지)을 포함하고 있었기 때문에 고려해야할 것도 매우 많았습니다.

이런 이유로 저는 이번 미션이 최종 코딩 테스트로 가는 마지막 관문이겠다는 생각이 들었습니다. 이번 미션의 제출에 성공하느냐 실패하느냐에서 최종 코딩 테스트 기회가 주어지느냐 마느냐가 결정될 것 같았습니다. 마치 우아한테크코스에서 저에게 그동안 프리코스를 얼마나 성실히 했는지를 물어보는 것 같았습니다. 부랴부랴 이전 미션들을 어떻게 구현했는지 살펴보며 활용할 수 있을만한 지식들을 학습하기 시작했습니다.

생소한 테스트 작성, 구현 기능의 잦은 수정, 그로 인해 터져 나오는 버그까지, 수많은 난관들이 절 괴롭혔습니다. 그래도 저에게만 어려운게 아니라는 마음가짐으로 차분히 미션을 진행했고, 다행히 마감 기한에 맞춰 제출에 성공했습니다. 미리 이번 미션의 총평을 하자면, 다음과 같습니다.

과연 최종 테스트도 이렇게 어려울까?

왜 이렇게 생각했는지, 코드를 모두 공개할 순 없지만, 프리코스의 모든 미션에서 매번 등장했던 요구사항인 기능을 구현하기 전 README.md에 구현할 기능 목록을 정리하기의 README.md 전문으로 그 이유를 대신하겠습니다.

README.md
# 12월 이벤트 플래너

## 구현 기능 목록

### Main

- Application
  - `EventController`를 통해 12월 이벤트 플래너를 시작한다.

### Model

- Badge
  - 12월 이벤트 플래너에서 제공할 이벤트 배지의 열거형이다.
  - 사용자가 제공 받은 총 혜택 금액에 따라 이벤트 배지를 부여한다.
- Bounds
  - 12월 이벤트 플래너에서 여러 조건 기준에 대한 정보를 제공하는 열거형이다.
  - 이벤트 기간의 첫 번째 날과 마지막 날에 대한 정보를 제공한다.
  - 크리스마스 날짜에 대한 정보를 제공한다.
  - 이벤트 적용을 위한 최소 주문 금액에 대한 정보를 제공한다.
  - 주문 메뉴의 최소 주문 수량에 대한 정보를 제공한다.
  - 주문 메뉴의 최대 주문 수량에 대한 정보를 제공한다.
  - 증정 메뉴의 기준 총 주문 금액에 대한 정보를 제공한다.
- Date
  - 12월 이벤트 플래너에서 방문 날짜 역할을 담당한다.
  - 사용자가 입력한 방문 날짜가 숫자가 아니라면 예외가 발생한다.
  - 사용자가 입력한 방문 날짜가 12월의 1일부터 31일 사이가 아니라면 예외가 발생한다.
  - 사용자가 입력한 방문 날짜가 크리스마스 이전인지 판별한다.
  - 사용자가 입력한 방문 날짜가 평일인지 판별한다.
  - 사용자가 입력한 방문 날짜가 주말인지 판별한다.
  - 사용자가 입력한 방문 날짜가 특별 할인일인지 판별한다.
  - 사용자가 입력한 방문 날짜를 제공한다.
- Discount
  - 12월 이벤트 플래너에서 할인 역할을 담당한다.
  - 사용자가 입력한 방문 날짜와 주문 메뉴에 따른 할인 내역에 대한 정보를 제공한다.
  - 사용자가 입력한 방문 날짜와 주문 메뉴에 따른 총 할인 금액을 제공한다.
- DiscountCondition
  - 12월 이벤트 플래너에서 할인 정책 역할을 담당한다.
  - 사용자가 입력한 방문 날짜가 현재 정책이 적용 가능한지 판별한다.
  - 적용된 할인 금액을 반환한다.
  - ChristmasDiscount
    - 크리스마스 디데이 할인 정책을 적용하고 할인 금액과 혜택 내역을 반환한다.
  - SpecialDiscount
    - 특별 할인 정책을 적용하고 할인 금액과 혜택 내역을 반환한다.
  - WeekdayDiscount
    - 평일 할인 정책을 적용하고 할인 금액과 혜택 내역을 반환한다.
  - WeekendDiscount
    - 주말 할인 정책을 적용하고 할인 금액과 혜택 내역을 반환한다.
- EventDay
  - 12월 이벤트 플래너에서 이벤트 적용 날짜 역할을 담당한다.
  - 사용자가 입력한 날짜가 이벤트에 적용되는지 판별한다.
- EventPlanner
  - 12월 이벤트 플래너에서 이벤트 플래너 역할을 담당한다.
  - 사용자가 주문한 메뉴 목록 문자열을 생성하고 반환한다.
  - 사용자가 입력한 주문 메뉴가 지정된 형식을 따르지 않으면 예외가 발생한다.
  - 사용자가 입력한 주문 메뉴가 중복되면 예외가 발생한다.
  - 사용자가 주문한 메뉴의 총 주문 금액을 반환한다.
  - 사용자가 주문한 메뉴에 대한 혜택 내역을 반환한다.
  - 사용자가 주문한 메뉴의 총 주문 금액에 대한 증정 메뉴의 정보를 반환한다.
  - 사용자가 주문한 메뉴의 총 주문 금액에 대한 증정 메뉴의 가격을 반환한다.
- Gift
  - 12월 이벤트 플래너에서 증정 메뉴 역할을 담당한다.
  - 사용자가 주문한 메뉴의 총 주문 금액에 따라 증정 메뉴의 정보를 반환한다.
  - 사용자가 주문한 메뉴의 총 주문 금액에 따라 증정 메뉴의 가격을 반환한다.
- Menu
  - 사용자가 선택할 메뉴에 대한 정보를 나타내는 열거형이다.
  - 사용자가 주문한 메뉴의 총 주문 금액을 반환한다.
  - 사용자가 주문한 메뉴가 존재하지 않으면 예외가 발생한다.
  - 사용자가 주문한 메뉴가 음료 밖에 없다면 예외가 발생한다.
  - 사용자가 주문한 메뉴의 종류별 주문 개수를 반환한다.
  - 사용자가 주문한 메뉴가 존재하는지 판별한다.
  - 사용자가 주문한 메뉴의 이름을 제공한다.
  - 사용자가 주문한 메뉴의 종류에 대한 정보를 제공한다.
- Message
  - 사용자에게 정보를 제공하기 위한 메시지의 열거형이다.
- Order
  - 12월 이벤트 플래너에서 주문서 역할을 담당한다.
  - 사용자가 주문한 메뉴의 가격에 대한 정보를 반환한다.
  - 사용자가 주문한 메뉴의 종류에 대한 정보를 반환한다.
  - 사용자가 주문한 메뉴가 존재하지 않으면 예외가 발생한다.
  - 사용자가 주문한 메뉴의 개수가 최소 주문 수량보다 적으면 예외가 발생한다.
  - 사용자가 주문한 메뉴의 개수가 최대 주문 수량보다 많으면 예외가 발생한다.
  - 사용자가 음료만 주문했다면 예외가 발생한다.
  - 사용자가 주문한 메뉴의 총 가격을 반환한다.
  - 사용자가 주문한 메뉴의 종류별 주문 개수를 반환한다.
  - 사용자가 주문한 메뉴 목록을 문자열 형태로 반환한다.

### View

- InputView
  - 12월 이벤트 플래너에서 사용자 입력을 받는 UI 역할을 담당한다.
- OutputView
  - 12월 이벤트 플래너에서 사용자에게 이벤트 적용 결과를 보여주는 UI 역할을 담당한다.

### Controller

- EventController
  - 12월 이벤트 플래너의 전체적인 흐름을 제어한다.
  - `InputView`로부터 사용자의 입력을 받는다.
  - 12월 이벤트 플래너의 핵심 로직들을 모델을 통해 수행한다.
  - `OutputView`를 통해 12월 이벤트 플래너의 결과를 출력한다.

읽기도 벅차며, 한번에 이해하기도 쉽지 않은 이 많은 양의 기능들을 처음부터 완벽하게 설계하려했던 제 자신이 바보 같아지기도 했습니다. 뭔가 다른 방법으로 구현했다면 더 빠르고 간단하게 구현할 수 있지 않았을까 하는 생각도 들었습니다. 앞선 회고들에서도 말했듯이, 분명히 더 나은 방법은 존재하겠지만, 기한을 맞추느라 급급했던 저는 스스로 고통받으며 이번 미션을 끝냈습니다.

객체의 분리, 역할과 책임을 다시 생각하기

이번 미션에서 끝까지 고민했던 부분은 내가 정말 객체의 역할과 책임을 잘 분배한 걸까? 였습니다. 미션 구현 도중 한번 몽땅 뒤집어 엎은 이유이기도 합니다. 처음 생각한 구현 기능 목록에 맞춰서 객체를 설계하고 기한에 쫓겨 급하게 구현하다보니 객체가 점점 비대해졌습니다. 한 객체가 너무 많은 기능을 가지고 있게 되었고 객체 간의 의존성도 많이 복잡해졌습니다. 사소한 수정에 영향을 받아 함께 수정되어야 하는 객체가 많아지니 유지보수는 커녕 버그도 제대로 잡을 수 없게 되었습니다.

결국, 아무리 IDE의 디버깅 기능을 이용해 버그를 잡아보려해도 어디서부터 구현이 잘못된 건지 찾을 수 없을 지경이 되었습니다. 이렇게 시간을 끌어서는 기한 안에 미션을 완성할 수 없겠다는 생각이 들었고, 저는 객체의 설게, 역할과 책임의 분배부터 잘못되었다고 판단해 처음부터 다시하기로 결정했습니다.

괜히 요구사항에서 구현하기 전 구현할 기능 목록을 README에 정리하라는 내용이 있는게 아님을 뼈저리게 느끼고 다시 객체 설계를 시작했습니다. 좀 더 작은 객체로 나눌 수는 없는지, 각 기능이 올바른 객체에게 주어졌는지, 객체가 다른 객체에게 과하게 의존적이진 않은지, 스스로 질문하며 설계해보니 처음 생각했던 구현할 객체 목록보다 훨씬 많아졌습니다. (이 과정의 결과물은 위의 README.md를 참고해주세요!)

약 6시간 남짓 남았을 무렵 처음부터 다시 구현하기 시작했고, 제자리에서 한 번도 움직이지 않고 개발만 해 마감 기한 직전에 제출에 성공했습니다. 미션을 끝내고 나선, 도대체 이번 미션이 저에게 뭘 물어보고 싶은 건지 천천히 고민해봤습니다. 물론 구현해야 하는 기능들이 난이도가 높았던 것은 맞지만 그렇다고 "너가 얼마나 개발을 잘하는지 보자!" 는 아닌 것 같았습니다.

이전의 미션들과 달리 복잡하고 긴 요구사항 전달 방식, 필요하다고 판단되는 객체의 수, 제출 방식의 차이 등을 고려해봤을 때, 얼마나 깊게 생각하고, 생각을 잘 현실에 실체화할 수 있는지를 묻는 것 같았습니다. 글을 읽고, 자신만의 생각으로 정리하고, 이를 코드에 옮겨 동작하도록 하는 것이 프로그래머라고 본다면, 이번 미션은 "너가 정말 프로그래머가 될 수 있을까?" 를 묻는 것이라고 생각합니다.

그렇게 본다면, 전 아직 부족한 프로그래머인 것 같지만 말입니다.

프리코스를 모두 마치고

이번 미션을 끝으로 프리코스는 모두 끝이 났습니다. 한 달이라는 시간 동안 학업과 병행하며 1주일 안에 시간을 짜내고 머리를 굴리며 주어진 미션을 완성하는 일은 꽤 색다른 경험이었던 것 같습니다. 프리코스 전의 프로그래밍 경험이라고 해봐야 제 머릿속의 아이디어를 코드로 옮기는 것이 전부였으며, 무엇인가 문제를 맞추는 개념의 개발은 알고리즘 풀이 뿐이었습니다.

그러나 우아한테크코스 프리코스는 누군가가 작성한 요구사항을 해석하고, 나만의 방식으로 이를 구현하기 위해 고민하고, 내 아이디어가 맞는지 평가받는 전혀 다른 방식의 프로그래밍이었습니다. 그동안 참여했던 팀 프로젝트, 경진대회 모두 제가 아이디어를 내고, 제가 아이디어를 구체화하고, 제 생각대로, 제 방식대로 팀원에게 할일을 분배했었습니다. 그러나 프리코스는 다른 사람이 원하는 방식이 아닐 경우 잘못된 구현이 될 수 있다는 점이 새롭게 느껴졌습니다.

switch-case 구문과 else 예약어를 사용하지 못했던 것, 예외 처리, 테스트 작성, 코드의 indent(들여쓰기)도 신경써야 하고 내가 무엇을 구현할 것인지 문서화해야 했던 모든 제약 사항들이 처음에는 불편하고 귀찮았습니다. 그러나 프리코스가 모두 끝난 지금 돌아보면 이런 제약들이 오히려 좋은 코드를 쓸 수 있도록 돕는 규칙이라는 생각이 들었습니다.

그래서 저는 우아한테크코스가 누구보다도 잘하는 개발자가 아닌 함께하기 좋은 개발자를 만드는 곳인 것 같습니다. 제 목표가 좋은 개발자인 만큼 꼭 우아한테크코스에 함께하고 싶습니다.

그리고 저는 해냈습니다.

woowacourse-accept-firststep

저를 좋게 봐주셨는지 최종 코딩 테스트 기회를 받았고, 이에 대한 회고는 다음 글에 있습니다. 우아한테크코스 최종 코딩 테스트 회고

hangillee

Personal blog by hangillee.

Road to good developer.