-
Notifications
You must be signed in to change notification settings - Fork 442
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
[연습] 자동차 경주 #514
base: main
Are you sure you want to change the base?
[연습] 자동차 경주 #514
Conversation
자동차 이름을 부여하는 부분은 자동차쪽으로 수정
0보다 작으면 -> 0 이하면
MIN_FUEL -> MIN_MOVE_FUEL 최소 연료 = MIN_FUEL
CarGameTest -> 이동횟수_등록_실패_테스트
레이스를 이동횟수 만큼 실행 -> 레이스를 1회만 실행하고 이동횟수를 차감하도록
|
||
|
||
public void moveOrStop(int fuel) { | ||
validateFuel(fuel); |
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.
Fuel 부분은 Randoms 라이브러리를 사용하는데,
검증 책임은 라이브러리를 만든 쪽에 있다고 생각해서
라이브러리를 사용하는 부분은 검증하지 않아도 될 것 같습니다!
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.
저도 같은 의견입니다 !
this.name = name; | ||
} | ||
|
||
// 추가 기능 구현 | ||
private void validateName(String name) { | ||
if (name.length() > MAX_NAME_LENGTH) { | ||
throw new IllegalArgumentException(Message.CAR_NAME_VALIDATION); |
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.
저는 예외 메세지는 추후에도 수정할 일이 없고,
여러 곳이 아닌 해당하는 하나의 예외에만 사용되기 때문에
가독성을 위해 상수화하지 않고 있습니다!
다른 분들의 의견은 어떨지 모르겠네요!
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.
저도 성훈님이랑 비슷한 의견입니다
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class CarGame { |
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.
'CarGame'이라고 네이밍을 하면 어떤 역할을 가지는 객체인지
처음에 알기 힘들 것 같아요!
어떤 책임을 가지는 객체인지 알기 쉽게 네이밍 해주면 좋을 것 같습니다!
추가적으로 CarGame이 너무 많은 역할을 하고 있는 것 같아요.
MVC 패턴을 참고해서 클래스 분리를 하는 것이 좋을 것 같아요!
} | ||
} | ||
|
||
public List<Car> getCars() { |
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.
Collection에 getter를 사용할 때 그냥 Collection 자체를 return하게 되면
외부에서 Collection을 받아서 Collection 내부의 값을 변경할 수도 있으므로
Collections.unmodifiableList(cars)
로 외부에서 내부의 값을 변경 못하도록 막아서 반환하는 게 좋을 것 같습니다!
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.
저도 같은 생각입니다
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.
감사합니다 이 부분은 처음 알았네요!
적용해보겠습니다~!
for (Car car : cars) { | ||
car.moveOrStop(getRandomFuel()); | ||
} | ||
moveCounts--; |
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.
시도 횟수를 하나씩 줄여가면서 하는 것보다
for문으로 하나씩 늘려가면서 하는 게 가독성에 더 좋을 것 같습니다!
|
||
public List<String> announceWinners() { | ||
return cars.stream() | ||
.filter(car -> car.getCurrentPosition() == cars.stream().map(Car::getCurrentPosition) |
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.
저도 Car에 Position을 얻기 위해 getter를 사용해서 받아왔었는데,
getter를 사용하는 대신 객체에 메시지를 보내자
이후에 생각나서 찾아보니
이 링크를 참고해서 Car 객체 내부에서 비교를 하도록 하는 것이 좋을 것 같습니다!
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 final InputView inputView; | ||
private final OutputView outputView; | ||
|
||
public MainController() { |
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.
클래스 변수로 받을 때 new로 생성 안하고,
생성자로 MainController가 생성될 때
new로 생성하는 이유가 따로 있나요?!
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.
딱히 이유는 없었던거 같아요.
스프링 프로젝트를 할 때 생성자 주입을 사용하다보니 습관적으로 한거 같아요!
int moveCounts = inputView.inputMoveCounts(); | ||
carGame.registerMoveCounts(moveCounts); | ||
} catch (IllegalArgumentException e) { | ||
outputView.printError(e.getMessage()); |
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.
catch에서 Error 메세지를 출력할 때,
저는 그냥 System.out.println으로 출력했는데
OutputView에 에러를 출력하는 기능을 만들어서
OutputView에게 에러 출력 책임을 맡기게 하는 것 잘 배워갑니다!
private static final String ONLY_NUMBER_REGEX = "^[0-9]+$"; | ||
|
||
public List<String> inputCars() { | ||
System.out.println(Message.INPUT_CAR_MESSAGE); |
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.
입력 문구를 출력하는 것도 출력하는 책임이라고 생각해서
출력 처리를 하는 책임을 가진 OutputView에서 처리하는 것이 좋을 것 같습니다!
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.
흠..저도 프리코스 진행할 때 고민했었는데
저는 View라는 자체가 사용자에게 보여지는 계층이다 보니
입력에 필요한 출력은 어쩔수 없이 InputView에서 담당하는게 맞다고 생각했습니다.
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.
InputView 클래스 자체가 입력에 관한 책임을 가지기 때문에 저도 입력에 필요한 출력은 InputView에서 담당하는것이 좀 더 낫다고 생각합니다 !
System.out.println(Message.OUTPUT_RACE_RESULT); | ||
} | ||
|
||
private void printCar(Car car) { |
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.
포맷으로 출력하는 System.put.printf를 몰랐었는데
건호님 코드 보고 알게 되었습니다! 감사합니다
|
||
private String getMove(int currentPosition) { | ||
StringBuilder stringBuilder = new StringBuilder(); | ||
for (int i = 0; i < currentPosition; i++) { |
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.
반복문 변수도 i 말고 네이밍 해주는 것이 좋을 것 같습니다!
@DisplayName("성공 테스트") | ||
void 자동차_등록_성공_테스트() { | ||
//when | ||
List<String> cars = Arrays.asList("pobi", "woni", "jun"); |
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.
자바 8이라 List.of를 못 써서 직접 List에 add 했었는데,
Arrays.asList가 있었군요! 배워갑니당
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.
저도 처음에 List.of를 사용하려고 했는데 자바 8이라 안되서 당황했는데
Arrays.asList는 사용 가능하더라구요..!
|
||
@Test | ||
@DisplayName("실패시 에러발생") | ||
void 자동차_등록_실패_테스트() { |
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.
정확하게 어떤 이유 때문에 실패하는 테스트인지 네이밍해주는 게 좋을 것 같아요!
'자동차_이름이_비었을_경우_테스트_실패()' 이런 식으로
구체적으로 적어주는 게 좋을 것 같습니다!
|
||
@Test | ||
@DisplayName("이동횟수 등록 실패 테스트") | ||
void 이동횟수_등록_실패_테스트() { |
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.
마찬가지로 '이동_횟수가_0이면_등록_실패' 느낌으로
구체적으로 네이밍 해주시면 좋을 것 같습니다.
또, 테스트할 것이 이동 횟수가 0일때, 음수일 때, 숫자가 아닐 때 등등 여러 조건이
있으므로 @ParameterizedTest
와 @ValueSource
를 사용해서
하나의 메소드에 여러 조건을 추가해서 테스트하는 것이 좋을 것 같습니다!
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 패턴으로 클래스가 하나의 책임만을 가지게 클래스를 분리하면 좋을 것 같아요!
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.
코드 잘봤습니다. 제 실력이 부족해 리뷰에 대해 의문점이나 아닌 것 같은 점이 있으면 말씀해주시면 감사하겠습니다.
this.name = name; | ||
} | ||
|
||
// 추가 기능 구현 | ||
private void validateName(String name) { | ||
if (name.length() > MAX_NAME_LENGTH) { | ||
throw new IllegalArgumentException(Message.CAR_NAME_VALIDATION); |
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.
저도 성훈님이랑 비슷한 의견입니다
for (String carName : cars) { | ||
this.cars.add(new Car(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.
for (String carName : cars) { | |
this.cars.add(new Car(carName)); | |
} | |
this.cars = cars.stream() | |
.map(Car::new) | |
.collect(Collectors.toList()); |
이런식으로 map을 사용하는 코드는 어떠신가요?
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.
이 부분에 대해서는 stream으로 처리할 생각을 못했는데
사용하는 것도 괜찮은거 같습니다.
} | ||
} | ||
|
||
public List<Car> getCars() { |
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 boolean checkIsOver() { | ||
return moveCounts <= 0; |
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.
0보다 작은 경우라고 표현하는 것보다 확실이 0일 경우 끝난다고 표현하는 것이 좋아보입니다
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.
확실히 우석님이 말씀하신대로 작성하는게 side effect 가 없을 거 같네요!
감사합니댜!
if (checkIsOver()) { | ||
throw new IllegalStateException(Message.GAME_OVER); | ||
} |
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.
MainController
에서 while (!carGame.checkIsOver())
하면서 반복하고 있는데 if문으로 한번 더 검증하는 로직은 불필요할 것 같아 보입니다!
String[] inputCars = input.split(CAR_REGEX); | ||
return Arrays.stream(inputCars).collect(Collectors.toList()); |
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.
String[] inputCars = input.split(CAR_REGEX); | |
return Arrays.stream(inputCars).collect(Collectors.toList()); | |
return Arrays.stream(input.split(CAR_REGEX)).collect(Collectors.toList()); |
한번 밖에 쓰이지 않는 변수를 할당하는 것보다 합치는 것이 어떨까요?
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.
놓친거 같아요! 확실히 깔끔해보이네요~
for (String inputCar : inputCars) { | ||
if (inputCar.length() > Car.MAX_NAME_LENGTH) { | ||
throw new IllegalArgumentException(Message.CAR_NAME_VALIDATION); | ||
} | ||
} |
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.
자동차의 이름에 대한 유효성 검증은 Car
객체에서 하는 것이 좋아보이고 실제로 Car 클래스에서 하시고 계셔서 없어져도 좋을 코드 같습니다!
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.
다시보니 검증에 대한 중복이 많네요!
신경써야할 거 같습니다 감사합니다~
for (Car car : cars) { | ||
printCar(car); | ||
} | ||
printNewLine(); |
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.
이런식으로 메서드를 만드는 것이 좋아보이네요 배워갑니다!
|
||
@Test | ||
@DisplayName("성공 테스트") | ||
void 자동차_등록_성공_테스트() { |
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
이 있는데 메서드명을 한글로 하신 이유가 궁금합니다
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 moveOrStop(int fuel) { | ||
validateFuel(fuel); |
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.
저도 같은 의견입니다 !
if (fuel >= MIN_MOVE_FUEL) { | ||
move(); | ||
} | ||
} |
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.
도메인 함수 내부에서 다른 도메인 함수를 호출하는 것 보다
boolean type을 반환하도록 moveOrStop 함수를 변경해 접근해보면 어떤지 제안드립니다 !
public CarGame() { | ||
cars = new ArrayList<>(); | ||
} | ||
|
||
public void registerCar(List<String> cars) { | ||
validateCars(cars); | ||
for (String carName : cars) { | ||
this.cars.add(new Car(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.
Car 객체들을 registerCar
함수가 아닌, 컨트롤러에서 생성해 생성자 주입 방식
을 사용하는 방법을 제안드립니다 !
|
||
private void startRace() { | ||
outputView.printRaceStart(); | ||
while (!carGame.checkIsOver()) { |
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.
"게임을 종료할 수 없는 동안" 이라는 조건보다, "게임이 진행되는 동안"으로 표현한다면 좀 더 직관적일 것 같습니다.
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.
생각을 많이 하고 설계를 했다는 느낌을 많이 받은 것 같습니다 !
예외 검증하는 로직에 고민이 많았는데, @This2sho님 코드 참고하면 도움이 많이 될 것 같습니다 !!
잘 보고 갑니다 :)
@@ -0,0 +1,39 @@ | |||
# 🚗 구현 기능 목록 |
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 registerMoveCounts(int moveCounts) { | ||
validateMoveCounts(moveCounts); | ||
this.moveCounts = moveCounts; | ||
} |
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.
도메인에서 한번 더 검증을 해줄 필요가 있을까? 라는 생각이 있었는데
결국 계층간의 의존성 없이 개발을 하기 위해서는 확실히 한번 더 검증을 해주는 것이 좋다는 느낌이 드는 것 같습니다 :D
잘 배우고 갑니다 !
🚗 구현 기능 목록
자동차
자동차 경주 게임
입력
출력
동작 순서