ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,55 @@
+package domain.user;
+
+import java.util.Objects;
+
+public class Score implements Comparable<Score> {
+    private static final int ZERO = 0;
+
+    private int value;
+
+    public Score(int value) {
+        validateScore(value);
+        this.value = value;
+    }
+
+    private void validateScore(int value) {
+        boolean isNegative = value < ZERO;
+        if (isNegative) {
+            throw new IllegalArgumentException("점수는 0보다 작을 수 없습니다.");
+        }
+    }
+
+    public boolean isBiggerThan(int value) {
+        return this.value > value;
+    }
+
+    public boolean isSame(int value) {
+        return this.value == value;
+    }
+
+    public boolean isSmallerThan(int dealerRuleScoreValue) {
+        return value < dealerRuleScoreValue;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        Score score1 = (Score) o;
+        return value == score1.value;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(value);
+    }
+
+    @Override
+    public int compareTo(Score o) {
+        return Integer.compare(value, o.value);
+    }
+}

리뷰: ```suggestion
        if (value < ZERO) {
```
위와 같이 표현해도 충분히 이해하기 쉽다고 생각하는데, 어떻게 생각하시나요? 😃
@@ -0,0 +1,36 @@
+package domain.result;
+
+import domain.user.Profit;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Arrays;
+
+public enum EarningRate {
+    ONE_POINT_FIVE(GameResult.BLACKJACK, BigDecimal.valueOf(1.5)),
+    ONE(GameResult.WIN, BigDecimal.ONE),
+    ZERO(GameResult.DRAW, BigDecimal.ZERO),
+    MINUS_ONE(GameResult.LOSE, BigDecimal.valueOf(-1));
+
+    private static final int SCALE = 0;
+
+    private GameResult gameResult;
+    private BigDecimal earningRate;
+
+    EarningRate(GameResult gameResult, BigDecimal earningRate) {
+        this.gameResult = gameResult;
+        this.earningRate = earningRate;
+    }
+
+    public static EarningRate from(GameResult gameResult) {
+        return Arrays.stream(EarningRate.values())
+                .filter(earningRate -> earningRate.gameResult == gameResult)
+                .findAny()
+                .orElseThrow(() -> new IllegalArgumentException("해당 게임 결과에 대한 수익률이 존재하지 않습니다."));
+    }
+
+    public Profit calculateProfit(BigDecimal amount) {
+        return new Profit(amount.multiply(earningRate)
+                .setScale(SCALE, RoundingMode.HALF_EVEN));
+    }
+}

