Skip to content

[성찬영_BackEnd] 1주차 과제 제출합니다.#5

Open
sungchan12 wants to merge 6 commits intoBCSDLab-Edu:mainfrom
sungchan12:main
Open

[성찬영_BackEnd] 1주차 과제 제출합니다.#5
sungchan12 wants to merge 6 commits intoBCSDLab-Edu:mainfrom
sungchan12:main

Conversation

@sungchan12
Copy link
Copy Markdown

어려웠던 점

  1. Utils에 검증 로직을 모을지, Car 생성자 안에서 처리할지 책임 분리 기준을 정하는 게 고민됐다.
  2. 메서드가 한 가지 일만 하도록 분리하는 것과 indent depth 2 제한을 동시에 지키려다 보니 메서드를 어디까지 쪼개야 할지 판단이 어려웠다.
    질문
    Cars가 출력(printMoveResult, printWinner)까지 하고 있는데, 출력을 별도 클래스로 분리해야 하는게 좋나요?

2. 자동차 이름 5자 초과 검증
3. 자동차 이름 중복 검증
4. 시도 횟수 숫자 여부 검증
5. 시도 횟수 1 미만 검증
 2. 무작위 값 4 이상이면 전진
 2. 최종 우승자 출력
 3. 공동 우승자 , 구분 출력
Copilot AI review requested due to automatic review settings March 29, 2026 13:11
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

자동차 경주 게임의 1주차 요구사항을 충족하기 위해, 입력 검증/도메인 모델/실행 흐름을 추가하고 기능 목록 문서를 작성한 PR입니다.

Changes:

  • 자동차 이름/시도 횟수 입력 검증 로직 추가(Utils)
  • 자동차/자동차 컬렉션 도메인 로직 및 우승자 산출/출력 추가(Car, Cars)
  • 실행 진입/게임 루프 구성 및 기능 목록 문서화(RunRacingGame, Application, docs/README.md)

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/main/java/racingcar/util/Utils.java 이름/숫자 검증 및 이름 분리(중복 체크) 유틸 추가
src/main/java/racingcar/entity/Car.java 자동차 이름/이동 횟수 상태 및 랜덤 이동 로직 추가
src/main/java/racingcar/entity/Cars.java 전체 자동차 이동, 결과/우승자 산출 및 출력 로직 추가
src/main/java/racingcar/RunRacingGame.java 콘솔 입력부터 라운드 진행/출력까지 실행 흐름 구성
src/main/java/racingcar/Application.java main에서 게임 실행 시작하도록 연결
docs/README.md 기능 목록 문서 추가

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

private int moveCnt;

