장's 개발생각

[개발생각] 우아한테크코스 5기 3주차 로또 후기

장아장 2022. 11. 18. 19:04

이전 게시물은 [개발공부] 우아한테크코스 5기 2주차 숫자야구 후기 를 보시면 됩니다!!

Source Code : https://github.com/JangAJang/java-lotto/tree/JangAJang

 

한장 요약

6전공중에 2전공의 2차시험으로 우테코 제출마감일 저녁에 우테코에 대한 생각과 시험공부를 병행하고,

이도저도 아니게 모든게 마무리 되어 마음에 상당히 들지 않는 한 주를 보냈다. 

 

계속해서 시험공부를 끝냈다고 생각했지만, 다시 보면 기억나지 않는 부분이 있었고

우아한테크코스도 이정도면 괜찮지 않을까 했지만 계속해서 마음에 들지 않는 부분이 생겼다. 

계속 혼자 해치웠나...? 하다가 아니 이게 뭐야 도대체 하고...이게 인생의 무한참조인가...!

 

저번 주차와 마찬가지로 기능 목록을 만들고 테스트를 구현한 후 이에 맞게 코드를 발전시켰다. 

단지 저번 주차에서 조금 더 발전 시키고 싶었던 것은,

  1. 생성자를 최대한 써먹어보자 : 생성자가 그저 생성만 하는 것이 아니라, 데이터를 초기화 시킨다는 것을 다시 생각해보자
  2. 모든 연산이 서비스에서 되던 과거의 코드에서 벗어나 보자

라는 목적을 가지고 이번 주차를 시작했다. 

 

DDD에 대한 유튜브를 찾아보기도 하다가, 조금 더 말이 되는 방식으로 로직을 구상해보았다. 

이번 로또게임의 기준으로는

  1. 플레이어가 로또를 구매한다. 
    1. 플레이어가 금액을 입력한다. 
    2. 플레이어가 입력한 금액을 구매금액으로 저장한다. 
    3. 플레이어가 입력한 금액/1000만큼의 로또를 무작위로 생성한다. 
  2. 당첨 번호를 입력한다. 
    1. 당첨번호를 저장한다. 
  3. 보너스 번호를 입력한다. 
    1. 보너스 번호가 당첨번호에 없던 번호일 경우에만 저장한다. 
  4. 플레이어와 컴퓨터를 비교해 결과를 출력한다. 
    1. 플레이어의 로또를 하나씩 당첨번호와 보너스 번호와 비교해 등수를 저장한다. 
    2. 플레이어의 로또를 하나씩 당첨번호와 보너스 번호와 비교해 등수의 금액을 추가한다. 
    3. 등수와 해당 등수의 로또개수를 해시맵으로 반환한다. 
    4. 총 당첨금을 로또 구매금액으로 나누고 *100해서 소수점 첫째 자리까지 반환한다. 
    5. 해시맵과 수익률을 출력한다. 

이렇게 논리적으로 정리를 했다. 

그런데 우테코에서 Lotto라는 도메인을 주었다. 

public class Lotto {
    private final List<Integer> numbers;

    public Lotto(List<Integer> numbers) {
        validate(numbers);
        this.numbers = numbers;
    }

    private void validate(List<Integer> numbers) {
        if (numbers.size() != 6) {
            throw new IllegalArgumentException();
        }
    }

    // TODO: 추가 기능 구현
}

이걸 보고 생각한 것은, JPA의 임베디드 타입처럼, 도메인들을 만들고 이를 엔티티라고 부르는 객체가 모두 불러와 사용하면 어떨까? 라는 생각을 했다. 

 

이러한 생각을 토대로 Lotto(로또 번호), BonusNumber(보너스 넘버), Winning(당첨등수들), Profit(수익률) 도메인을 만들었다. 

  • 플레이어 : List<Lotto>, Winning, Profit
  • 컴퓨터 : Lotto, BonusNumber

이렇게 도메인들을 이용해 객체를 만들고, 이들을 위에 있는 동사들로 객체 내에서 로직을 구현했다. 

예를 들면

public void buyTickets(long payment){
    payTickets(payment);
    makeTickets(countTickets(payment));
}

private void payTickets(long payment){
    playerProfit.checkPayment(payment);
}

private int countTickets(long payment){
    return (int)(payment / 1000L);
}