리뷰: EarningRate를 GameResult의 필드로 포함시키면 어떨까요? 🤔
@@ -0,0 +1,98 @@
+package domain.user;
+
+import domain.card.Deck;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+
+public class Users {
+    private static final int DEALER_COUNT = 1;
+
+    private List<User> users;
+
+    public Users(List<User> users) {
+        validateUsers(users);
+        this.users = users;
+    }
+
+    private void validateUsers(List<User> users) {
+        validateDuplicateNames(users);
+        validateIsExistsDealer(users);
+    }
+
+    private void validateDuplicateNames(List<User> users) {
+        int playerCount = users.stream()
+                .filter(User::isPlayer)
+                .collect(toSet())
+                .size();
+        if (playerCount != users.size() - DEALER_COUNT) {
+            throw new IllegalArgumentException("플레이어는 중복되는 이름을 가질 수 없습니다.");
+        }
+    }
+
+    private void validateIsExistsDealer(List<User> users) {
+        boolean isExistsDealer = users.stream()
+                .anyMatch(User::isDealer);
+        if (!isExistsDealer) {
+            throw new IllegalArgumentException("유저들에 딜러가 포함되어 있지 않습니다.");
+        }
+    }
+
+    public void receiveCards(Deck deck) {
+        users.forEach(deck::distributeCard);
+    }
+
+    public boolean hasWaitingPlayer() {
+        return users.stream()
+                .filter(User::isPlayer)
+                .anyMatch(User::isWait);
+    }
+
+    public Player findPlayerOfCurrentTurn() {
+        return users.stream()
+                .filter(User::isPlayer)
+                .map(user -> (Player) user)
+                .filter(User::isWait)
+                .findFirst()
+                .orElseThrow(() -> new IllegalStateException("대기중인 플레이어가 없습니다."));
+    }
+
+    public UserProfits produceUserProfits() {
+        Map<User, Profit> userProfits = new HashMap<>();
+        Dealer dealer = findDealer();
+        findPlayers().forEach(player -> userProfits.put(player, player.produceProfit(dealer)));
+        Profit dealerProfit = calculateDealerProfit(userProfits);
+        userProfits.put(dealer, dealerProfit);
+        return new UserProfits(userProfits);
+    }
+
+    private Profit calculateDealerProfit(Map<User, Profit> playerProfitResults) {
+        return playerProfitResults.values().stream()
+                .reduce(Profit.ZERO, Profit::add)
+                .negate();
+    }
+
+    public Dealer findDealer() {
+        return users.stream()
+                .filter(User::isDealer)
+                .map(user -> (Dealer) user)
+                .findFirst()
+                .orElseThrow(() -> new IllegalStateException("딜러가 존재하지 않습니다."));
+    }
+
+    public List<Player> findPlayers() {
+        return users.stream()
+                .filter(User::isPlayer)
+                .map(user -> (Player) user)
+                .collect(toList());
+    }
+
+    public List<User> getUsers() {
+        return Collections.unmodifiableList(users);
+    }
+}

리뷰: 메서드 참조로 변경해볼 수도 있을 것 같아요!

map(Dealer.class::cast)
```suggestion
                .map(Dealer.class::cast)
```
@@ -1,4 +1,70 @@
 package controller;
 
+
+import domain.card.Deck;
+import domain.user.*;
+import view.InputView;
+import view.OutputView;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
 public class BlackJackGame {
+
+    public static void main(String[] args) {
+        Users users = inputUsers();
+        Deck deck = new Deck();
+        deck.distributeCardsToUsers(users);
+        OutputView.printDistributeCardsMessageAndCardsOfAllUsers(users);
+        proceedPlayersTurn(users.findPlayers(), deck);
+        proceedDealerTurn(users.findDealer(), deck);
+        OutputView.printAllUsersResult(users);
+        OutputView.printAllUsersProfit(users);
+    }
+
+    private static Users inputUsers() {
+        List<UserName> userNames = inputPlayerNames();
+        List<User> users = userNames.stream()
+                .map(BlackJackGame::convertNamesAndBettingMoneyIntoPlayers)
+                .collect(toList());
+        users.add(new Dealer());
+        return new Users(users);
+    }
+
+    private static List<UserName> inputPlayerNames() {
+        return InputView.inputNames().stream()
+                .map(String::trim)
+                .map(UserName::new)
+                .collect(toList());
+    }
+
+    private static Player convertNamesAndBettingMoneyIntoPlayers(UserName userName) {
+        BettingMoney bettingMoney = convertAmountIntoBettingMoney(InputView.inputAmount(userName));
+        return new Player(userName, bettingMoney);
+    }
+
+    private static BettingMoney convertAmountIntoBettingMoney(BigDecimal amount) {
+        return new BettingMoney(amount);
+    }
+
+    private static void proceedPlayersTurn(List<Player> players, Deck deck) {
+        players.forEach(player -> proceedPlayerTurn(player, deck));
+    }
+
+    private static void proceedPlayerTurn(Player player, Deck deck) {
+        while (player.isOwnTurn()) {
+            player.proceedOwnTurn(InputView.inputAnswer(player), deck);
+            OutputView.printCardsHeldByPlayer(player);
+        }
+    }
+
+    private static void proceedDealerTurn(Dealer dealer, Deck deck) {
+        while (dealer.isOwnTurn()) {
+            dealer.hit(deck);
+            OutputView.printDealerGetOneMoreCard();
+        }
+    }
+
 }

