ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,55 @@
+package subway.given;
+
+import io.restassured.response.*;
+import org.springframework.http.*;
+
+import java.util.*;
+
+import static io.restassured.RestAssured.*;
+
+public class GivenLineApi {
+
+    public static final String LINE_PATH = "/lines";
+    public static final String BG_COLOR_600 = "bg-color-600";
+
+    public static final String LINE_1 = "신분당선";
+    public static final String LINE_2 = "분당선";
+
+    public static final Long LINE_ID_1 = 1L;
+
+    public static final Long STATION_ID_1 = 1L;
+    public static final Long STATION_ID_2 = 2L;
+    public static final Long STATION_ID_3 = 3L;
+
+    public static ExtractableResponse<Response> createLine(
+            final String name,
+            final Long upStationId,
+            final Long downStationId
+    ) {
+
+        final var params = new HashMap<>();
+        params.put("name", name);
+        params.put("color", BG_COLOR_600);
+        params.put("upStationId", upStationId.toString());
+        params.put("downStationId", downStationId.toString());
+        params.put("distance", "10");
+
+        // When
+        return given().log().all()
+                .body(params)
+                .contentType(MediaType.APPLICATION_JSON_VALUE)
+                .when()
+                .post(LINE_PATH)
+                .then().log().all()
+                .extract();
+    }
+
+    public static ExtractableResponse<Response> getLineById(final Long lineId) {
+        return given().log().all()
+                .contentType(MediaType.APPLICATION_JSON_VALUE)
+                .when()
+                .get(LINE_PATH + "/" + lineId)
+                .then().log().all()
+                .extract();
+    }
+}

리뷰: Map 으로 만들어서 넘기기 보다는 DTO 로 만들어도 좋지 않을까요? ☺️
@@ -1 +1,30 @@
-# java-lotto 게임
+# java-Lotto 게임
+
+# 구현 기능 목록
+
+- [x] 구입금액 입력받기
+    - [x] 1000원 미만 입력 시 처리
+    - [x] 1000의 배수 아닌 값 입력 시 처리
+    - [x] 숫자가 아닌 값 (문자열)
+    - [x] 정상값 처리
+    - [x] 공백 처리
+- [x] 구매 개수 구하기
+- [x] 랜덤 로또번호 구매 개수만큼 만들기
+    - [x] defaultNumberSet 1번만 생성되도록 변경
+    - [x] RandomLottoTest 상수 리팩토링
+    - [x] PurchaseCount의 1000 접근
+- [x] 지난 주 당첨 번호 입력받기
+    - [x] WinningNumbers 멤버변수 ArrayList 클래스 확인
+    - [x] 숫자 개수 6개 확인
+    - [x] 숫자가 아닌 값 포함
+    - [x] 범위 (1~45) 확인
+    - [x] 공백 처리
+- [x] 보너스 볼 입력받기
+- [x] 당첨 통계
+    - [x] 당첨 조건을 enum 처리
+    - [x] 일치 개수 찾기
+    - [x] 5개 일치 시 보너스 볼 일치 여부 확인
+    - [x] 로또 당첨 개수 구하기
+    - [x] 당첨값의 합 구하기
+    - [x] 수익률 구하기
+    - [x] 결과 출력
\ No newline at end of file

