[1단계 - 자동차 경주 구현] 케빈(박진홍) 미션 제출합니다.#165
Conversation
쉼표 혹은 콜론을 구분자로 가지는 문자열을 구분자를 기준으로 분리한 다음 숫자의 합을 반환한다.
구분자와 숫자를 제외한 문자 혹은 음수가 문자열에 포함되어 있으면 RuntimeException을 던진다
test 클래스에 있던 StringCalulator를 main클래스로 이동한 후, 테스트 확인 완료
10라인 이상의 메소드를 수정하였고, 메소드가 한가지 일만 하도록 수정함
Cars 클래스 생성 테스트
tryCount가 0이면 false를 반환한다.
tdd를 진행하며 사용했던 클래스트들을 test에서 삭재함.
Car 클래스 접근지정자 변경
Livenow14
- 메서드 인라인화 할 수 있는 부분은 인라인화한다. - 인스턴스 변수는 클래스 선언 사이에 공백을 추가한다. - 정적 팩토리 메서드 네이밍 규칙에 맞게 of를 from으로 변경한다.
- 콘솔의 화면을 담당하는 Screen 추상 클래스 및 하위 클래스를 삭제한다. - 기존 InputView와 OutputView가 해당 스크린 클래스들의 역할을 수행한다.
choihz
left a comment
There was a problem hiding this comment.
안녕하세요, 케빈! 리뷰어 코니입니다.
첫 미션을 아주 잘 구현해 주셨네요 🏅 컨벤션 지키기, 메서드 분리, 의미 있는 메서드 네이밍, 기능 목록 정리와 기능별 커밋 모두 훌륭합니다 👍 남겨드린 피드백은 생각해 보시고 다음 단계에서 반영해 주세요.
말씀하신 대로 Cars가 RandomUtils와 강하게 결합되어 있어 테스트 코드 작성이 어려운 상황이네요. 물론 케빈의 제안대로 테스트를 위해 생성자를 오픈할 수도 있겠지만 이번 미션의 경우엔 더 좋은 방법이 있을 것 같아요! 피드백에 남겨드린 힌트를 참고해서, 어떻게 하면 이 결합을 분리할 수 있을지 고민해 보세요.
더 궁금한 점이 있으시다면 언제든 코멘트나 DM 주세요~
| class CarsTest { | ||
|
|
||
| @Test | ||
| void Cars_쉼표로_구분된_문자열_받으면_객체가_생성된다() { |
There was a problem hiding this comment.
메서드 이름은 영어로 간단히 짓고, 처음에 학습 테스트를 할 때 사용했던 @DisplayName으로 한글 이름을 보여주면 어떨까요? 매번 _를 쓸 수고도 줄어들고 가독성도 더 좋아질 것 같네요!
| void Cars_쉼표로_구분된_문자열_받으면_객체가_생성된다() { | ||
| String carNames = "pobi,brown"; | ||
| assertThatCode(() -> Cars.generate(carNames)) | ||
| .doesNotThrowAnyException(); |
There was a problem hiding this comment.
실행한 코드가 어떤 예외도 던지지 않는다는 사실만으로 "객체가 생성"됨을 보장할 수 있을까요?
| @@ -0,0 +1,26 @@ | |||
| package racing.domain.dto; | |||
There was a problem hiding this comment.
dto는 domain의 하위 개념이 아니에요! 패키지 위치가 부적절한 것 같네요~
| public Car(String name) { | ||
| this.name = name; | ||
| this.position = DEFAULT_POSITION; | ||
| validateName(); |
There was a problem hiding this comment.
생성자 안에서 입력값을 검증하고 있군요 👍 하지만, 입력값을 먼저 검증한 이후에 인스턴스 변수에 할당해 주세요!
There was a problem hiding this comment.
페어와 방어적 복사에 대한 개념을 잘못 이해하고 유효성 검증 코드를 짰네요... 😓😓
| } | ||
| } | ||
|
|
||
| public boolean move(int randomNumber) { |
There was a problem hiding this comment.
Car 입장에서, 받는 숫자가 "random"인지 알 필요가 있을까요?
또한 현재 이 메서드는 자동차가 움직였을 때 true, 움직이지 않았을 때 false를 리턴하고 있네요. 그리고 이 반환값은 테스트에서만 쓰이고 있어요! 테스트를 다른 방법으로 할 수 있다면, 이 메서드도 이름이 암시하는 것처럼 움직이는 한 가지 일만 할 수 있지 않을까요?
| public List<String> findWinnerNames() { | ||
| int maxPosition = getMaxPosition(); | ||
| return cars.stream() | ||
| .filter(car -> car.getPosition() == maxPosition) |
There was a problem hiding this comment.
람다와 스트림을 쓰셨군요 👍
여기서는 Car의 위치 정보를 가져와 maxPosition과 직접 비교하고 있는데요, 이 역할을 Car에게 위임하면 어떨까요? 이것을 "메시지를 보낸다"고 표현하곤 하는데요, 이렇게 메시지를 보내면 어떤 장점이 있을지도 생각해 보아요.
src/main/java/racing/docs/요구사항.md
Outdated
| } | ||
|
|
||
| public void race() { | ||
| cars.forEach(car -> car.move(RandomUtils.getRandomNumber(START_NUMBER, END_NUMBER))); |
There was a problem hiding this comment.
Cars가 RandomUtils와 강하게 결합하고 있네요~ 이렇게 되면 Cars의 테스트가 굉장히 어려워지죠!
다음 단계에서 이 결합을 어떻게 분리시킬지 고민해 보고, 테스트 코드도 작성해 보아요! (힌트: 전략 패턴)
| void Car_유효하지_않은_이름_예외가_발생한다(String name) { | ||
| assertThatThrownBy(() -> { | ||
| new Car(name); | ||
| }).isInstanceOf(IllegalArgumentException.class); |
There was a problem hiding this comment.
예외를 던질 때 예외 상황에 맞는 메시지를 담아주면, 아래와 같이 더 정밀하게 검증할 수 있겠죠?
assertThatThrownBy(() -> {
// ...
}).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("이름은 5자 이하만 가능합니다.");| } | ||
| Matcher matcher = PATTERN.matcher(this.name); | ||
| if (!matcher.matches()) { | ||
| throw new IllegalArgumentException(); |
There was a problem hiding this comment.
이름 유효성 검증 👍
하지만 예외에 어떤 메시지도 담겨있지 않네요. 그래서 실제로 프로그램을 실행해 잘못된 이름을 입력했을 때, 사용자는 영문도 모른 채 영어로 된 이상한 메시지만 보게 돼요. 상황에 맞는 적절한 예외 메시지를 담아주면 어떨까요?
안녕하세요?
페어와 함께 다음 내용을 고민했습니다.