리뷰: ```suggestion
    private static void showDealerProfit(PlayerProfitStatistics playerProfitStatistics) {
```
dealer를 파라미터로 받아와서  ``showDealerProfit`` 내부에서 사용하지 않는 것 같아요🤔
@@ -1,4 +1,70 @@
 package controller;
 
+
+import domain.card.Deck;
+import domain.user.*;
+import view.InputView;
+import view.OutputView;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
 public class BlackJackGame {
+
+    public static void main(String[] args) {
+        Users users = inputUsers();
+        Deck deck = new Deck();
+        deck.distributeCardsToUsers(users);
+        OutputView.printDistributeCardsMessageAndCardsOfAllUsers(users);
+        proceedPlayersTurn(users.findPlayers(), deck);
+        proceedDealerTurn(users.findDealer(), deck);
+        OutputView.printAllUsersResult(users);
+        OutputView.printAllUsersProfit(users);
+    }
+
+    private static Users inputUsers() {
+        List<UserName> userNames = inputPlayerNames();
+        List<User> users = userNames.stream()
+                .map(BlackJackGame::convertNamesAndBettingMoneyIntoPlayers)
+                .collect(toList());
+        users.add(new Dealer());
+        return new Users(users);
+    }
+
+    private static List<UserName> inputPlayerNames() {
+        return InputView.inputNames().stream()
+                .map(String::trim)
+                .map(UserName::new)
+                .collect(toList());
+    }
+
+    private static Player convertNamesAndBettingMoneyIntoPlayers(UserName userName) {
+        BettingMoney bettingMoney = convertAmountIntoBettingMoney(InputView.inputAmount(userName));
+        return new Player(userName, bettingMoney);
+    }
+
+    private static BettingMoney convertAmountIntoBettingMoney(BigDecimal amount) {
+        return new BettingMoney(amount);
+    }
+
+    private static void proceedPlayersTurn(List<Player> players, Deck deck) {
+        players.forEach(player -> proceedPlayerTurn(player, deck));
+    }
+
+    private static void proceedPlayerTurn(Player player, Deck deck) {
+        while (player.isOwnTurn()) {
+            player.proceedOwnTurn(InputView.inputAnswer(player), deck);
+            OutputView.printCardsHeldByPlayer(player);
+        }
+    }
+
+    private static void proceedDealerTurn(Dealer dealer, Deck deck) {
+        while (dealer.isOwnTurn()) {
+            dealer.hit(deck);
+            OutputView.printDealerGetOneMoreCard();
+        }
+    }
+
 }

리뷰: 개인적인 의견이지만, 자주 사용되는 함수인 경우 static import를 하는 것도 좋지만, ``마치 현재 클래스의 멤버인것 처럼 사용할 수 있기 때문에 편리하지만 그 만큼 혼동을 주기도 쉽다고`` 생각합니다.
@@ -0,0 +1,36 @@
+package domain.card;
+
+import domain.user.User;
+import domain.user.Users;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Deck {
+    private static final int ZERO = 0;
+    private static final int NUMBER_OF_CARDS_BY_RULE = 2;
+    private static final int TOP = 0;
+
+    private final List<Card> cards;
+
+    public Deck() {
+        this.cards = new ArrayList<>(Card.getCachedCards());
+        Collections.shuffle(cards);
+    }
+
+    public void distributeCardsToUsers(Users users) {
+        for (int i = ZERO; i < NUMBER_OF_CARDS_BY_RULE; i++) {
+            users.receiveCards(this);
+        }
+    }
+
+    public void distributeCard(User user) {
+        user.draw(cards.remove(TOP));
+    }
+
+    public List<Card> getCards() {
+        return Collections.unmodifiableList(cards);
+    }
+
+}

