-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature(step4): 자동차 경주(우승자) 기능 구현 #6056
feature(step4): 자동차 경주(우승자) 기능 구현 #6056
Conversation
- 진입점에 맞추어 main 클래스 package안으로 이동 - 클래스, 인스턴스 변수 공백 추가 - private method static 제거 - 테스트 코드 분리 - util 클래스 객체 생성 방지를 위해 private생성자 추가
- Car, Position 불변 객체로 변경 - RacingGame 접근 범위 private로 제한 - 테스트 케이스 불변객체 적용 - 유틸클래스 private 생성자 추가 - InputView > InputValidator로 변경
- 1자 이상 5자 이하, 공백 및 6자 이상 예외 처리 - 에러메시지 추가 - private 생성자 추가
- CarGenerator 관련 파일 삭제하고 팩토리 메서드 패턴을 통해 이름 입력으로 차량 객체 생성하도록 수정 - 테스트 코드에 이름 받도록 수정
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 이진님 😃
불변 객체를 잘 활용해서 잘 구현해 주셨네요 👍
몇 가지 코멘트 남겨두었는데 확인해 주시고 다시 리뷰 요청해 주세요.
src/main/java/racingcar/Main.java
Outdated
InputView inputView = new InputView(); | ||
|
||
final List<String> names = getValidCarNames(inputView); | ||
final int attemptCount = getValidAttemptCount(inputView); | ||
|
||
RacingGame racingGame = RacingGame.createRacingGame(names); | ||
|
||
final RacingGame finalResult = racingGame.race(attemptCount); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final 변수 👍
변수에 따라 final 이 있기도하고 없기도 한데요
어떤 기준으로 지역 변수에 final 키워드를 추가하시는지 궁금합니다 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
웬만하면 불변성을 나타내려고 final을 붙이는데 누락이 있는거 같습니다. 좀 더 꼼꼼히 보도록 하겠습니다!
피드백 감사합니다 ~! 😄
|
||
private final String name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이름도 Position처럼 원시 값을 포장하면 어떨까요?
이름 유효성에 대한 책임을 위임할 수 있을 것 같아요
public Car(String name) { | ||
validateName(name); | ||
this.name = name; | ||
this.position = new Position(0); | ||
} | ||
|
||
public Car(String name, Position initialPosition) { | ||
validateName(name); | ||
this.name = name; | ||
this.position = initialPosition; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
부 생성자는 주 생성자를 호출해 중복되는 코드를 제거하면 어떨까요?
생성자에 대한 단위 테스트도 추가되면 좋을 것 같아요
public void incrementPosition() { | ||
position += 1; | ||
public Position incrementPosition() { | ||
return new Position(this.position + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
불변 객체 💯
|
||
private OutputView() {} | ||
|
||
private static final String SEPERATOR = ", "; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Position, Car 클래스에도 출력을 위한 기호들이 선언되어 있는데요
출력에 관련된 상수는 모두 OutputView로 모아서 응집도를 높이면 어떨까요?
@DisplayName("자동차가 이동해도 기존 객체는 변하지 않는다.(불변 객체 테스트)") | ||
@Test | ||
void car_not_move_immutable_test() { | ||
String carName = "car"; | ||
Car initialCar = new Car(carName); | ||
|
||
car.move(randomValue); | ||
car.move(randomValue2); | ||
Car movedCar = initialCar.move(4); | ||
|
||
assertThat(car.isAtPosition(new Position(expectedPosition))).isTrue(); | ||
assertThat(initialCar.isAtPosition(new Position(0))).isTrue(); | ||
assertThat(movedCar.isAtPosition(new Position(1))).isTrue(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
불변에 대한 테스트 👍
isAtPosition 메서드로 값을 꺼내 비교해도 좋지만 비교해야할 값이 많다면 코드의 양도 많이 늘어날 수 있는데요
객체끼리 비교하는 방법도 고려해 보시면 좋을 것 같아요
assertThat(initialCar).isNotEqualTo(movedCar);
@DisplayName("초기 위치가 5인 자동차가 2번 이동 하면 현재 위치보다 2 증가한다.") | ||
@ParameterizedTest | ||
@CsvSource({ | ||
"0,1,1,0", | ||
"3,4,4,5", | ||
"5,4,1,6", | ||
"5,1,5,6" | ||
}) | ||
void move_initial_move(int initialPosition, int randomValue, int randomValue2, int expectedPosition) { | ||
String carName = "car"; | ||
Car initialCar = new Car(carName, new Position(initialPosition)); | ||
|
||
Car movedOnceCar = initialCar.move(randomValue); | ||
Car movedTwiceCar = movedOnceCar.move(randomValue2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
위치 값에 알고 있는 객체는 Position입니다.
그러니 테스트 대상도 Position#incrementPosition() 가 되어야 하지 않을까요?
@@ -3,16 +3,20 @@ | |||
import org.junit.jupiter.api.DisplayName; | |||
import org.junit.jupiter.api.Test; | |||
|
|||
import java.util.List; | |||
|
|||
import static org.assertj.core.api.Assertions.assertThat; | |||
|
|||
class RacingGameTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
프로그래밍 요구사항
모든 로직에 단위 테스트를 구현한다. 단, UI(System.out, System.in) 로직은 제외
핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.
우승자 기능이 추가되었지만 관련 테스트가 누락되었네요
모든 public 메서드에 대해 누락된 테스트가 없는지 검토해 보시면 좋을 것 같아요
- 생성자 테스트 코드 작성
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 이진님 😃
피드백 반영 잘해주셨네요 👍
소소하게 코멘트 남겨두었는데 확인해 주시고 다음 단계 진행해 주세요!
@@ -1,38 +1,23 @@ | |||
package racingcar.model; | |||
|
|||
import racingcar.message.ErrorMessage; | |||
import static racingcar.view.OutputView.NAME_POSITION_SEPERATOR; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MVC 패턴을 의식하셔서 model, view 패키지를 나누셨을거라 생각되는데요
이미 OutputView에서 Car 모델을 참조하고 있기에 model 패키지와 view 패키지는 순환참조하게 되었네요.
다음 단계의 주제이니 의존성 방향을 정리해 보시면 좋을 것 같아요.
public class CarName { | ||
|
||
private final String name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
객체 분리 👍
@DisplayName("자동차명은 1자에서 5자 이하이다.") | ||
@ParameterizedTest | ||
@ValueSource(strings = {"a", "ab", "abc", "abcd", "abcde"}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이름 길이가 10자, 20자 제한으로 변경되면 테스트해야할 값도 많아질 것 같아요.
경계값이 되는 값으로 테스트하면 어떨까요?
@DisplayName("자동차명이 null이면 exception을 발생시킨다.") | ||
@Test | ||
void car_name_with_blank() { | ||
assertThatThrownBy(() -> new Car(new CarName(""))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CarName 에 대한 테스트이니 new Car
는 제외하면 어떨까요?
assertThatThrownBy(() -> new Car(new CarName(""))) | |
assertThatThrownBy(() -> new CarName("")) |
|
||
Car movedCar = initialCar.move(randomValue); | ||
|
||
assertThat(movedCar.getName()).isEqualTo(carName); | ||
assertThat(movedCar.getName().getName()).isEqualTo(carName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
자동차 객체는 비교적 단순하지만 객체 그래프가 깊어지면 get..get..get..get.. 같은 코드가 될 가능성이 높습니다.
디미터 법칙을 적용해 개선해 보시면 좋을 것 같아요.
안녕하세요~ 오늘도 잘 부탁드립니다 😄