카카오 테크 캠퍼스의 두 번째 미니과제 '자동차 경주' 과제가 나왔습니다. 과제를 진행했던 과정을 포스팅으로 담아보았습니다.
과제 진행 요구 사항
기능 요구 사항
- 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다.
- 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차의 이름을 같이 출력한다.
- 자동차 이름은 쉽표를 기준으로 구분하여 이름은 5자 이하만 가능하다.
- 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
- 전진하는 조건은 0에서 9사이에서 무작위 값을 구한 후 무작위 값이 4이상일 경우다.
- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한
- 명 이상일 수 있다.
- 우승자가 여러 명일 경우 쉼표를 이용하여 구분한다.
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시키고, [ERROR]로 시작하는 에러 메시지를 출력 후 그 부분부터 다시 받는다.
- Exception 이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리한다.
실행 결과
프로그래밍 요구 사항
- JDK 17 버전에서 실행 가능해야 한다.
- Application의 main() 이 프로그램 실행의 시작점이다.
- System.exit() 를 호출하지 않는다.
- 자바 코드 컨벤션을 지키면서 프로그래밍한다.
- indent depth는 2까지만 허용된다.
- 3항 연산자를 쓰지 않는다.
- 함수는 한 가지 일만 하도록 작게 만든다.
- JUnit5와 AssertJ를 이용하여 정리한 기능 목록이 정상적으로 작동하는지 테스트 코드로 확인한다.
- 함수의 길이가 15라인을 넘어가지 않도록 구현한다.
- else 예약어를 사용하지 않는다.
- 도메인 로직에 단위 테스트를 구현해야한다. UI 로직은 제외한다.
기능 목록 작성하기📄
저번 과제와 동일한 순서로 먼저 기능 목록부터 작성했습니다.
이번에는 IllegalArgumentException 과 IllegalStateException 을 나눠서 에러 처리를 해야 했습니다. 이에 대해 간단하게 알아보니 IllegalArgumentException는 호출자가 인수로 부적절한 값을 넘길 때 던지는 예외이고, IllegalStateException 는 대상 객체의 상태가 호출된 메서드를 수행하기에 적절하지 않을 때 발생시키는 예외입니다.
# 🚗자동차 경주🚗
## 📃기능 목록📃
### 입력 기능
- [x] 자동차 이름 입력
- [x] 시도할 횟수 입력
### 출력 기능
- [x] 자동차 이름 입력을 위한 출력
- [x] 시도할 횟수 입력을 위한 출력
- [x] 실행 결과 출력
- [x] 우승자 출력
- [x] [ERROR] 메시지 출력
- [x] 에러 이후 재입력
### 자동자 전진, 멈춤
- [x] 무작위 값 생성
- [x] 각 자동차의 무작위 값에 대한 전진, 멈춤 결정
### 우승자 결정
- [x] 게임 완료 후, 누가 우승했는지 결정
### IllegalArgumentException 발생
- [x] 입력 받은 횟수가 숫자가 아닌 경우
- [x] 자동차 이름이 제대로 입력되지 않은 경우 (null 또는, 이름이 6자 이상인 경우)
구현 방향
먼저, 클래스로 분리해보고자 했습니다.
자동차 경주 게임을 실행하는 Game 클래스, 자동차 경주 게임의 핵심인 Car 클래스, 입력 클래스, 출력 클래스로 나눠보려 합니다.
Game 클래스
- 필드
- rule
- output
- input
- racingCars
- gameCnt
- 메서드
- start : 게임 시작
- carNameProcess - 함수 분리
- cntProcess - 함수 분리
- createCars
- createCnt
- raceForCnt
- winnerFind : 우승자 찾기
Car 클래스
- 필드
- name
- distance
- 메서드
- advance
- getName
- getDistance
Rule 클래스
- 메서드
- randomAdvanceOrStop(Car car)
- 랜덤 값으로 4 이상이면 전진 미만이면 멈춤
- carNameIsNull
- carNameIsOverSize
- tryCntInputValid(String input)
- 숫자가 아닌 경우
- randomAdvanceOrStop(Car car)
Input 클래스
- 필드
- scanner
- 메서드
- carNameInput
- tryCntInput
Output 클래스
- 메서드
- carNameOutput
- tryCntOutput
- resultOutput(Car[] cars)
- winnerOutput(Car[] cars)
- errorOutput(String error)
CarRaceApplication 클래스
- 메서드
- main
리펙토링
이렇게 구현하고 보니 Game 클래스가 매우 많은 기능을 담당하는 것 같았고 무거워 보였습니다. 특히, 입력 처리, 출력 처리를 메서드로 분리해보긴 하였으나 이것을 Game 클래스에서 담당할 필요는 없어 보였습니다.
따라서, 아래와 같이 수정해보았습니다. 이렇게 수정함으로써 클래스가 단일 책임 원칙을 지킬 수 있게 된 것 같습니다.
Game 클래스
- 필드
- inputProcessor
- raceProcessor
- outputProcessor
- racingCars
- gameCnt
- 메서드
- start
- createCars
- setGameCnt
- findWinners
InputProcessor 클래스
- 필드
- input
- output
- rule
- 메서드
- processCarNames
- processGameCount
OutputProcessor 클래스
- 필드
- output
- 메서드
- processWinnerName
RaceProcessor 클래스
- 필드
- output
- rule
- 메서드
- raceForCnt
과제 진행 소감🎓
이번 과제 코드를 짜기 전에 설계를 진행했는데도 구현하고 보니 Game 클래스가 입력 처리, 자동차 경주 처리, 출력 처리 등의 많은 책임을 갖고 있다는 것을 확인했습니다. 그래서 입력 처리 클래스와 경주 처리 클래스, 출력 처리 클래스를 추가하여 분리했고, Game 클래스와 협력하도록 구현했습니다. 그리고, Game 클래스에서 가독성이 부족해 보이는 부분은 변수로 분리하여 매개변수로 주입하는 방법으로 리펙토링해보았습니다.
클래스가 많은 책임을 갖고 있다는 것을 느끼고, 분리한 것에 발전했다는 생각이 들었습니다. 이전의 숫자 야구 게임 과제를 구현할 때도 요구 사항에는 없었지만 미리 객체 지향적으로 짜보려고 노력했었는데 그 때의 노력이 지금 도움이 된 것 같습니다.
앞으로도 객체 지향 원칙을 준수하며 코드를 작성해 나가도록 노력하려 합니다.
받은 피드백🍫
이번 피드백에서는 가독성이 좋았다는 평가를 받았습니다. 과제를 설계하는데 많은 고민을 했었는데 멘토분의 긍정적인 피드백을 받으니 뿌듯했습니다.
그리고, 좀 더 좋은 네이밍이 무엇일지에 대해서도 고민해야겠다는 생각을 했습니다.
'🍫카카오 테크 캠퍼스 2기 BE' 카테고리의 다른 글
[카카오 테크 캠퍼스 / BE] 2단계 두 번째 코드 리뷰 (0) | 2024.07.14 |
---|---|
[카카오 테크 캠퍼스 / BE] 2단계 첫 번째 코드 리뷰 후기 (0) | 2024.07.02 |
[카카오 테크 캠퍼스 / BE] 첫 번째 미니과제, 숫자 야구 게임⚾ (0) | 2024.05.27 |
[카카오 테크 캠퍼스 / 2기] '웰컴 키트' 라는 것을 받다 (0) | 2024.05.14 |
[카카오 테크 캠퍼스] 1단계 4주차 학습 일지 (0) | 2024.05.12 |