본문 바로가기
Memo/우테코 4기

[우테코] 로또 미션 2단계 학습 로그

by 연로그 2022. 3. 5.
반응형

블로그 유입ㅋㅋㅋ 제 블로그에서 복 잘 받아가셨나요?

 


목차

1. GitHub 저장소

2. 새로운 요구사항

3. 리팩토링

4. 생각하기


 


1. GitHub 저장소

step 1(리팩토링 전): https://github.com/yeon-06/java-lotto/tree/step1

step 2(리팩토링 후): https://github.com/yeon-06/java-lotto/tree/step2

Pull Request: https://github.com/woowacourse/java-lotto/pull/454

 


2. 새로운 요구사항

 

 

수동 로또

  • (e) 구입한 금액보다 많이 구매했는지 확인
  • 수동으로 구매할 로또 개수 입력
  • 수동 로또 번호 입력

 


3. 리팩토링

 

3-1. String.format() 사용

int MIN = 1;
int MAX = 45;

// AS-IS
String NUMBER_RANGE_ERROR = "로또 숫자는 " + MIN + " 이상 " + MAX +" 이하의 숫자만 가능합니다.";

// TO-BE
String NUMBER_RANGE_ERROR = String.format("로또 숫자는 %d 이상 %d 이하의 숫자만 가능합니다.", MIN, MAX);

 

3-2. 캐싱된 인스턴스의 자료형 Map으로 변경

// AS-IS
private static final LottoNumber[] cacheLottoNumber = new LottoNumber[MAX + 1];

// TO-BE
private static final Map<Integer, LottoNumber> cacheLottoNumber = new HashMap<>();

👉 현재는 저장되는 값도 저장하는 값의 의미도 숫자다.

하지만 특정 문자열 등이 캐싱되어야 하는 경우 등에서 Array나 List 등은 값을 꺼내올 때 의미를 분명히 하는데 한계가 있다고 판단했다.

 

3-3. 테스트 코드 given, when, then 분리

  • given: 테스트를 위한 준비 과정
  • when: 테스트를 하고자 하는 행위(기능)
  • then: 검증

 

예제

@Test
@DisplayName("LottoTicket 추가")
void addLottoTicket() {
    // given
    LottoTicket lottoTicket1 = LottoTicket.createAutoLottoTicket(3);
    LottoTicket lottoTicket2 = LottoTicket.createAutoLottoTicket(2);

    // when
    lottoTicket1.addLottoTicket(lottoTicket2);

    // then
    int lottoCount = lottoTicket1.getLottoTicket().size();
    assertThat(lottoCount).isEqualTo(5);
}

 

3-4. @ParameterizedTest와 파라미터 여러개 받기

별도로 작성한 포스팅이 있어 생략한다.

👉 https://yeonyeon.tistory.com/198

 

[JUnit5] 중복되는 테스트 코드 줄이기

목차 개요 @ParameterizedTest란? 예제 코드 -@ValueSource 파라미터를 여러개 받고 싶다면? - @CsvSource 사용자 정의 클래스를 파라미터로 넣고 싶다면? - @MethodSource 👀 개요 테스트 코드를 작성하다 보면..

yeonyeon.tistory.com

 

3-5. Predicate의 활용

별도로 작성한 포스팅이 있어 생략한다.

👉 https://yeonyeon.tistory.com/200

 

[Java] Predicate란?

🤔 개요 우테코 오늘자 강의에서 BiPredicate라는 개념을 처음 들어보았다. Predicate란 무엇인지, 언제 사용하는 것인지 그리고 내 코드에 적용하는 과정까지를 담아본다. 생각보다 어렵지 않다. 설

yeonyeon.tistory.com

 

 


4. 생각하기

📑: 상황, 🙋‍♀️: 연로그(본인), 🙍‍♂️: 닉(리뷰어)

 

4-1. 정적 팩토리 메소드 - 이름 붙이기

📑 LottoTicket의 발급 방법이 수동, 자동 두 가지가 생겼다.