리뷰: 구현 기능 목록 작성 👍
@@ -10,6 +10,13 @@ repositories {
 dependencies {
     testImplementation('org.junit.jupiter:junit-jupiter:5.6.0')
     testImplementation('org.assertj:assertj-core:3.15.0')
+
+    compileOnly 'org.projectlombok:lombok:1.18.20'
+    annotationProcessor 'org.projectlombok:lombok:1.18.20'
+
+    testCompileOnly 'org.projectlombok:lombok:1.18.20'
+    testAnnotationProcessor 'org.projectlombok:lombok:1.18.20'
+
 }
 
 test {

리뷰: 롬복 플러그인을 활용하셨네요!
@@ -0,0 +1,24 @@
+package lotto.controller;
+
+import lotto.domain.dto.LottoResult;
+import lotto.domain.dto.PurchaseInput;
+import lotto.domain.dto.PurchaseResult;
+import lotto.domain.dto.WinningLottoInput;
+import lotto.service.LottoService;
+
+public class LottoController {
+
+    private final LottoService lottoService;
+
+    public LottoController() {
+        this.lottoService = new LottoService();
+    }
+
+    public PurchaseResult purchase(PurchaseInput purchaseInput) throws IllegalArgumentException {
+        return lottoService.purchase(purchaseInput);
+    }
+
+    public LottoResult calculateResult(PurchaseResult purchaseResult, WinningLottoInput winningLottoInput) throws IllegalArgumentException {
+        return lottoService.calculateResult(purchaseResult, winningLottoInput);
+    }
+}

리뷰: MVC 패턴을 이용해 문제를 풀려고 시도하셨네요!
다만 Model - View - Controller 역할 분리가 명확하게 되어있지 않아
현재 Controller가 View를 직접 활용하는 방식으로 코드 구현이 되어있는데요.
각자의 역할과 책임은 무엇이고, 이를 어떻게 독립적으로 분리해낼 수 있을 지, 또 왜 그러하여야 하는지 고민해보시면 좋겠습니다. 현재는 `LottoController.start()` 는 `LottoApplication`의 main과 같은 역할로 보이네요.
@@ -0,0 +1,31 @@
+package lotto.view;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+import java.util.stream.Collectors;
+
+public class ConsoleInputView implements InputView {
+
+    private static final String LOTTO_NUMBERS_INPUT_DELIMITER = ",";
+
+    private final Scanner scanner = new Scanner(System.in);
+
+    public Integer getPurchaseCost() throws NumberFormatException {
+        String input = scanner.nextLine().trim();
+        return Integer.parseInt(input);
+    }
+
+    public List<Integer> getWinningLottoNumbers() throws NumberFormatException {
+        String input = scanner.nextLine();
+        return Arrays.stream(input.split(LOTTO_NUMBERS_INPUT_DELIMITER))
+                .map(String::trim)
+                .map(Integer::new)
+                .collect(Collectors.toList());
+    }
+
+    public Integer getWinningLottoBonus() throws NumberFormatException {
+        String input = scanner.nextLine().trim();
+        return Integer.parseInt(input);
+    }
+}

리뷰: 과한(불필요한) 메서드 포장입니다.
@@ -0,0 +1,86 @@
+package lotto.view;
+
+import lotto.domain.*;
+import lotto.domain.dto.LottoResult;
+
+public class ConsoleOutputView implements OutputView {
+
+    private static final String ERROR_HEADER = "[ERROR] ";
+
+    private void print(String contents) {
+        System.out.println(contents);
+    }
+
+    public void printLottoCount(PurchaseCount purchaseCount) {
+        int count = purchaseCount.getPurchaseCount();
+        print(count + "개를 구매했습니다.");
+    }
+
+    public void printLottoSet(LottoSet lottoSet) {
+        for (Lotto lotto : lottoSet.getLottoSet()) {
+            printLotto(lotto);
+        }
+    }
+
+    private void printLotto(Lotto lotto) {
+        String result = "[";
+        for (LottoNumber lottoNumber : lotto.getLottoNumbers()) {
+            result += lottoNumber.getLottoNumber() + ", ";
+        }
+        result = removeCommaAtTheEnd(result) + "]";
+
+        print(result);
+    }
+
+    private String removeCommaAtTheEnd(String str) {
+        return str.substring(0, str.length() - 2);
+    }
+
+    public void askPurchaseCost() {
+        print("구입금액을 입력해 주세요.");
+    }
+
+    public void askWinningLottoNumbers() {
+        print("지난 주 당첨 번호를 입력해 주세요.");
+    }
+
+    public void askWinningLottoBonus() {
+        print("보너스 볼을 입력해 주세요.");
+    }
+
+    public void printLottoStatistic(LottoResult lottoStatistics) {
+        String result = "당첨 통계\n---------\n" +
+                generatePrizeResultMessage(Prize.FIFTH, lottoStatistics.getPrizeCount().getFifth()) +
+                generatePrizeResultMessage(Prize.FOURTH, lottoStatistics.getPrizeCount().getFourth()) +
+                generatePrizeResultMessage(Prize.THIRD, lottoStatistics.getPrizeCount().getThird()) +
+                generatePrizeResultMessage(Prize.SECOND, lottoStatistics.getPrizeCount().getSecond()) +
+                generatePrizeResultMessage(Prize.FIRST, lottoStatistics.getPrizeCount().getFirst()) +
+                generateProfitRateMessage(lottoStatistics.getProfitRate());
+        print(result);
+    }
+
+    private String generatePrizeResultMessage(Prize prize, int prizeCount) {
+        return generatePrizeResultMessage(prize) + prizeCount + "개\n";
+    }
+
+    private String generatePrizeResultMessage(Prize prize) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(prize.getMatchNumbersCount())
+                .append("개 일치");
+        if (prize.isBonus()) {
+            sb.append(", 보너스 볼 일치 ");
+        }
+        sb.append("(")
+                .append(prize.getPrizeMoney())
+                .append("원)- ");
+        return sb.toString();
+    }
+
+    private String generateProfitRateMessage(double profitRate) {
+        return "총 수익률은 " + profitRate + "입니다.";
+    }
+
+    public void printException(String message) {
+        print(ERROR_HEADER + message);
+    }
+}

리뷰: line 9 to 13
너무 명확한 값들이 과하게 상수로 만들어졌습니다.
모든 literal value가 나쁜 것은 아닙니다. ^^;
@@ -0,0 +1,33 @@
+package lotto.service;
+
+import lotto.domain.*;
+import lotto.domain.dto.LottoResult;
+import lotto.domain.dto.PurchaseInput;
+import lotto.domain.dto.PurchaseResult;
+import lotto.domain.dto.WinningLottoInput;
+
+public class LottoService {
+
+    public PurchaseResult purchase(PurchaseInput purchaseInput) throws IllegalArgumentException {
+        PurchaseCount purchaseCount = new PurchaseCount(purchaseInput.getPrice());
+        LottoSet lottoSet = new LottoSet(purchaseCount);
+
+        return PurchaseResult.builder()
+                .purchaseCount(purchaseCount)
+                .lottoSet(lottoSet)
+                .build();
+    }
+
+    public LottoResult calculateResult(PurchaseResult purchaseResult, WinningLottoInput winningLottoInput) throws IllegalArgumentException {
+        LottoMatcher lottoMatcher = new LottoMatcher(
+                new WinningLotto(winningLottoInput), purchaseResult.getLottoSet()
+        );
+        PrizeCount prizeCount = lottoMatcher.countPrizes();
+        LottoStatistics lottoStatistics = new LottoStatistics(prizeCount, purchaseResult.getPurchaseCount());
+
+        return LottoResult.builder()
+                .prizeCount(prizeCount)
+                .profitRate(lottoStatistics.calculateProfitRate())
+                .build();
+    }
+}

리뷰: PurchaseCount 객체를 생성하는 이 시점에 유효성 검증이 해당 객체 생성자에서 진행되는데요,
컨트롤러 레이어에서 사용자의 입력 값의 유효성을 먼저 검증할 수 있지 않을까요?

고민해볼 거리: 유효성 검증은 어떤 레이어에서 진행되어야할까?
@@ -0,0 +1,19 @@
+package lotto.exception;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lotto.domain.Lotto;
+
+@RequiredArgsConstructor
+public enum ExceptionMessage {
+
+    NON_NUMBER_INPUT("숫자를 입력해주세요."),
+    LESS_THAN_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY("구입금액은 " + Lotto.PRICE + " 이상의 값을 입력해주세요."),
+    NON_MULTIPLE_OF_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY("구입금액은 " + Lotto.PRICE + "의 배수로 입력해주세요."),
+    INVALID_LENGTH_INPUT_FOR_LOTTO("로또 번호는 6개를 입력해주세요"),
+    DUPLICATE_LOTTO_NUMBER_INPUT_FOR_LOTTO("로또 번호는 중복되지 않는 6개의 숫자를 입력해주세요"),
+    OUT_OF_BOUND_INPUT_FOR_LOTTO_NUMBER("로또 번호는 1 이상 45 이하의 값을 입력해주세요.");
+
+    @Getter
+    private final String message;
+}

리뷰: 예외 메시지를 별도로 분리해서 한 곳에서 관리하고 있네요!
현재는 IllegalArgumentException만을 사용하고 메시지로 특정 예외에 대해서 처리하고 있는데요,
구체적인 CustomException을 만들고 상황에 따라 이를 던져 해당 Exception을 활용하는 방법도 생각해볼 수 있습니다.
@@ -0,0 +1,53 @@
+package lotto.domain;
+
+import lombok.Getter;
+
+import java.util.Objects;
+
+import static lotto.exception.ExceptionMessage.OUT_OF_BOUND_INPUT_FOR_LOTTO_NUMBER;
+
+public class LottoNumber {
+
+    public static final int LOWER_BOUND = 1;
+    public static final int UPPER_BOUND = 45;
+
+    @Getter
+    private final int lottoNumber;
+
+    public LottoNumber(int lottoNumber) throws IllegalArgumentException {
+        validate(lottoNumber);
+
+        this.lottoNumber = lottoNumber;
+    }
+
+    private void validate(int lottoNumber) throws IllegalArgumentException {
+        if (isOutOfBound(lottoNumber)) {
+            throw new IllegalArgumentException(OUT_OF_BOUND_INPUT_FOR_LOTTO_NUMBER.getMessage());
+        }
+    }
+
+    private boolean isOutOfBound(int lottoNumber) {
+        return lottoNumber < LOWER_BOUND || lottoNumber > UPPER_BOUND;
+    }
+
+    public boolean isGreaterThan(LottoNumber winningNumber) {
+        return this.getLottoNumber() > winningNumber.getLottoNumber();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        LottoNumber that = (LottoNumber) o;
+        return lottoNumber == that.lottoNumber;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(lottoNumber);
+    }
+}

리뷰: `isInteger` 는 직독하면 정수인가? 는 판단문입니다.
다만 내용을 보니 0~9까지 숫자 즉 음이 아닌 정수인지를 정규표현식을 이용해 판단하고 있네요.
isNonNegativeInteger 정도로 더 정확하게 표현해보면 어떨까요?
```suggestion
        if (!isNonNegativeInteger(input)) {
```
@@ -0,0 +1,35 @@
+package lotto.domain;
+
+import lombok.Builder;
+import lombok.Getter;
+
+import static lotto.exception.ExceptionMessage.LESS_THAN_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY;
+import static lotto.exception.ExceptionMessage.NON_MULTIPLE_OF_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY;
+
+public class PurchaseCount {
+
+    private static final int MINIMUM_INPUT = 1000;
+
+    @Getter
+    private final Integer purchaseCount;
+
+    @Builder
+    public PurchaseCount(int purchasePrice) {
+        validate(purchasePrice);
+
+        this.purchaseCount = purchasePrice / Lotto.PRICE;
+    }
+
+    private void validate(int purchasePrice) {
+        if (purchasePrice < MINIMUM_INPUT) {
+            throw new IllegalArgumentException(LESS_THAN_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY.getMessage());
+        }
+        if (notMultipleOfLottoPrice(purchasePrice)) {
+            throw new IllegalArgumentException(NON_MULTIPLE_OF_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY.getMessage());
+        }
+    }
+
+    private boolean notMultipleOfLottoPrice(int input) {
+        return input % Lotto.PRICE != 0;
+    }
+}

리뷰: `isInteger` 는 직독하면 정수인가? 는 판단문입니다.
다만 내용을 보니 0~9까지 숫자 즉 음이 아닌 정수인지를 정규표현식을 이용해 판단하고 있네요.
isNonNegativeInteger 정도로 더 정확하게 표현해보면 어떨까요?
```suggestion
        if (!isNonNegativeInteger(input)) {
```
@@ -0,0 +1,35 @@
+package lotto.domain;
+
+import lombok.Builder;
+import lombok.Getter;
+
+import static lotto.exception.ExceptionMessage.LESS_THAN_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY;
+import static lotto.exception.ExceptionMessage.NON_MULTIPLE_OF_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY;
+
+public class PurchaseCount {
+
+    private static final int MINIMUM_INPUT = 1000;
+
+    @Getter
+    private final Integer purchaseCount;
+
+    @Builder
+    public PurchaseCount(int purchasePrice) {
+        validate(purchasePrice);
+
+        this.purchaseCount = purchasePrice / Lotto.PRICE;
+    }
+
+    private void validate(int purchasePrice) {
+        if (purchasePrice < MINIMUM_INPUT) {
+            throw new IllegalArgumentException(LESS_THAN_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY.getMessage());
+        }
+        if (notMultipleOfLottoPrice(purchasePrice)) {
+            throw new IllegalArgumentException(NON_MULTIPLE_OF_LOTTO_PRICE_INPUT_FOR_PURCHASE_MONEY.getMessage());
+        }
+    }
+
+    private boolean notMultipleOfLottoPrice(int input) {
+        return input % Lotto.PRICE != 0;
+    }
+}

리뷰: `notMatchesCondition` 표현이 모호하고 두 가지 서로 다른 일을 하고 있습니다.
1. 입력이 로또를 구매할 수 있는 최소 값(1000)미만인지 검증
2. 정확히 티켓 가격의 배수인지 검증

1의 상황을 2의 부분집합으로 생각하여 구현하신 것으로 추측되는데,
사용자에게 실패에 대한 더 정확한 에러를 구분하여 노출하는 것이 좋지 않을까요?
@@ -0,0 +1,17 @@
+package lotto.domain;
+
+import lombok.Builder;
+import lombok.Getter;
+import lotto.domain.dto.WinningLottoInput;
+
+public class WinningLotto extends Lotto {
+
+    @Getter
+    private final LottoNumber bonusNumber;
+
+    @Builder
+    public WinningLotto(WinningLottoInput winningLottoInput) throws IllegalArgumentException {
+        super(winningLottoInput.getNumbers());
+        this.bonusNumber = new LottoNumber(winningLottoInput.getBonus());
+    }
+}

리뷰: 사용자 입력(InputView)에 대한 파싱과 검증이 서비스 레이어를 통과해 도메인 모델까지 침투했습니다.
이를 담당하는 영역인 컨트롤러 레이어에서 선작업을 모두 마무리지어야합니다.
가급적 도메인 모델은 사용자 입력 방식과 독립적이어야합니다.
어떤 뷰를 통해 접근하든 도메인은 그 자체로 문제 영역만을 표현하고 해결하는 레이어이어야합니다.
@@ -0,0 +1,53 @@
+package lotto.domain;
+
+import lombok.Getter;
+
+import java.util.Objects;
+
+import static lotto.exception.ExceptionMessage.OUT_OF_BOUND_INPUT_FOR_LOTTO_NUMBER;
+
+public class LottoNumber {
+
+    public static final int LOWER_BOUND = 1;
+    public static final int UPPER_BOUND = 45;
+
+    @Getter
+    private final int lottoNumber;
+
+    public LottoNumber(int lottoNumber) throws IllegalArgumentException {
+        validate(lottoNumber);
+
+        this.lottoNumber = lottoNumber;
+    }
+
+    private void validate(int lottoNumber) throws IllegalArgumentException {
+        if (isOutOfBound(lottoNumber)) {
+            throw new IllegalArgumentException(OUT_OF_BOUND_INPUT_FOR_LOTTO_NUMBER.getMessage());
+        }
+    }
+
+    private boolean isOutOfBound(int lottoNumber) {
+        return lottoNumber < LOWER_BOUND || lottoNumber > UPPER_BOUND;
+    }
+
+    public boolean isGreaterThan(LottoNumber winningNumber) {
+        return this.getLottoNumber() > winningNumber.getLottoNumber();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        LottoNumber that = (LottoNumber) o;
+        return lottoNumber == that.lottoNumber;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(lottoNumber);
+    }
+}

리뷰: LottoNumber를 생성할 때 String으로 생성할 필요가 있을까요?
String type으로 받다보니 형변환까지 책임져야하는 상황이 되었네요.
@@ -0,0 +1,17 @@
+package lotto.domain;
+
+import lombok.Builder;
+import lombok.Getter;
+import lotto.domain.dto.WinningLottoInput;
+
+public class WinningLotto extends Lotto {
+
+    @Getter
+    private final LottoNumber bonusNumber;
+
+    @Builder
+    public WinningLotto(WinningLottoInput winningLottoInput) throws IllegalArgumentException {
+        super(winningLottoInput.getNumbers());
+        this.bonusNumber = new LottoNumber(winningLottoInput.getBonus());
+    }
+}

리뷰: 반복문과 조건문을 중첩해서 로직이 복잡하네요.
더 나은 방식으로 리팩토링을 해야겠죠?
@@ -0,0 +1,55 @@
+package lotto.domain;
+
+import lombok.Getter;
+
+@Getter
+public enum Prize {
+
+    FIRST(6, false, 2000000000),
+    SECOND(5, true, 30000000),
+    THIRD(5, false, 1500000),
+    FOURTH(4, false, 50000),
+    FIFTH(3, false, 5000),
+    LOSE(2, false, 0);
+
+    private final int matchNumbersCount;
+    private final boolean isBonus;
+    private final long prizeMoney;
+
+    Prize(int matchNumbersCount, boolean isBonus, long prizeMoney) {
+        this.matchNumbersCount = matchNumbersCount;
+        this.isBonus = isBonus;
+        this.prizeMoney = prizeMoney;
+    }
+
+    public static Prize getMatchPrize(int matchNumbersCount, boolean isBonus) {
+        if (matchNumbersCount <= LOSE.matchNumbersCount) {
+            return LOSE;
+        }
+        if (matchNumbersCount == FIFTH.matchNumbersCount) {
+            return FIFTH;
+        }
+        if (matchNumbersCount == FOURTH.matchNumbersCount) {
+            return FOURTH;
+        }
+        if (matchNumbersCount == FIRST.matchNumbersCount) {
+            return FIRST;
+        }
+        return dissolveSecondOrThird(isBonus);
+    }
+
+    private static Prize dissolveSecondOrThird(boolean isBonus) {
+        if (isBonus) {
+            return Prize.SECOND;
+        }
+        return Prize.THIRD;
+    }
+
+    public static long sumOfPrizeMoney(PrizeCount prizeCount) {
+        return prizeCount.getFirst() * FIRST.prizeMoney
+                + prizeCount.getSecond() * SECOND.prizeMoney
+                + prizeCount.getThird() * THIRD.prizeMoney
+                + prizeCount.getFourth() * FOURTH.prizeMoney
+                + prizeCount.getFifth() * FIFTH.prizeMoney;
+    }
+}

리뷰: Enum 활용 👏
@@ -0,0 +1,35 @@
+package lotto.domain;
+
+import lombok.Getter;
+
+@Getter
+public class PrizeCount {
+
+    private int first;
+    private int second;
+    private int third;
+    private int fourth;
+    private int fifth;
+
+    public void addPrize(Prize prize) {
+        if (prize == Prize.FIRST) {
+            first++;
+            return;
+        }
+        if (prize == Prize.SECOND) {
+            second++;
+            return;
+        }
+        if (prize == Prize.THIRD) {
+            third++;
+            return;
+        }
+        if (prize == Prize.FOURTH) {
+            fourth++;
+            return;
+        }
+        if (prize == Prize.FIFTH) {
+            fifth++;
+        }
+    }
+}

리뷰: 이 클래스의 이름이 Prize**Count**이니
line 9 to 13 count 는 중복처럼 느껴지네요. 더 단순하게 네이밍해도 의미 전달에 무리 없어보입니다.
@@ -0,0 +1,17 @@
+package lotto.domain;
+
+import lombok.Builder;
+import lombok.Getter;
+import lotto.domain.dto.WinningLottoInput;
+
+public class WinningLotto extends Lotto {
+
+    @Getter
+    private final LottoNumber bonusNumber;
+
+    @Builder
+    public WinningLotto(WinningLottoInput winningLottoInput) throws IllegalArgumentException {
+        super(winningLottoInput.getNumbers());
+        this.bonusNumber = new LottoNumber(winningLottoInput.getBonus());
+    }
+}

리뷰: 1. 네이밍에서 Condition과 같은 모호한 단어를 사용하면 좋지 않습니다. 더 구체적인 표현을 사용하도록 합시다.
2. find라는 표현과 get이라는 표현 사이에 미묘한 차이가 있습니다. 어떤 차이인지는 찾아서 공부하고 저에게도 공유해주세요.
@@ -0,0 +1,22 @@
+package lotto.domain;
+
+import lombok.Builder;
+import lombok.Getter;
+
+public class LottoStatistics {
+
+    @Getter
+    private final PrizeCount prizeCount;
+    private final PurchaseCount purchaseCount;
+
+    @Builder
+    public LottoStatistics(PrizeCount prizeCount, PurchaseCount purchaseCount) {
+        this.prizeCount = prizeCount;
+        this.purchaseCount = purchaseCount;
+    }
+
+    public double calculateProfitRate() {
+        return (double) Prize.sumOfPrizeMoney(prizeCount)
+                / (purchaseCount.getPurchaseCount() * Lotto.PRICE);
+    }
+}
\ No newline at end of file

리뷰: 통계를 담는 객체를 만든 것 아주 좋습니다 👍
@@ -0,0 +1,21 @@
+import React from 'react';
+
+class InputBox extends React.Component {
+  // eslint-disable-next-line no-useless-constructor
+  constructor(props) {
+    super(props);
+  }
+  render() {
+    const { name, type, placeholder, recivedValue } = this.props;
+    return (
+      <input
+        name={name}
+        type={type}
+        placeholder={placeholder}
+        onChange={recivedValue}
+      />
+    );
+  }
+}
+
+export default InputBox;

리뷰: 이부분 왜 주석처리하셨나요?
이렇게 안쓰는 코드를 주석처리해서 남겨두면 다른사람도 이 코드가 어디에 쓰이는건가 해서 모두 못지우고 결국 아무 쓸모 없지만 계속 전해 내려가는 주석코드가 됩니다
필요없는 코드는 삭제해주세요!
커밋만 잘 남겨두면 다시 돌아올 수 있으니까 과감하게 지워도 됩니다!
@@ -0,0 +1,21 @@
+import React from 'react';
+
+class InputBox extends React.Component {
+  // eslint-disable-next-line no-useless-constructor
+  constructor(props) {
+    super(props);
+  }
+  render() {
+    const { name, type, placeholder, recivedValue } = this.props;
+    return (
+      <input
+        name={name}
+        type={type}
+        placeholder={placeholder}
+        onChange={recivedValue}
+      />
+    );
+  }
+}
+
+export default InputBox;

리뷰: ```suggestion
    const {name, type, placeholder, recivedValue} = this.props;
    return (
      <input
        name={name}
        type={type}
        placeholder={placeholder}
        onChange={recivedValue}
      />
    );
```
구조분해할당해서 쓰면 좀 더 깔끔하겠네요