Skip to content

Conversation

@SuperBlueBloodMoon
Copy link

@SuperBlueBloodMoon SuperBlueBloodMoon commented Aug 25, 2025

모델 구조
Car: 한 자동차의 이름(racerName)과 현재 위치(position)를 필드로 가짐.
Cars: 경주에 참여하는 모든 자동차를 List로 관리.
입력 처리
InputView는 사용자에게 자동차 이름과 시도 횟수를 입력받아 List으로 RacingCarController에 전달.
RacingCarController는 NameSplitterService로 이름을 쉼표 기준으로 분리하고, NameValidationService로 유효성을 검사. 기준에 맞지 않으면 에러 발생, 맞으면 List 반환.
모델 생성
CreateCarService는 받은 이름 리스트로 각 Car 객체를 생성하고, 이를 Cars 객체로 묶어 반환.
시도 횟수 처리
ParseService를 이용해 입력 받은 시도 횟수를 Integer로 변환.
게임 진행
반복문을 통해 라운드마다 GameService와 OutputView를 사용.
GameService는 RandomService, ClassificationService, MovementService를 활용하여:
랜덤 값을 생성
기준(4 이상) 판단
해당 자동차 위치 전진
한 라운드가 끝나면 OutputView로 현재 상태 출력.
결과 산출
ResultService가 Cars를 이용해 최대 위치를 계산하고, 해당 위치에 있는 자동차 이름을 리스트로 반환.
반환된 리스트를 OutputView로 전달하여 최종 우승자 출력.

의도
이 프로젝트는 MVC 구조와 단일 책임 원칙을 기준으로 제작함. 컨트롤러에서는 게임의 흐름을 제어하고, 필요한 기능들은 서비스로 구현. 각각의 서비스는 단일 책임 원칙을 준수하기 위해 하나의 책임만을 가지고 있음.

궁금증
이 프로젝트의 Service가 많이 존재하고 있는데 제작자는 모든 기능을 구별하고 단일 책임 원칙을 위해 각각의 Service를 구현했음. 근데 이러한 기능들을 각각 나눠서 작성하는 것이 맞는 설계인지 궁금함. (Service 객체의 구현이 많아지는 문제)

@gmltn9233
Copy link

RacingCar 문제 제출

eva

Copy link

@gmltn9233 gmltn9233 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

미션 수행하느라 수고하셨습니다.
우아한 테크코스 클린코드 원칙 을 읽어보신후 이러한 원칙들을 왜 지켜야하는지 고민하며 리뷰를 살펴보면 더 좋은 공부가 될 것 같습니다.

이번주 미션 총평

1. 단일책임원칙 올바르게 이해하기

현재 코드를 보면 Service가 9개입니다. 이전 리뷰에서 단일책임 원칙에대해서 공부하라고 리뷰드렸었는데, 단일책임 원칙은 "책임"을 분리하라는거지 "기능"을 분리하라는게 아닙니다.

"책임"이 무엇을 의미할까요?
자동차가 움직이는것은 누구의 책임일까요? 자동차에게 명령을 내리는건 누구의 책임일까요?
책임의 주체가 누구인지 고민하다보면 객체지향에 대해서 한발짝 더 가까이 다가설 수 있을거 같습니다.

image

2. MVC 패턴

현재 Controller, Model, Service, View 를 사용하신것을 보니 MVC 패턴을 따라 설계한것으로 생각됩니다. MVC 패턴에서 각 레이어의 책임은 무엇일까요?

MVC 패턴 , 5 Layer 패턴
글을 참고해서 다시 생각해보세요. 현재는 Service 가 너무 많은 책임을 지니고 있습니다.

다음주 미션 과제

1. 테스트 코드 작성해보기

현재 테스트 코드가 하나도 작성되어있지 않습니다. 테스트 코드를 작성하는 연습을 해보세요.

2. 클린코드 원칙 차근차근 적용해보기

모든 원칙을 반드시 적용하라는것은 아닙니다. 하지만 원칙들이 왜 있는지 고민하다보면 더 좋은 코드가 나올거 같습니다.

3. DTO, Enum, 커스텀 예외 익히기

이건 보너스입니다.

Comment on lines +5 to +20
public class NameValidationService {
public List<String> validateName(List<String> racerNames) {
for (String name : racerNames) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("이름은 비어있을 수 없습니다. 애플리케이션 종료.");
}
if (name.matches(".*\\s.*")) {
throw new IllegalArgumentException("이름에는 공백을 입력할 수 없습니다. 애플리케이션 종료.");
}
if (name.length() > 5) {
throw new IllegalArgumentException(name + "의 길이가 5글자 이상입니다. 애플리케이션 종료.");
}
}
return racerNames;
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum으로 에러 메시지를 관리하는건 어떨까요?

Comment on lines +39 to +40
List<String> carNames =
nameValidationService.validateName(nameSplitterService.nameSplit(input.getFirst()));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드 한줄에서 여러개의 . 이 사용되었습니다. 캡슐화와 관련하여 디미터의 법칙에 대해서 공부해보세요.

int roundCount = parseService.parseInt(input.getLast());

for (int round = 0; round < roundCount; round++) {
gameService.gameRound(carRacers);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드명은 명사보단 동사로 지어 어떤 동작을 수행하는지 나타내야합니다.

}
List<String> winnerNames = resultService.findWinners(carRacers);

outputView.output_winner(winnerNames);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Java 에서는 카멜 케이스 표기법을 준수해주세요.

Comment on lines +16 to +18
public int size() {
return racers.size();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드명 동사로 바꿔주세요.

Comment on lines +20 to +28
public int getMaxPosition() {
int maxPosition = 0;
for (Car racer : racers) {
if (maxPosition < racer.getPosition()) {
maxPosition = racer.getPosition();
}
}
return maxPosition;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good.
어떤 포인트에서 good이라 남겼는지 고민해보세요.

Comment on lines +11 to +16
if (racingCarRandomValue > 3) {
result.add(1);
} else {
result.add(0);
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이전 미션 리뷰를 안읽으셨나요?

Comment on lines +8 to +16
public class RandomService {
public List<Integer> randomValue(int numberOfCars) {
List<Integer> carsRandomValue = new ArrayList<>();
for (int index = 0; index < numberOfCars; index++) {
carsRandomValue.add(Randoms.pickNumberInRange(0, 9));
}
return carsRandomValue;
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이와 같이 랜덤 넘버를 생성하는 로직을 구현했을때, 해당 메서드를 테스트하려면 어떻게 해야할까요? 테스트 하기 쉬운, 확장성 있는 방법이 없을지 고민해보세요.

Comment on lines +110 to +113
-   JUnit 5와 AssertJ를 이용하여 정리한 기능 목록이 정상적으로 작동하는지 테스트 코드로 확인한다.


-   테스트 도구 사용법이 익숙하지 않다면 아래 문서를 참고하여 학습한 후 테스트를 구현한다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"테스트 코드로 확인한다."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants