[플레이그라운드] TDD, 클린 코드 (6) - 자동차 경주 (피드백 후)
2023, Oct 10
목차
피드백 강의 영상 시청 후 변경한 부분을 써보겠다.
전체 코드
https://github.com/Kyuyoung11/java-racingcar-playground
기능 목록
[기능 목록]
1. 각 자동차 이름 부여
1-1. 자동차 이름 입력 받기 (* 5자 초과 안됨)
1-2. , 기준으로 자동차 이름 구분
2. 시도할 횟수 입력
3. 시도횟수 만큼 자동차 전진 시도
3-1. 0~9 random값 구하기
3-2. 4이상이면 전진
3-3. 전진
3-4. 출력
4. 우승자 출력
1. Car 전진 후 출력하는 메소드 분리
기존에는 Car에 toString을 Override하여 구현하였다.
[수정 전 코드]
public class Car {
...
@Override
public String toString() {
StringBuilder distanceBuilder = new StringBuilder();
for (int i=0; i<this.distance; i++)
distanceBuilder.append('-');
return name + " : " + distanceBuilder.toString();
}
}
해당 코드의 문제점
- 비즈니스로직(Car 기존 메소드)과 UI로직(view용 print)가 분리되어야 함.
- distance를 ‘-‘로 표현하는건 view용 print니까 단일 책임 원칙 위배~
[수정 후 코드]
public class RacingPrinter {
public static String makeHyphens(int count) {
StringBuilder sb = new StringBuilder();
for (int i=0; i<count; i++) {
sb.append('-');
}
return sb.toString();
}
public static void printCar(Car car) {
System.out.print(car.getName()+" : " + makeHyphens(car.getPositionValue()));
}
}
2. Strategy패턴 이용한 MovingStrategy 구현
장점
- Random 관련된 메소드를 분리시켜서, 테스트 불가능한 메소드를 최소화할 수 있음
public class Car {
...
public void move(MovingStrategy movingStrategy) {
if (movingStrategy.movable())
this.position = this.position.add();
}
...
}
move 메소드를 호출하면서, 클래스를 따로 써줄 수 있음
car.move(new RandomMovingStrategy());
car.move(() -> true);
//이것과 동일한 코드
car.move(new MovingStrategy() {
@Override
public boolean movable(){
return true;
}
});
이걸 단위테스트코드에 적용하면 아주 용이하다~~
3. 원시값 포장
Car의 멤버변수들을 클래스로 구현
public class Car {
private final Name name;
private Position position;
...
}
public class Name {
private static final int MAX_NAME_LENGTH = 5;
private final String name;
public Name(String name) {
_validate(name);
this.name = name;
}
private void _validate(String name) {
if (name.length()<=0) {
throw new IllegalArgumentException("자동차 이름은 1자 이상이어야 합니다.");
}
if (name.length()>=MAX_NAME_LENGTH) {
throw new IllegalArgumentException("자동차 이름은 "+MAX_NAME_LENGTH+"자를 초과할 수 없습니다.");
}
}
...
}
장점 (주관적인 의견임)
- MAX_NAME_LENGTH 같은 상수가 좀 더 클래스 자체와 어울리는 위치에 온 기분이다.
- validate 메소드까지 Car에서 가져올 수 있으니, 역할이 분명해진 것 같다.
강의를 통해 알게 된 내용
- Strategy 패턴을 적절히 사용함으로써 테스트가 어려운 로직 분리
- 일급 컬렉션
- 원시값 포장
- GIT 커밋 메시지에 더 신경쓰기
나는 아직 멀었다