private void makeTickets(int ticketCount){
    for(int count = 0; count < ticketCount; count++){
        playerLotto.add(new Lotto(Randoms.pickUniqueNumbersInRange(1, 45, 6)));
    }
}

이런 식으로 플레이어가 로또 구매금액을 입력하고 구매를 한다는 것은, 

  1. 수익률 계산을 위해 구매 금액을 저장
  2. 구매금액 / 1000 개 만큼 로또를 생성

의 과정을 가지기에, 이를 플레이어라는 객체 안에 묶어두었다. 

플레이어 안에서 처리할 수 있는 로직들을 플레이어에서 처리하고, 컴퓨터에서 처리해야 할 로직들을 컴퓨터에서 처리하려고 노력했다. 

 

또한, 플레이어와 컴퓨터의 숫자를 비교하는 부분을 위해 서비스를 만들어 서비스에서 처리하게 시켰다. 

상수들이 반복적으로 사용되는 등수를 당첨금으로 만드는 부분도 따로 로직을 클래스로 구현했다.

 

사실 이제부터 아쉬운 부분들이다. 

  1. enum 클래스를 제대로 써먹지 못했다. enum에 몇개가 같아야 당첨인지, 그리고 당첨금은 얼마인지를 다 매핑해두었다면 훨씬 수월할 문제를 제대로 써먹지 못했다. 
  2. Domain이라고 명시되어 있는 부분들은 생성자를 써먹었지만, Player, Computer의 생성자는 충분히 써먹지 못했다. Computer 생성자에 View에서 받는 로또 번호와 보너스 넘버를 바로 집어넣어 생성자 처리하면 어떨까 하는 후회도 된다. 
  3. 예외처리시 행동 방법을 잘못 생각했다.

1, 2번의 문제는 계속해서 리펙토링 해야겠지만, 3번의 문제에 대해 조금 더 이야기를 해봐야 할 것 같다. 

사용자가 잘못된 값을 입력할 경우 IllegalArgumentException를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 종료한다.

이 문구를 보고, 발생되었을 때 에러 메시지를 출력 후 종료한다는 것이, IllegalArgumentException으로 종료된다는 것인줄 알고 있었다. 

이에 대해 인터넷으로 검색해본 결과, 이를 어떻게 처리하는게 맞는지 느꼈다. 

 

일단, 우리가 예기치 못한 상황으로 버그가 있는 것은 자바 기준 빨간 에러메시지를 통해 알 수 있다. 

그런데, 의도한 예외사항에 대해서 빨간 에러메시지가 있는것이 맞는가? 라는 생각을 해봐야 했다. 

이를 위해, try-catch를 통해 의도했다면 의도대로 종료되게 만드는 것이 맞다고 생각된다. 

try{
    lotteryController.runLottoMatch();
} catch (IllegalArgumentException exception){

}

이런식으로 캐치를 해서 종료를 시키는 것이 문제 없이 종료된 다는 것을 느꼈다. 

이제 이 catch문구에서 더 해야할 것이 무엇인지 알 수 있다. 

설명을 더 하거나, 게임을 처음부터 재실행하거나, 혹은 끊긴 부분을 재요청하거나 3가지 중에 하나겠다는 생각도 든다. 

 

스스로의 불찰에 대해 더욱 후회하기도 하지만, 맨날 성공해서 배울 수는 없으니까...

 

앞으로 1주밖에 남지 않은 우테코 프리코스지만, 프리코스가 끝나도 우테코 회고록은 1주마다, 혹은 비주기적으로 올라갈 것 같다. 

이전 기수에 있던 문제들도 프리코스에서 배운 부분들을 활용해 풀어보고, 여태 풀었던 코드도 리펙토링 해볼까 한다. 

 

이쯤되면 오기가 들기도 한다. 

내 머리속에 프리코스 멘토님들의 수준까지의 코드가 존재하지 않을 수 있다고 스스로 알고 있다. 

그래서 계속해서 만들고 생각해서 마음에 드는게 보일때까지(이걸 보실진 모르겠다) 두드려 봐야겠다. 

 

문도 계속 두들겨주면 열어주는데 코드도 계속 두들기다보면 머리도 문열고 집어넣어주겠지

(겁나 뚜들기다보면 해결된다는 짤)