여기서 자동 발급을 하는 경우 new 키워드를 통해 생성자 호출할 때 자동 발급할 티켓 개수를 넘겨주었다.

 

🙍‍♂️ LottoTicket을 만드는데 생성자에 단순한 숫자를 넣어주니까 의미 전달이 조금 약한 것 같아요.
(물론 autoTicketCount 라는 변수명으로 어느정도 유추할 수는 있겠지만)
정적 팩토리 메서드를 사용해서 의미를 명확하게 해보면 어떨까요? :)

 

🙋‍♀️ 리팩토링 된 코드.

자동 로또를 발급 받는지 수동 로또를 발급 받는지 의미가 명확해졌다.

public class LottoTicket {
    private final List<LottoNumbers> lottoTicket;

    private LottoTicket(final List<LottoNumbers> lottoTicket) {
        this.lottoTicket = lottoTicket;
    }

    public static LottoTicket createAutoLottoTicket(int count) {
        return new LottoTicket(generateTickets(count));
    }

    private static List<LottoNumbers> generateTickets(int count) { ... }

    public static LottoTicket createManualLottoTicket(List<LottoNumbers> lottoTicket) {
        return new LottoTicket(lottoTicket);
    }
}

 

4-2. 테스트 확인 또 확인

📑 누락된 테스트 케이스를 급하게 추가하다가 다른 테스트 케이스가 깨지는 경우가 생겼다.

제출 전 전체 테스트 다 통과하는지 꼭꼭 확인 또 확인하기😭

 

4-3. 적절한 VO의 생성

🙋‍♀️ 수동 로또 개수를 검증하는 로직을 분리하고 싶어서 ManualLottoCount라는 vo를 생성했습니다.
다만 ManualLottoCount에 저장한 값이 계속 필요해서 사용할때마다 getValue()를 호출하게 되네요.
이게 적절한 VO의 생성이 맞나?라는 의문이 계속 들어요😂

 

🙍‍♂️ 값을 사용해야 하는 시점에서는 어쩔 수 없죠 ㅎㅎ
그게 아니라면 public 메서드를 열어서 내부에서 처리하게끔 해야하는데, 아래 count 계산 로직의 경우 책임 분리의 관점에서 애매한 부분이 있을수도 있겠네요 :)

 

4-4. protecteddefault

🙋‍♀️ default와 protected 중 고민했으나 나중에 LottoNumber을 상속하는 클래스가 생기면 해당 클래스의 패키지에서도 사용할 일이 생기지 않을까? 라고 예상했습니다.
하지만 LottoNumber을 상속하는 경우가 생기지 않을 것 같기도 하고... 뭘 사용해야 더 적절한지에 대한 고민이 생겼습니다.
닉은 default와 protected를 사용하는 기준 같은게 따로 있으실까요?

 

🙍‍♂️ 일단 저는 상수 같은 경우는 public으로 열긴 하는데요. (불변 상수기 때문에 접근제어를 fit하게 해봤자 큰 의미 없다고 생각해서)
저도 해당 시점에 판단해서 상속이 필요할 것 같으면 protected, 패키지 내에서만 사용할 것 같으면 default로 둡니다.
사실 자바에서 패키지 기반으로 접근 제어를 한다는 사실이 맘에 들진 않아요 ㅋㅋ (코틀린을 쓰면 그런 고민할 필요가 없습니다 갓틀린 짱짱..)

답은 없으니 각 제어자 목적에 맞게 고민하고 판단하셔서 결정하시면 됩니다 :)

 

👉 이 부분에 대해서는 별도로 좀 더 자세히 공부해보았다.

https://yeonyeon.tistory.com/203

 

[Java] 접근 권한을 최소화해야 하는 이유

이 포스팅에 들어가기 앞서 잘 설계된 컴포넌트란 무엇인가?에 대해서 생각해보도록 하자. 우리가 컴포넌트를 설계할 때 중요한 것이 뭘까? 어떤 컴포넌트를 잘 설계되었다고 표현할까? ✨ 잘

yeonyeon.tistory.com

 

반응형