리뷰: 가급적  가독성을 위해서 아래와 같이 ``stream()``  다음에는 들여쓰기를 해주세요 🙏
이와 유사한 부분들은 찾아서 전부 수정해주세요 😉

```suggestion
            Arrays.stream(Type.values())
                .forEach(type -> cards.add(new Card(symbol, type)));
```
@@ -0,0 +1,36 @@
+package domain.card;
+
+import domain.user.User;
+import domain.user.Users;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Deck {
+    private static final int ZERO = 0;
+    private static final int NUMBER_OF_CARDS_BY_RULE = 2;
+    private static final int TOP = 0;
+
+    private final List<Card> cards;
+
+    public Deck() {
+        this.cards = new ArrayList<>(Card.getCachedCards());
+        Collections.shuffle(cards);
+    }
+
+    public void distributeCardsToUsers(Users users) {
+        for (int i = ZERO; i < NUMBER_OF_CARDS_BY_RULE; i++) {
+            users.receiveCards(this);
+        }
+    }
+
+    public void distributeCard(User user) {
+        user.draw(cards.remove(TOP));
+    }
+
+    public List<Card> getCards() {
+        return Collections.unmodifiableList(cards);
+    }
+
+}

리뷰: Deck을 정적 팩토리 메서드로만 생성하기로 했다면,  기본 생성자를 ``private``으로 지정하여 외부에서 (생성자로) Deck 객체를 생성할 수 없도록 막아주세요
@@ -1,4 +1,70 @@
 package controller;
 
+
+import domain.card.Deck;
+import domain.user.*;
+import view.InputView;
+import view.OutputView;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
 public class BlackJackGame {
+
+    public static void main(String[] args) {
+        Users users = inputUsers();
+        Deck deck = new Deck();
+        deck.distributeCardsToUsers(users);
+        OutputView.printDistributeCardsMessageAndCardsOfAllUsers(users);
+        proceedPlayersTurn(users.findPlayers(), deck);
+        proceedDealerTurn(users.findDealer(), deck);
+        OutputView.printAllUsersResult(users);
+        OutputView.printAllUsersProfit(users);
+    }
+
+    private static Users inputUsers() {
+        List<UserName> userNames = inputPlayerNames();
+        List<User> users = userNames.stream()
+                .map(BlackJackGame::convertNamesAndBettingMoneyIntoPlayers)
+                .collect(toList());
+        users.add(new Dealer());
+        return new Users(users);
+    }
+
+    private static List<UserName> inputPlayerNames() {
+        return InputView.inputNames().stream()
+                .map(String::trim)
+                .map(UserName::new)
+                .collect(toList());
+    }
+
+    private static Player convertNamesAndBettingMoneyIntoPlayers(UserName userName) {
+        BettingMoney bettingMoney = convertAmountIntoBettingMoney(InputView.inputAmount(userName));
+        return new Player(userName, bettingMoney);
+    }
+
+    private static BettingMoney convertAmountIntoBettingMoney(BigDecimal amount) {
+        return new BettingMoney(amount);
+    }
+
+    private static void proceedPlayersTurn(List<Player> players, Deck deck) {
+        players.forEach(player -> proceedPlayerTurn(player, deck));
+    }
+
+    private static void proceedPlayerTurn(Player player, Deck deck) {
+        while (player.isOwnTurn()) {
+            player.proceedOwnTurn(InputView.inputAnswer(player), deck);
+            OutputView.printCardsHeldByPlayer(player);
+        }
+    }
+
+    private static void proceedDealerTurn(Dealer dealer, Deck deck) {
+        while (dealer.isOwnTurn()) {
+            dealer.hit(deck);
+            OutputView.printDealerGetOneMoreCard();
+        }
+    }
+
 }

리뷰: ```suggestion
        List<Player> players = players.getPlayers();
        for (Player player : players) {
```
위와 같이 변경하는게 더 좋은건 이전 피드백을 통해서 알고 계실 것 같습니다 😉
@@ -1,4 +1,70 @@
 package controller;
 