public Car(String name) {
Utils.isValidName(this.name = name);
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

생성자에서 Utils.isValidName(this.name = name)처럼 대입을 인자에서 수행하면 가독성이 떨어지고(필드 초기화/검증 순서가 한 줄에 섞임) 디버깅도 어려워집니다. 먼저 파라미터 name을 검증한 뒤, 검증 통과 시에만 필드에 대입하도록 분리해 주세요.

Suggested change
Utils.isValidName(this.name = name);
Utils.isValidName(name);
this.name = name;

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +25
public void setMoveCnt() {
int RandomNum = Randoms.pickNumberInRange(0, 9);
if (RandomNum >= 4) {
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

setMoveCnt()는 일반적인 setter처럼 보이지만 실제로는 난수에 따라 이동을 수행합니다. API 의미가 불명확해 호출부(Cars.moveAllCars)도 읽기 어려우니 move()/tryMove() 등 동작을 드러내는 이름으로 바꾸고, 로컬 변수명도 Java 컨벤션에 맞게 lowerCamelCase(예: randomNumber)로 정리해 주세요.

Suggested change
public void setMoveCnt() {
int RandomNum = Randoms.pickNumberInRange(0, 9);
if (RandomNum >= 4) {
public void move() {
int randomNumber = Randoms.pickNumberInRange(0, 9);
if (randomNumber >= 4) {

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +9

public class Cars {
private ArrayList<Car> cars;

public Cars(ArrayList<Car> cars) {
this.cars = cars;
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Cars 생성자가 ArrayList<Car>를 그대로 받아 필드에 저장하면 외부에서 전달된 리스트를 수정해 내부 상태가 예기치 않게 변할 수 있습니다. 타입은 List<Car>로 받도록 좁히고, 내부에서는 방어적 복사(예: new ArrayList<>(cars)) 및 final 필드로 불변성을 높여 주세요.

Suggested change
public class Cars {
private ArrayList<Car> cars;
public Cars(ArrayList<Car> cars) {
this.cars = cars;
import java.util.List;
public class Cars {
private final List<Car> cars;
public Cars(List<Car> cars) {
this.cars = new ArrayList<>(cars);

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +23
public void printMoveResult() {
for (Car car : this.cars) {
System.out.println(car.getName() + " : " + "-".repeat(car.getMoveCnt()));
}
System.out.println();
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Cars가 도메인 컬렉션 역할을 하면서 System.out.println로 출력까지 수행하면 도메인 로직과 I/O가 결합되어 테스트/확장이 어려워집니다. 이동 결과/우승자 정보를 문자열 또는 DTO로 반환하고, 출력은 별도 View/Printer(또는 RunRacingGame)로 위임하는 구조로 분리해 주세요.

Copilot uses AI. Check for mistakes.
@@ -3,5 +3,6 @@
public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

템플릿 TODO 주석이 그대로 남아 있어 제출 코드의 완성도를 떨어뜨립니다. 구현이 완료된 상태라면 해당 TODO 주석을 제거해 주세요.

Suggested change
// TODO: 프로그램 구현

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +36
public static String[] splitNames(String input) {
String[] names = input.split(",");
HashSet<String> set = new HashSet<>();
for (String name : names) {
if (!set.add(name)) {
throw new IllegalArgumentException("이름 중복은 허용 안됩니다.");
}
}
return names;
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

String#split(",")은 기본 동작상 뒤쪽의 빈 토큰을 제거합니다. 예를 들어 입력이 "pobi,woni," 또는 "pobi,," 처럼 끝에 쉼표가 오면 마지막 빈 이름이 배열에서 사라져 빈값 검증이 누락될 수 있습니다. trailing empty token을 보존하도록 split에 limit(-1)을 사용하고, 생성된 토큰에 대해 빈 문자열도 예외 처리되도록 해주세요.

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +10
if (name.isBlank() || name.contains(" ")) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

이름 공백 검증이 name.contains(" ")로 되어 있어 탭(\t), 개행(\n) 같은 다른 공백 문자가 포함된 경우는 통과할 수 있습니다. 요구사항이 '공백 포함 불가'라면 Character.isWhitespace/정규식(\s) 등으로 모든 whitespace를 차단하도록 검증을 강화해 주세요.

Suggested change
if (name.isBlank() || name.contains(" ")) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}
if (name.chars().anyMatch(Character::isWhitespace)) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +6
public class Utils {

Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Utils는 static 메서드만 제공하는 유틸 클래스인데 public 기본 생성자가 열려 있어 인스턴스화가 가능합니다. 의도치 않은 사용을 막기 위해 final 클래스로 만들고 private 생성자를 추가하는 방식으로 유틸리티 클래스를 고정해 주세요.

Suggested change
public class Utils {
public final class Utils {
private Utils() {
// Utility class; prevent instantiation
}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

@dh2906 dh2906 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다!
고민하신 부분은 담당 버디님이 잘 남겨주실거에용

import racingcar.util.Utils;

public class Car {
private final String name;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

final 선언을 한 이유가 있으신가요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

이름의 값은 변하지 않는다와 혹시 모를 이름 변경이 되는 것을 막기 위해 final로 선언했습니다.

private int moveCnt;

public Car(String name) {
Utils.isValidName(this.name = name);
Copy link
Copy Markdown
Collaborator

@dh2906 dh2906 Mar 29, 2026

Choose a reason for hiding this comment

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

오 이렇게도 할 수 있었네요?! 👀
그렇지만 이는 가독성이 떨어지므로 분리하는게 좋아보여요

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵 감사합니다!

Comment on lines +24 to +27
int RandomNum = Randoms.pickNumberInRange(0, 9);
if (RandomNum >= 4) {
this.moveCnt += 1;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
int RandomNum = Randoms.pickNumberInRange(0, 9);
if (RandomNum >= 4) {
this.moveCnt += 1;
}
if (Randoms.pickNumberInRange(0, 9) >= 4) {
this.moveCnt += 1;
}

이렇게 할 수도 있어 보여요.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵 감사합니다!

import java.util.ArrayList;

public class Cars {
private ArrayList<Car> cars;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

타입이 List가 아닌 ArrayList로 둔 이유가 있으신가요??

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

java 입문서에서 ArrayList로 선언하는 예제를 보고 그대로 사용했습니다.

Comment on lines +37 to +41
for (Car car : this.cars) {
if (car.getMoveCnt() == max) {
winners.add(car.getName());
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

스트림을 적용해보셔도 좋을 것 같아요 (스트림쓰면 코드가 더 간지나고 예뻐보여요)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵 한번 적용해보겠습니다!

public class Utils {

public static void isValidName(String name) {
if (name.isBlank() || name.contains(" ")) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

isBlank()가 공백 글자도 잘 잡는걸로 아는데 조건을 하나 더 쓴 이유가 있으신가요??

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

이름 중간에 공백이 들어갈 시 isBlank가 검증에 실패할 때도 있어서 contain 조건도 추가했습니다.

Comment on lines +8 to +13
if (name.isBlank() || name.contains(" ")) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}
if (name.length() > 5) {
throw new IllegalArgumentException("5글자 초과했습니다.");
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

이름의 공백 검증, 이름의 글자 수 검증은 서로 다른 역할이라고 생각할 수 있어요!
그러므로 메소드를 분리하는 것도 고려해볼 수 있어요.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵 감사합니다.

if (name.isBlank() || name.contains(" ")) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}
if (name.length() > 5) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

5라는 숫자는 매직넘버라 추후에 요구사항으로 최대 이름의 글자수가 변경된다면 글자수와 관련된 모든 로직에 수정이 필요해질 수 있어요.
그러므로 이는 상수로 분리하는 것을 추천드립니다!

자료 참고해주세요!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵! 감사합니다


public static String[] splitNames(String input) {
String[] names = input.split(",");
HashSet<String> set = new HashSet<>();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Set 자료구조는 무엇이고, HashSet와는 무슨 차이가 있을까요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Set은 인터페이스고 HashSet은 인터페이스를 이용한 클래스로 알고있습니다.

new RunRacingGame().run();
}
}
} No newline at end of file
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

깃허브에 코드를 올릴때는 맨 마지막 라인에 공백이 들어와야 해요!

자료 참고바랍니당

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵 감사합니다.

Copy link
Copy Markdown

@Soundbar91 Soundbar91 left a comment

Choose a reason for hiding this comment

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

첫 과제 고생하셨습니다 ~ 자바 활용 부분을 위주로 리뷰를 남겼습니다.
교육장님 코멘트도 참고하시면 좋을 거 같아요 !

Utils에 검증 로직을 모을지, Car 생성자 안에서 처리할지 책임 분리 기준을 정하는 게 고민됐다.

2주차 과제에서 책임 분리 관련 과제를 진행할 건데, 고민을 하신 부분이 보기 좋습니다 !
저는 Utils으로 별도 로직을 빼는 것보다 Car 생성자 내부에서 처리하는 것이 좋다고 생각합니다.

Car를 생성하는 규칙은 Car 클래스 내부에 위치함으로써 응집성을 높일 수 있고, 명시해주신 패키지 entityutil에 의존하고 있는게 적절하다고 생각하지 않습니다. util이라는 패키지, 클래스는 범용적으로 사용하는 메소드를 모아둔 것이지 특정 클래스에 의존하는 패키지, 클래스는 아니라고 생각하기 때문입니다.

메서드가 한 가지 일만 하도록 분리하는 것과 indent depth 2 제한을 동시에 지키려다 보니 메서드를 어디까지 쪼개야 할지 판단이 어려웠다.

코드에서 잘 쪼개신 거 같아요 ! 리드미에서 적힌 것 처럼, 메소드에 기능이 한개 이상이 되버리면 보통 쪼개는 거 같아요. dpeth를 줄이는 방법으로 코멘트에 작성한 것 처럼 자바에서 제공해주는 메소드로 빼는 방법도 있을 거 같아요.

Cars가 출력(printMoveResult, printWinner)까지 하고 있는데, 출력을 별도 클래스로 분리해야 하는게 좋나요?

이 부분도 2주차에서 진행할 거 같은데, 질문 좋습니다 👍
우선, 찬영님이 Cars 클래스를 추가하신 목적이 무엇인지 생각하면 좋을 거 같아요. 목적에 출력까지도 있다면 찬영님이 그렇게 생각하신 이유도 궁금하네요 👀

저는 Cars에서 반환값으로 결과를 리턴한다면, Cars에서 출력 로직을 안 가져도 된다고 생각합니다. 그 출력값을 누가 받아서 출력을 하면 되기 때문입니다. 그게 별도의 클래스가 될 수도 있고, 만들어주신 RunRacingGame 클래스가 될 수도 있을 거 같아요.

클래스를 무엇을 위해 추가했는지, 너무 많은 일을 하고 있거나 여기서 하지 않아도 되는 행위를 하고 있는지를 한 번 생각해보시면 좋을 거 같아요 ! 이 고민의 결과를 2주차에 잘 녹이시면 좋을 거 같습니다 👍

Comment on lines +25 to +33
private int findMaxMoveCnt() {
int max = 0;
for (Car car : this.cars) {
if (car.getMoveCnt() > max) {
max = car.getMoveCnt();
}
}
return max;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

depth를 더 줄인다면 이렇게도 될 거 같아요 !
Java에서 기본적으로 제공해주는 유용한 메소드들도 많아서, 한 번 찾아보면 좋을 거 같아요 👍

Suggested change
private int findMaxMoveCnt() {
int max = 0;
for (Car car : this.cars) {
if (car.getMoveCnt() > max) {
max = car.getMoveCnt();
}
}
return max;
}
private int findMaxMoveCnt() {
int max = -1;
for (Car car : this.cars) {
max = Math.max(max, car.getMoveCnt();
}
return max;
}

import static racingcar.util.Utils.splitNames;

public class RunRacingGame {
public void run() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.

현재 run() 메소드는 너무 많은 일을 하고 있는 거 같아요 !
부분부분 메소드로 분리해보면 어떨까요 ?


public void printMoveResult() {
for (Car car : this.cars) {
System.out.println(car.getName() + " : " + "-".repeat(car.getMoveCnt()));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

String의 repeat 메소드 좋습니다 !
자바에도 형식을 지정해서 출력하는 메소드 System.out.printf()가 존재합니다. 추가적으로 알아보면 좋을 거 같아요 !

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.

4 participants