📌 Intro
오늘 마지막 4주차 미션을 제출하며 프리코스를 마무리했다. (아직 피어리뷰가 있기는 하지만) 프리코스를 진행한 4주간 정말 바쁘게 살았던 것 같다. 아마 주말에 1박 2일 혹은 2박 3일로 여행을 다녀와서 그런 것이려나ㅎㅎ 그래도 생각해보면 그 여행 덕분에 지치지 않고 끝까지 완주할 수 있었던 것 같기도 하다. 가능하다면 4주차 코드리뷰를 끝내고 3, 4주차 미션에 대한 리팩토링을 진행해보면 더 좋은 경험이 될 것 같다. 근데 종설도 해야하고..... 기말고사도 있고... 졸업하기 위해서 오픽도 봐야한다.... 멀다 멀어...
일단 4주차 미션에 대해 간략하게 알아보자. 오징어 게임에서 진행했던 유리/강화유리 발판을 밟고 넘어가는 게임을 구현하는 것이었다. 사용자에게 다리의 길이를 입력받아 랜덤으로 다리를 생성하고 사용자에게 위 칸으로 이동할지 아래 칸으로 이동할지 입력을 받고 만약 이동이 가능한 곳이라면 다음 입력을 받는 식으로 진행한다. 다리의 끝에 도달했다면 결과를 출력하고 게임을 끝낸다. 만약 이동이 불가능한 곳으로 입력을 받았다면 사용자에게 게임을 다시 시작할 것인지 그대로 종료할 것인지 입력을 받고 입력에 따라 결과를 출력하는 방식으로 진행한다.
📌 추가된 요구 사항
클래스(객체)를 분리하는 연습
리팩터링
4주차 미션에서는 3주차 미션 학습 목표와 더불어 리팩터링이 추가되었다. 클래스의 구조와 제약사항을 요구사항에 추가함으로써 클래스 분리에 대해 더 깊이 고민하도록 만들었고, 함수의 길이를 10줄로 제한하여 난이도를 높였다. 그래서 일단 기능이 가능하도록 구현한 뒤 리팩터링을 진행하라는 의미로 여러가지 제약사항을 걸어둔 것 같다.
- 함수의 길이가 10라인을 넘어가지 않도록 구현한다.
- 메서드의 파라미터 개수는 최대 3개까지만 허용한다.
- InputView, OutputView, BridgeGame, BridgeMaker, BridgeRandomNumberGenerator 클래스의 요구사항을 참고하여 구현한다.
- InputView 클래스에서만 사용자의 입력을 받을 수 있다.
- BridgeGame 클래스에서 InputView, OutputView를 사용하지 않는다.
InputView
- 제공된 InputView 클래스를 활용해 구현해야 한다.
- InputView의 패키지는 변경할 수 있다.
- InputView의 메서드의 시그니처(인자, 이름)와 반환 타입은 변경할 수 있다.
- 사용자 값 입력을 위해 필요한 메서드를 추가할 수 있다.
OutputView 클래스
- 제공된 OutputView 클래스를 활용해 구현해야 한다.
- OutputView의 패키지는 변경할 수 있다.
- OutputView의 메서드의 이름은 변경할 수 없고, 인자와 반환 타입은 필요에 따라 추가하거나 변경할 수 있다.
- 값 출력을 위해 필요한 메서드를 추가할 수 있다.
BridgeGame 클래스
- 제공된 BridgeGame 클래스를 활용해 구현해야 한다.
- BridgeGame에 필드를 추가할 수 있다.
- BridgeGame의 패키지는 변경할 수 있다.
- BridgeGame의 메서드의 이름은 변경할 수 없고, 인자와 반환 타입은 필요에 따라 추가하거나 변경할 수 있다.
- 게임 진행을 위해 필요한 메서드를 추가하거나 변경 할 수 있다.
BridgeMaker 클래스
- 제공된 BridgeMaker 클래스를 활용해 구현해야 한다.
- BridgeMaker의 필드를 변경할 수 없다.
- BridgeMaker의 메서드의 시그니처(인자, 이름)와 반환 타입은 변경할 수 없다.
BridgeRandomNumberGenerator 클래스
- Random 값 추출은 제공된 bridge.BridgeRandomNumberGenerator의 generate()를 활용한다.
- BridgeRandomNumberGenerator, BridgeNumberGenerator 클래스의 코드는 변경할 수 없다.
📌 구현 내용
앞서 이야기한 것처럼 제약사항이 많았지만 일단 최대한 요구사항을 맞춰가면서 구현을 진행했다. 나중에 리팩터링을 진행하더라도 코드 전체를 뒤집는 일은 없도록 하기 위해서 많은 고민을 하며 코드를 적어내려갔던 것 같다. 그래서 그런지 실제로 깃에 커밋을 할 때 refactor를 사용하지는 않았던 것 같다. (잘못한건 아니겠지만 회고록을 작성하다보니 괜히 찝찝하다...)
BridgeGame class : 다리 건너기 게임 전체를 관리하는 역할
BridgeMaker class : 다리 길이를 입력 받아서 다리를 생성해주는 역할
BridgeRandomNumberGenerator class : 0, 1 중 하나를 무작위로 생성해주는 역할
Controller class : 게임을 준비하고 실행하는 역할
InputView class : 사용자에게 입력 받는 역할
OutputView class : 게임 결과를 출력하는 역할
Message Object : 출력하는 문구를 관리하는 역할
ExceptionHandler Object : 입력에서 발생할 수 있는 예외를 처리하는 역할
가장 먼저 주어진 클래스별로 역할을 구분했고 이후에는 필요한 기능을 나열하고 비슷한 기능들끼리 모아 클래스를 만들었다. 출력 문구는 3주차에서 학습했던 것처럼 Enum class를 통해 관리했다.
BridgeGame 클래스
InputView, OutputView를 사용하지 않는다는 제약 조건이 있어서 오랜 시간이 걸렸다. 나는 BridgeGame 클래스의 역할을 게임 전체를 관리하는 역할로 구분했기 때문에 필수적으로 사용해야 했다. 이 부분을 어떻게 해결해야 할까 한참을 고민했던 것 같다. 결국 게임의 로직을 관리하는 Controller class를 만들어서 필요한 클래스들을 생성하고 그 안에서 게임 로직을 돌리도록 했다.
BridgeGame 클래스를 게임 전체를 관리하도록 했기 때문에 다리의 상태, 총 시도 횟수, 이동 방법을 갖도록 했다.
BridgeMaker 클래스
제약조건으로 클래스의 필드를 변경할 수 없고 makeBridge 함수의 시그니처(인자, 이름)와 반환 타입은 변경할 수 없었다. 하지만 BridgeNumberGenerator의 generate 함수는 Int형 0 또는 1의 결과를 반환하기 때문에 각 값에 맞게 U와 D를 저장하는 리스트를 생성하고 반환해주도록 했다.
InputView 클래스
사용자에게 물음을 주고 입력을 받는 역할을 하도록 했다. 물음을 주는 문구는 UI라는 enum class를 통해 관리하였다. 요구 사항 중 하나로 사용자가 잘못된 입력을 했을 경우 [Error]를 포함한 에러 메시지를 출력하고 다시 입력을 받도록 해야했다. 반복 입력을 위해 do while문을 사용했고 에러 메시지 출력을 위해 예외처리 클래스를 만들었다. 예외처리 클래스는 입력값을 파라미터로 받아 올바른 입력인지 확인하여 잘못된 입력이라면 에러 메시지를 출력하고 false를 올바른 입력이라면 true를 반환하도록 했다.
OutputView 클래스
결과를 출력하는 기능만을 추가했고 출력할 문자열은 전체 게임을 관리하는 BridgeGame 클래스에서 처리한 뒤 반환받아 사용하였다. 이렇게 한 이유는 3주차 피드백 내용에 객체를 객체답게 사용하라는 내용 때문이었다. 특정 데이터를 관리하는 클래스가 있다면 그 클래스 내에서 데이터를 이용하여 처리하고 결과만을 반환받아 사용하도록 하는 것이 객체를 객체답게 사용하는 것이라 생각했다.
Message 오브젝트
출력하는 문구를 enum class로 묶어 관리한다.
ExceptionHandler 오브젝트
입력에서 발생할 수 있는 예외를 처리한다. 앞에서도 말했던 것처럼 잘못된 입력이 들어왔을 때 에러 메시지를 출력하고 다시 입력을 받아야 했기 때문에 예외가 발생했는지 발생하지 않았는지를 확인하기 위해 함수의 반환 값을 Boolean으로 설정했고, InputView 클래스에서 반환 값을 이용하여 반복적으로 입력을 요구할 수 있도록 했다.
📌 느낀점
1주차부터 4주차까지 진행하면서 4주차 내용처럼 자세하게 적었던 적은 없던 것 같다. 그만큼 4주차 내용에 진심이었고, 이전에 학습했던 부분들을 모두 담으려고 노력했던 것 같다. 사실 프리코스를 시작할 때까지만 해도 프리코스에 대해 깊게 생각하지 않았다. 그냥 우테코에 참여하기 위한 일련의 과정 중 하나로만 생각했다. 1주차 미션과 2주차 미션을 진행할 때까지만 해도 그 생각은 변함이 없었다. 하지만 2주차 미션을 제출하고 다른 참여자들과 피어리뷰를 진행하면서 프리코스에 참맛을 알게 된 것 같다. 항상 반복하는 말이지만 같은 요구 사항에 대해 얼마나 다르게 생각할 수 있는지 코드 한 줄 한 줄에서 깊은 고민의 흔적인 느껴지는 것도 알 수 있었다. 그 분들과 피어리뷰를 하면서 내 코드에 더 신경쓰게 되었고 다듬을 수 있었다. 또 3주차부터 추가된 요구사항을 지키려고 노력하면서 앞으로도 계속 가지고 갈 좋은 습관들을 만들게 되었다. 나아가 우테코에 참여하면 좋겠지만 3주차 미션도 엉망이었고 소감문도 작성하지 못해서 큰 기대를 하지는 않는다. 그래도 코딩테스트 없이 모두가 4주간의 프리코스를 진행할 수 있었던 덕분에 얻어가는 것이 많은 것 같다. 프리코스에서 깨달은 것들을 조금 더 갈고 닦아서 더 내 것으로 만드려고 노력해야겠다. 한 달 동안 정말정말 고생 많았던 나 자신에게 칭찬하고 앞으로도 바쁠 나에게 격려를 하면서 마친다.