+
+import domain.card.Deck;
+import domain.user.*;
+import view.InputView;
+import view.OutputView;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
 public class BlackJackGame {
+
+    public static void main(String[] args) {
+        Users users = inputUsers();
+        Deck deck = new Deck();
+        deck.distributeCardsToUsers(users);
+        OutputView.printDistributeCardsMessageAndCardsOfAllUsers(users);
+        proceedPlayersTurn(users.findPlayers(), deck);
+        proceedDealerTurn(users.findDealer(), deck);
+        OutputView.printAllUsersResult(users);
+        OutputView.printAllUsersProfit(users);
+    }
+
+    private static Users inputUsers() {
+        List<UserName> userNames = inputPlayerNames();
+        List<User> users = userNames.stream()
+                .map(BlackJackGame::convertNamesAndBettingMoneyIntoPlayers)
+                .collect(toList());
+        users.add(new Dealer());
+        return new Users(users);
+    }
+
+    private static List<UserName> inputPlayerNames() {
+        return InputView.inputNames().stream()
+                .map(String::trim)
+                .map(UserName::new)
+                .collect(toList());
+    }
+
+    private static Player convertNamesAndBettingMoneyIntoPlayers(UserName userName) {
+        BettingMoney bettingMoney = convertAmountIntoBettingMoney(InputView.inputAmount(userName));
+        return new Player(userName, bettingMoney);
+    }
+
+    private static BettingMoney convertAmountIntoBettingMoney(BigDecimal amount) {
+        return new BettingMoney(amount);
+    }
+
+    private static void proceedPlayersTurn(List<Player> players, Deck deck) {
+        players.forEach(player -> proceedPlayerTurn(player, deck));
+    }
+
+    private static void proceedPlayerTurn(Player player, Deck deck) {
+        while (player.isOwnTurn()) {
+            player.proceedOwnTurn(InputView.inputAnswer(player), deck);
+            OutputView.printCardsHeldByPlayer(player);
+        }
+    }
+
+    private static void proceedDealerTurn(Dealer dealer, Deck deck) {
+        while (dealer.isOwnTurn()) {
+            dealer.hit(deck);
+            OutputView.printDealerGetOneMoreCard();
+        }
+    }
+
 }

리뷰: 지금 ``BlackJackGame`` 은 Controller의 역할과 객체의 역할을 동시에 하고 있는 것으로 보여요 🤔

질문 주셨던 ``뚱뚱한 Controller`` 의 원인이 여기에 있는 것 같아요 😅 
``BlackJackGame`` 이라는 객체를 만들어서 Controller 의 역할과 분리하는 것이 어떨까요?  😉
@@ -1,4 +1,70 @@
 package controller;
 
