각종 후기/우아한테크코스

[우아한 테크코스 3기] LEVEL 1 회고 - 로또 1단계 미션의 2차 피드백을 받아보다 (21일차)

제이온 (Jayon) 2021. 2. 22.

안녕하세요? 제이온입니다.

 

오늘은 오후 1시부터 시작이었고, 로또 미션 1단계의 2차 피드백 반영한 것 외에는 자습을 하였습니다.

 

 

데일리 미팅

저번 주 금요일은 워니 사정으로 데일리 미팅이 진행되지 않았지만, 오늘은 정상적으로 오후 1시에 진행되었습니다. 오늘의 진행자는 '삭정'이었고, 우테코 자소서 3번 문항인 "1년 이상 몰입한 경험이 무엇인가?"에 대해서 말하기로 하였습니다. 제 예상과는 다르게 다들 공부보다는 게임, 운동 쪽으로 답변을 하였습니다. 프로 제의 받을 정도로 롤이나 오버워치를 잘하는 크루도 있었고, 운동 쪽으로도 수상 경력이 있는 크루도 있었습니다.

 

저는 알고리즘을 1년 동안 열심히 하였다고 이야기 하였고, 그 외에 블로그 포스팅도 꾸준히 한 점을 어필하였습니다. 그리고 저는 블로그 광고 수익을 높이려고 광고를 많이 붙이고 안티 애드블록을 설치하곤 하였는데, 제 글을 보는 크루가 불편함을 느끼게 하는 것은 아닌 것 같아서 광고를 조금 줄이고 안티 애드블록도 해제하였습니다. 아마 우테코 크루들이 없었더라면, 이 부분을 고치지 않았을 것 같습니다. 

 

아무튼 제가 마지막으로 발표를 하였기 때문에 내일 데일리 미팅을 진행하게 되었고, 어떤 주제로 말하기를 할 지는 고민 중입니다. 로키가 제 글을 본다면 댓글로 추천해 주면 좋겠군요.

 

 

2차 피드백

저번 포스팅에서 저는 3가지 피드백에 대해 질문을 하였습니다. 첫 번째는 getInt()에 대한 메소드명을 수정할 것, 두 번째는 도메인에서 출력 로직을 작성하지 말 것, 세 번째는 LottoManager가 하는 일이 많으니 줄일 것이었습니다.

 

 

 

 

첫 번째 피드백은 금방 해결되었습니다. 바로, getInt()를 이용하여 구입금액과 보너스 볼을 입력받는 것이죠. 아래처럼 소스코드를 작성하면 됩니다.

 

 

    private static int getInt() {
        try {
            String input = scanner.nextLine().trim();
            return Integer.parseInt(input);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException(INPUT_INTEGER_ERROR_MESSAGE);
        }
    }

    public static int getMoney() {
        System.out.println(INPUT_MONEY_MESSAGE);
        return getInt();
    }

    public static int getBonusBall() {
        System.out.println(INPUT_BONUS_BALL_MESSAGE);
        return getInt();
    }

 

 

 

 

두 번째 피드백은 도메인에 있는 출력 로직을 뷰 로직으로 옮기는 것입니다. 이때, Controller에서 View를 출력하기 위한 값을 Model에서 꺼내서 전달하거나, DTO를 만들어 보라고 조언해 주셨습니다. 저는 우선, DTO를 어제 처음 알아서 개념정도만 간략하게 아는 정도였고 Controller에서 View를 출력하기 위한 값을 Model에서 꺼내서 전달한다는 점이 확 와닿지는 않았습니다..

 

그래서 저는 최우선적으로 도메인에 있는 출력 로직을 싹 지우기로 하였습니다. 자연스럽게 LottoStatistics 클래스 자체가 필요가 없어졌고 이들을 OutputView로 옮겼습니다.

 

 

    public static void printWinningStats(final RatingInfo ratingInfo, double rate) {
        printWinningDetail(ratingInfo);
        printEarningRate(rate);
    }

    private static void printWinningDetail(final RatingInfo ratingInfo) {
        System.out.println(WINNING_DETAIL_HEADER);
        System.out.println(getWinningDetail(ratingInfo));
    }

    private static String getWinningDetail(final RatingInfo ratingInfo) {
        final StringBuilder log = new StringBuilder();
        for (Rating rating : Rating.values()) {
            if (rating == Rating.MISS) {
                break;
            }
            log.append(appendWinningRatingLog(rating, ratingInfo.get(rating)));
        }
        return log.toString();
    }

    private static String appendWinningRatingLog(final Rating rating, final int count) {
        if (rating == Rating.SECOND) {
            return String
                .format(SECOND_PRINT_FORMAT, rating.getMatchCount(), rating.getReward(), count);
        }
        return String
            .format(PRINT_FORMAT, rating.getMatchCount(), rating.getReward(), count);
    }

    private static void printEarningRate(final double rate) {
        System.out.printf(TOTAL_EARNING_RATE_MESSAGE, rate);
    }

 

 

