[우아한테크코스 백엔드 4기] 레벨1 - "자동차 경주 구현" 회고

헌치·2022년 2월 23일
2

우아한테크코스

목록 보기
9/30
post-thumbnail

🔗 관련 링크

깃허브 링크
작성한 코드


⚙️ 구현 기능 목록

입력

  • 경주 할 자동차의 이름을 입력받는다.
  • 이름을 쉼표 기준으로 분리한다.
  • 사용자가 잘못된 값을 입력할 경우 Exception를 발생시키고 프로그램을 종료한다.
    • 빈 문자열(null)이 입력된 경우
    • 이름이 5자 보다 클 경우
    • 이름이 중복된 경우
    • 입력된 이름이 하나일 경우
    • 공백(들) 혹은 ','로만 이루어진 문자열이 입력된 경우
    • 이름에 특수문자가 들어간 경우 (다만, '_' 제외)
  • 시도할 횟수를 입력받는다.
  • 사용자가 잘못된 값을 입력할 경우 Exception를 발생시키고 프로그램을 종료한다.
    • 빈 문자열(null)이 입력된 경우
    • 숫자가 아닐 경우
    • 0 이하의 값이 입력된 경우

경기진행

  • 입력 받은 횟수만큼 라운드을 반복한다.
  • 각 자동차마다
    • 0~9 사이의 랜덤 값을 구한다.
    • 4 이상인 경우 전진한다.
  • 각 라운드마다 결과를 출력한다.

경기종료

  • 게임이 끝난 후 가장 많이 전진한 위치를 구한다.
  • 최대 위치 값에 해당하는 우승한 자동차 목록을 구한다.
  • 우승자(들)를 출력한다.

⛳ 피드백

@코딩 컨벤션 지키기

1. 구현 순서

  1. 상수(static final String...)
  2. 클래스 변수(static int...)
  3. 인스턴스 변수(String)
  4. 생성자
  5. 정적 팩토리 메서드(of()...)
  6. 주요 로직 메서드
  7. getter
  8. override(equals())

2. 변수 이름에 자료형은 사용하지 않는다

  • numList, arrayString

3. 상수

  • CONSTANT_CASE
  • static final String...

4. 패키지 구조

  • domain
    • DTO
    • VO
  • controller
  • view
  • service
  • utils
    • validator
  • exception

@값의 변경 막기

1. 인스턴스 변수 private

2. final 키워드 사용, 생성자로 값 초기화

public class Car {
  private final String name;

  public Car(final String name) {
    this.name = name;
  }
}

3. setter x

4. getter o

  • 도메인-도메인 : x
  • 도메인-컨트롤러 : ?
  • 도메인-컨트롤러-뷰 : o(Dto)

@테스트

1. 테스트 메서드 의미 알려주는게 명확

  • 한글 변수명
  • @SuppressWarnings("NonAsciiCharacters") 태그 추가

2. extracting 사용

  • Collection 속 VO/DTO 값 추출 가능
List<Human> list = new ArrayList<>(Arrays.asList(human1,human2));

assertThat(list)
	.extracting("name")
	.contains("hunch", "judi");

3. 메서드 시그니처 분리

  • 테스트메서드에서 변경될 값을 로직메서드 인자로 뺀다
public void move(int number) { //랜덤값 number을 밖으로 이동
    if (number >= MOVABLE_LOWER_BOUND) {
        position++;
    }
}

4. 인터페이스 분리

  • 전략 패턴을 활용한다
    • 파라미터에 인터페이스를 가져온다
    • 테스트에 쓸 값을 @override 된 메서드를 통해 가져온다

//전략1 사용
public void moveCarByRandomNumber() {
    final NumberGenerator randomGenerator = new RandomNumberGenerator(); 
    move(randomGenerator);
}

//전략2 사용
public void goCar() {
    final NumberGenerator goGenerator = new GoNumberGenerator(); 
    move(goGenerator);
}

//전략이 넘어올 메서드
public void move(NumberGenerator numberGenerator) {
    final int number = numberGenerator.generate();
    if (number >= MOVABLE_LOWER_BOUND) {
        position++;
    }
}

//인터페이스
public interface NumberGenerator {
    int generate();
}

//전략1 : 랜덤이동
public class RandomNumberGenerator implements NumberGenerator {
    private static final int RANDOM_NUMBER_UPPER_BOUND = 10;
    @Override
    public int generate() {
        return random.nextInt(RANDOM_NUMBER_UPPER_BOUND);
    }
}

//전략2 : 무조건 이동
public class GoNumberGenerator implements NumberGenerator {
    private static final int GO_NUMBER = 4;
    @Override
    public int generate() {
        return GO_NUMBER;
    }
}

5. 조건문/sout/while 등 사용 X

@데이터 저장 방법

1. VO(Value Object)

  • 값 자체를 표현하는 객체
  • Read–Only(불변 객체)
  • 객체들의 주소가 달라도 값이 같으면 동일
    - equals(), hashCode() 사용
  • 대부분의 도메인
  • 값 비교는 Comparable implementcompareTo() 사용
public class Position implements Comparable<Car> {
	//...
	@Override
    public int compareTo(Position position) {
        return Integer.compare(this.position, o.get());
    }
}

2. DTO(Data Transfer Object)

  • 전송되는 데이터의 컨테이너
  • 비지니스 로직까지 담아서 사용 가능
  • 도메인과 같을수도, 다를수도 있음
  • modelview로 넘어오는 것 제한
  • 보통 controller에서 view로 값 전송할 때 사용

참고링크 : DTOvsVO

@ 정적 팩토리 메서드

1. 뜻

  • Static Factory Method
  • 객체 생성의 역할을 하는 클래스 메서드
  • 도메인에서 “객체 생성”의 역할 자체가 중요한 경우 사용

2. 예시

public class LottoFactory() {
  private static final int LOTTO_SIZE = 6;

  private static List<LottoNumber> allLottoNumbers = ...; // 1~45까지의 로또 넘버

  public static Lotto createAutoLotto() {
    Collections.shuffle(allLottoNumbers);
    return new Lotto(allLottoNumbers.stream()
            .limit(LOTTO_SIZE)
            .collect(Collectors.toList()));
  }

  public static Lotto createManualLotto(List<LottoNumber> lottoNumbers) {
    return new Lotto(lottoNumbers);
  }
  ...
}

3. 장점

  • 생성자별 이름을 만들수 있다
  • 호출할 때마다 새로운 객체를 생성할 필요가 없다
  • 하위 자료형 객체를 반환할 수 있다
  • 객체 생성을 캡슐화할 수 있다
public class Level {
  ...
  public static Level of(int score) {
    if (score < 50) {
      return new Basic();
    } else if (score < 80) {
      return new Intermediate();
    } else {
      return new Advanced();
    }
  }
  ...
}

4. 네이밍 컨벤션

  • from : 매개 변수 1개
  • of : 매개 변수 2개 이상
  • getInstance | instance : 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있음
  • newInstance | create : 새로운 인스턴스를 생성
  • get[OtherType] : 다른 타입의 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있음.
  • new[OtherType] : 다른 타입의 새로운 인스턴스를 생성.

🖋 소감

수없는 시행착오와 질문의 반복

  1. 커리큘럼의 탄탄함을 몸소 느꼈다
  2. 피드백 루프 속에서 성장했다
  3. 크루들이 성실한 인싸임을 알았다
profile
🌱 함께 자라는 중입니다 🚀 rerub0831@gmail.com

2개의 댓글

comment-user-thumbnail
2022년 2월 23일

정리 최고네요!! 감사합니다 😁👍👍

1개의 답글