✔ 자동차 경주
미션 제출 방법
- 미션 요구사항을 파악해 기능을 구현한 후 GitHub을 통해 add, commit, push
- 미션을 모두 완료 후 Pull Request로 woowacourse에 제출
- 우아한테크코스 지원 플랫폼에 GitHub ID, Pull Request 주소, 과제 진행 소감을 프리코스 과제로 제출
1주차 공통 피드백 정리
1) 요구사항을 정확히 준수한다
2) 커밋 메시지를 의미 있게 작성한다
3) git을 통해 관리할 자원에 대해서도 고려한다
4) Pull Request를 보내기 전 브랜치를 확인한다
5) PR을 한 번 작성했다면 닫지 말고 추가 커밋을 한다
6) 이름을 통해 의도를 드러낸다
7) 축약하지 않는다
8) 공백도 코딩 컨벤션이다
9) 공백 라인을 의미 있게 사용한다
10) space와 tab을 혼용하지 않는다
11) 의미 없는 주석을 달지 않는다
12) IDE의 코드 자동 정렬 기능을 활용한다
13) Java에서 제공하는 API를 적극 확용한다
14) 배열 대신 Java Collection을 사용한다
진행 방식
1) 과제 진행 요구 사항 파악하기
1. 미션 저장소를 Fork & Clone해 시작하기
2. 기능을 구현하기 전에 구현할 기능 목록을 정리해 추가하기3. 커밋 단위는 기능 목록 단위로 추가
3. 커밋 단위는 기능 목록 단위로 추가
2) 프로그래밍 요구 사항 파악하기
1. JDK 17 버전에서 실행
2. 프로그램 실행의 시작점은 Application의 main()
3. Java 코드 컨벤션 가이드를 준수하여 프로그래밍
4. build.gradle 파일은 변경할 수 없음
5. ApplicationTest의 모든 테스트가 성공해야 함
6. 파일, 패키지 이름을 수정하거나 이동하지 않음
7. Randoms의 pickNumberInRange() 및 Console의 readLine() API를 사용하여 구현
8. indent depth를 3이 넘지 않도록 구현
9. 3항 연산자를 쓰지 않음
10. 함수가 한 가지 일만 하도록 최대한 작게 만들어라
11. 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인하라 (각 함수별로 테스트를 작성)
3) 기능 요구 사항 파악하기
[게임 설명 - 초단간 자동차 경주 게임]
1. 주어진 횟수 동안 무작위 값에 따라 n대의 자동차는 전진 또는 멈춤
2. 각 자동차에 이름을 부여하여 전진하는 자동차를 출력
3. 자동차 경주 게임을 완료한 후 우승자 출력
[기능 요구 사항 설명]
1. 쉼표(,)를 기준으로 구분하여 5자 이하의 이름을 각 자동차에 부여
2. 사용자가 몇 번의 이동을 할 것인지 지정
3. 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이
4 이상일 경우 전진, 아닐 경우 멈춤
5. 전진하는 자동차는 자동차를 출력할 때 자동차 이름을 같이 출력
6. 지정 횟수만큼 시도했다면 최종 우승자를 출력하고 게임이 종료
7. 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션 종료
[입출력 요구 사항 설명]
* 입력 *
쉼표(,)를 기준으로 5자 이하의 경주할 자동차 이름
시도할 횟수
* 출력 예시 *
경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)
pobi,woni,jun
시도할 회수는 몇회인가요?
5
실행 결과
pobi : -
woni :
jun : -
pobi : --
woni : -
jun : --
pobi : ---
woni : --
jun : ---
pobi : ----
woni : ---
jun : ----
pobi : -----
woni : ----
jun : -----
최종 우승자 : pobi, jun
(단독 우승자의 경우, 최종 우승자 : pobi)
구현할 기능 목록 정리
1) 게임이 시작되면 자동차 이름을 입력받기 위해 '경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)' 출력
2) 입력받은 경주할 자동차 이름을 쉼표로 구분하여 저장
자동차에 따라 쉼표를 구분자로 하여 5자 이하의 자동차 이름 저장
[Exception]
쉼표로 구분되지 않을 경우 (구분자를 포함하지 않은 경우)
1자 이상, 5자 이하가 아닐 경우
다른 자동차의 이름과 중복될 경우
→ 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션 종료
3) 이동할 횟수를 입력받기 위해 '시도할 횟수는 몇회인가요?' 출력
4) 입력받은 시도할 횟수를 저장
[Exception]
수가 아닐 경우
음수 혹은 0일 경우
소수인 경우
→ 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션 종료
5) 시도할 횟수 동안, 각 자동차에 대한 전진하는 조건 구하기
0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우 전진
4 미만일 경우 멈춤
6) 전진 결과를 출력
전진하는 자동차는 자동차를 출력할 때 자동차 이름을 같이 출력
전진 횟수에 따라 '-' 출력
7) 시도할 횟수만큼 시도한 후 최종 우승자 출력
가장 많이 전진한 자동차 이름 출력
우승자가 여러 명일 경우 쉼표(,)를 이용하여 이름 출력
기능 구현
1) MVC 패턴을 적용해서 설계해보자
Model : 애플리케이션의 정보, 데이터 등의 가공을 책임지는 컴포넌트
View : 사용자 인터페이스 요소로 데이터를 기반으로 사용자들이 볼 수 있는 화면
Dto : MVC 중 Model 쪽에 속하여 MVC 흐름 속에서 데이터가 교환될 수 있도록 하는 객체
(View와 Model의 데이터를 주고 받을 때 별도의 DTO 사용)
Controller : 데이터와 사용자 인터페이스 요소를 잇는 다리 역할로, 이벤트들을 처리
[필요한 Model - 1주차 미션에서 적용했던 domain, service에 추가적으로 dto를 작성해보았다]
1. 자동차 객체 (domain) - 이름, 위치(전진 횟수)
2. 게임 객체 (domain) - 자동차들, 시도 횟수, 현재 시도 횟수
3. 자동차 이름 저장 request (dto)
4. 게임 시도 횟수 저장 request (dto)
5. 게임 진행 결과 출력 response (dto)
6. 게임 우승 자동차 출력 response (dto)
7. 게임과 관련된 서비스 (service) - 전진/멈춤값 가져오기, 자동차 움직이기, 우승자 찾기 → 인터페이스로 구현
[필요한 View]
1. 사용자 입력 화면
2. 사용자 출력 화면
[필요한 Controller]
1. 게임 시작 컨트롤러 - 데이터인 Model와 사용자 인터페이스인 View를 잇는 역할
[그 외 utils]
1. 입력 변수 처리 및 예외처리 (validator)
2. 전진/멈춤값 생성 (generator)
3. 형변환 (parser)
model
|- domain
|- Car.java : 자동차 객체 정보 Domain
|- Game.java : 게임 객체 정보 Domain
|- dto
|- CarRequestDto.java : 자동차 이름 요청 DTO
|- CarResponseDto.java : 우승 자동차 이름 응답 DTO
|- GameRequestDto.java : 게임 시도 횟수 요청 DTO
|- GameResponseDto.java : 게임 진행 결과 응답 DTO
|- service
|- RacingCarService.java : 게임 관련 자동차 움직이기, 우승자 찾기 등의 Service
view
|- InputView.java : 사용자 입력 View
|- OutputView.java : 사용자 출력 View
controller
|- RacingCarController.java : 게임 시작 Controller
utils
|- Validator.java : 입력 변수 처리하고 예외처리 Util
|- Generator.java : 전진/멈춤값 랜덤 생성 Util
|- Parser.java : 형변환 Util
constants
|- Error.java : 예외 메시지 상수 Constant
|- Phrase.java : 출력 메시지 상수 Constant
|- Rule.java : 룰 상수 Constant
Application.java
2) TDD를 적용해가면서 구현해보자
1. 테스트 코드 작성
2. 테스트 코드를 통과하기 위한 최소한의 코드 작성
3. 테스트 코드 통과를 유지하면서 리팩토링
+) 테스트 코드를 짜기 힘들 경우 코드 먼저 짜고서라도 테스트 코드 작성하기
3) 리팩토링
클린 코드에 맞춰 리팩토링을 하려고 노력했다.
1. 의미 있는 메소드명, 변수명, 클래스명을 사용하자
2. 중복을 최대한 제거하자
3. 한 메소드에서는 하나의 일만 하도록 하자
4. 상수 대신 열거형을 사용하자
5. 인터페이스 사용과 의존성 주입을 통해 결합도를 낮추자
6. final 사용을 통해 변수를 불변하도록 하자
7. 생성자 대신 정적 팩토리 메서드를 사용해보자
8. 접근 권한을 최소화하자
9. 가독성이 떨어지지 않는다면 스트림을 사용해보자
10. 각 함수별로 테스트를 작성하여 정상 동작함을 확인하자
이 외에도 다양한 곳을 리팩토링하려고 했다.
회고
이전 미션에서 제가 작성한 MVC 패턴에 대한 문제점을 파악하려고 했습니다.
먼저 utils과 service 간의 경계를 명확히 나누려고 했습니다. 서비스와 밀접한 관련이 있는 코드는 service로 이동하고, 그 외 값 생성 및 검사와 같이 단순한 작업은 utils로 분리했습니다.
이전에는 model의 domain에서 유효성 검사를 진행한 후, 저장을 했습니다. 이번에는 model에 dto를 생성하여 view에서 받아온 데이터를 dto에서 검사한 후 domain으로 전달하는 방식으로 코드를 구현했습니다. 이렇게 함으로써 model과 view 간의 경계를 명확히 나누고자 했습니다.
또한 이전 미션에서는 Controller 내에서 의존성 주입이 미리 이루어져 있었지만, 이번에는 메인 메소드에서 인터페이스 구현체를 호출하여 의존성 주입을 수행하도록 변경하여 책임을 분리하고자 했습니다.
그뿐만 아니라 SOLID 원칙을 준수하며, 각각의 책임을 최대한 분리하고 함수를 작게 만들고자 노력했으며, 각 코드에 대한 꼼꼼한 테스트 작성을 목표로 했습니다.
'Community > 우테코 프리코스' 카테고리의 다른 글
[우테코] 웹 백엔드 프리코스 4주차 미션 (0) | 2023.11.09 |
---|---|
[우테코] 웹 백엔드 프리코스 3주차 미션 (0) | 2023.11.02 |
[우테코] 웹 백엔드 프리코스 1주차 미션 (0) | 2023.10.19 |
[우테코] 2024 우아한테크코스 입학설명회 (0) | 2023.10.06 |