이런 식으로 printWinningStats()을 큰 틀로 받고, 내부적으로 출력 로직을 만들어 주었습니다. 기존의 인자로 LottoStatistics 객체를 받아와서 그 안에서 출력할 String을 내 보내주는 방식으로 작성하였는데, 위 코드로 수정하면서 출력문이 바뀌더라도 OutputView에서 변경할 수 있게 되었습니다.

 

그리고 원래 LottoStatistics 클래스에서는 수익률을 계산해 주는 메소드가 존재하였는데, LottoStatistics에 그대로 둘까 고민하다가 실질적인 메소드가 하나 밖에 없어서 LottoService(구 LottoManager)로 이동하였습니다.

 

 

 

 

위의 2개 피드백은 나름대로 반영을 하였다고 생각합니다. 하지만 마지막 피드백은 막막하였습니다. 우선, 수정된 제 LottoService 클래스 코드를 보여드리겠습니다.

 

 

public class LottoService {

    private final RatingInfo ratingInfo = new RatingInfo();
    private final LottoRepository lottoRepository = new LottoRepository();
    private final LottoMachine lottoMachine;

    public LottoService(final LottoMachine lottoMachine) {
        this.lottoMachine = lottoMachine;
    }

    public LottoRepository getLotto(final Ticket ticket) {
        lottoRepository.generateLottoByTicket(lottoMachine, ticket.getCount());
        return lottoRepository;
    }

    public RatingInfo scratchLotto(final WinningLotto winningLotto) {
        for (Lotto lotto : lottoRepository.toList()) {
            int match = winningLotto.compareLottoNumber(lotto);
            boolean hasBonusBall = winningLotto.compareBonusBall(lotto);
            ratingInfo.update(Rating.getRating(match, hasBonusBall));
        }
        return ratingInfo;
    }

    public double calculateEarningRate(final int money) {
        return totalSum() / money;
    }

    private double totalSum() {
        double sum = 0;
        for (Rating rating : Rating.values()) {
            if (rating == Rating.MISS) {
                break;
            }
            sum += rating.getReward() * ratingInfo.get(rating);
        }
        return sum;
    }
}

 

 

구매한 티켓의 개수에 따라 로또 번호를 얻어내고, 로또 번호를 긁어서 당첨 내역을 반환하고, 수익률을 계산해 주는 3가지 역할을 수행하고 있습니다. LottoService라는 이름에 따르면, 프로그램의 전반적인 시스템 로직을 다루고 있으므로 괜찮은건지.. 아니면 이것을 분리해야하는건지.. 그것도 아니면 위 로직을 LottoController로 옮겨야하는 것인지는 잘 몰라서 이 내용은 리뷰어 님께 질문하였습니다.

 

아마 LottoService 문제를 해결하면 로또 미션 2단계로 넘어갈 수 있지 않을까 기대합니다.

 

 

독서

주말동안 '코딩을 지탱하는 기술'을 모두 다 읽고, 오늘부터 '개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴'을 읽기 시작하였습니다. 이전에 객체 지향 관련 도서로 '객체지향의 사실과 오해'를 읽었었는데, 아무래도 사례와 개념 위주의 설명이어서 추상적으로 이해한 면이 있었습니다. 그래서 예제 코드가 많은 '개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴'은 저에게 있어서 객체 지향 설계를 어떻게 할 지 방향성을 잘 잡아 준다고 느껴졌습니다.

 

특히, 객체 지향 설계에서 가장 중요한 점은 객체의 책임을 적절하게 부여하는 것인데, UML 도형과 각종 예제 코드를 통해서 어떤 흐름인지 이해하기 참 좋았습니다. 얼른 이 책을 다 읽고 실제 개발에도 적용해 보고 싶다는 생각을 하였습니다.

 

 

정리

오늘도 나름 널널하게 하루를 보냈던 것 같습니다. 데이브의 피드백이 완료되는 대로 수정 사항을 적용하고, 2차 미션도 서둘러서 해야겠습니다.

 

위 미션의 코드가 궁금하신 분은 이곳을 참고하시길 바랍니다.

댓글

추천 글