+
+import domain.card.Deck;
+import domain.user.*;
+import view.InputView;
+import view.OutputView;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
 public class BlackJackGame {
+
+    public static void main(String[] args) {
+        Users users = inputUsers();
+        Deck deck = new Deck();
+        deck.distributeCardsToUsers(users);
+        OutputView.printDistributeCardsMessageAndCardsOfAllUsers(users);
+        proceedPlayersTurn(users.findPlayers(), deck);
+        proceedDealerTurn(users.findDealer(), deck);
+        OutputView.printAllUsersResult(users);
+        OutputView.printAllUsersProfit(users);
+    }
+
+    private static Users inputUsers() {
+        List<UserName> userNames = inputPlayerNames();
+        List<User> users = userNames.stream()
+                .map(BlackJackGame::convertNamesAndBettingMoneyIntoPlayers)
+                .collect(toList());
+        users.add(new Dealer());
+        return new Users(users);
+    }
+
+    private static List<UserName> inputPlayerNames() {
+        return InputView.inputNames().stream()
+                .map(String::trim)
+                .map(UserName::new)
+                .collect(toList());
+    }
+
+    private static Player convertNamesAndBettingMoneyIntoPlayers(UserName userName) {
+        BettingMoney bettingMoney = convertAmountIntoBettingMoney(InputView.inputAmount(userName));
+        return new Player(userName, bettingMoney);
+    }
+
+    private static BettingMoney convertAmountIntoBettingMoney(BigDecimal amount) {
+        return new BettingMoney(amount);
+    }
+
+    private static void proceedPlayersTurn(List<Player> players, Deck deck) {
+        players.forEach(player -> proceedPlayerTurn(player, deck));
+    }
+
+    private static void proceedPlayerTurn(Player player, Deck deck) {
+        while (player.isOwnTurn()) {
+            player.proceedOwnTurn(InputView.inputAnswer(player), deck);
+            OutputView.printCardsHeldByPlayer(player);
+        }
+    }
+
+    private static void proceedDealerTurn(Dealer dealer, Deck deck) {
+        while (dealer.isOwnTurn()) {
+            dealer.hit(deck);
+            OutputView.printDealerGetOneMoreCard();
+        }
+    }
+
 }

리뷰: ``Deck이 초기 패를 초기화``하고 ``Users와 Dealer에게 패를 나눠주는 행위``가 정말 Controller의 ``책임``이 맞을까요? 🤔
@@ -1,4 +1,70 @@
 package controller;
 
+
+import domain.card.Deck;
+import domain.user.*;
+import view.InputView;
+import view.OutputView;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
 public class BlackJackGame {
+
+    public static void main(String[] args) {
+        Users users = inputUsers();
+        Deck deck = new Deck();
+        deck.distributeCardsToUsers(users);
+        OutputView.printDistributeCardsMessageAndCardsOfAllUsers(users);
+        proceedPlayersTurn(users.findPlayers(), deck);
+        proceedDealerTurn(users.findDealer(), deck);
+        OutputView.printAllUsersResult(users);
+        OutputView.printAllUsersProfit(users);
+    }
+
+    private static Users inputUsers() {
+        List<UserName> userNames = inputPlayerNames();
+        List<User> users = userNames.stream()
+                .map(BlackJackGame::convertNamesAndBettingMoneyIntoPlayers)
+                .collect(toList());
+        users.add(new Dealer());
+        return new Users(users);
+    }
+
+    private static List<UserName> inputPlayerNames() {
+        return InputView.inputNames().stream()
+                .map(String::trim)
+                .map(UserName::new)
+                .collect(toList());
+    }
+
+    private static Player convertNamesAndBettingMoneyIntoPlayers(UserName userName) {
+        BettingMoney bettingMoney = convertAmountIntoBettingMoney(InputView.inputAmount(userName));
+        return new Player(userName, bettingMoney);
+    }
+
+    private static BettingMoney convertAmountIntoBettingMoney(BigDecimal amount) {
+        return new BettingMoney(amount);
+    }
+
+    private static void proceedPlayersTurn(List<Player> players, Deck deck) {
+        players.forEach(player -> proceedPlayerTurn(player, deck));
+    }
+
+    private static void proceedPlayerTurn(Player player, Deck deck) {
+        while (player.isOwnTurn()) {
+            player.proceedOwnTurn(InputView.inputAnswer(player), deck);
+            OutputView.printCardsHeldByPlayer(player);
+        }
+    }
+
+    private static void proceedDealerTurn(Dealer dealer, Deck deck) {
+        while (dealer.isOwnTurn()) {
+            dealer.hit(deck);
+            OutputView.printDealerGetOneMoreCard();
+        }
+    }
+
 }

리뷰: ```suggestion
        OutputView.printCardsHeldByDealer(firstCard);
```
위와 같이 Card를 파라미터로 전달해서, ``OutputView.printCardsHeldByDealer`` 내부에서 symbol과 type을 꺼내서 출력하면 되지 않을까요 🤔