[🚀 사이클2 - 미션 (블랙잭 베팅)] 와이제리 미션 제출합니다.#1136
Conversation
- 객체지향적인 코드를 위해 초기 핸드 사이즈를 Deck으로 이동
- Controller에서 Dealer, Player의 초기 드로우 된 카드 사이즈를 이용해 사용
- List와 연관된 assertThat containsExactly() 활용하여 플레이어의 승/무/패/버스트 여부를 한 번에 테스트 - 플레이어, 딜러 버스트인 경우 테스트 추가 - 딜러의 승/무/패 횟수 테스트 추가
- Cards -> Deck 클래스 이름 수정 - 테스트에 맞는 설명 수정DisplayName
- format() 메서드 추가
- 정수형 반환 전에 입력받은 문자열이 숫자 패턴에 맞는지 검증
- 배팅 금액인 BettingAmount 클래스 추가 - 플레이어, 배팅 금액을 보유한PlayerBet 클래스 추가 - PlayerBet의 일급컬렉션 PlayersBet 클래스 추가
- int, long, double보다 정확한 소수 계산을 위한 BigDecimal 사용 - 금액을 잃는 경우인 applyLoseAmount() 추가
| public BigDecimal value() { | ||
| return amount; | ||
| } |
There was a problem hiding this comment.
오차 없이 정확하게 계산해야 하는 값에는 BigDecimal을 사용하는 것이 좋다고 하여 적용해 보았습니다.
이와 관련해 궁금한 점이 있습니다. value()처럼 값 객체를 반환하는 메서드에서 반환값을 BigDecimal 그대로 반환하지 않고, String으로 변환해 반환하는 경우 이것도 뷰와 연관된 책임을 도메인이 가지게 되는 것인지 궁금합니다.
There was a problem hiding this comment.
쉽게 사용자에게 보여줄 정보의 양식이 변경될 경우 도메인이 같이 변경되면 뷰와 연관된 책임을 도메인이 가진다고 볼 수 있겠네요. BigDecimal을 그대로 반환하지 않고 String으로 변환했을 때, 베팅 금액과 관련된 뷰가 변경되면 어디가 변경될 지 고민해보면 답을 찾을 수 있을 것 같아요~
verus-j
left a comment
There was a problem hiding this comment.
안녕하세요 와이제리~
테스트 코드와 관련된 리뷰 먼저 드립니다. 테스트 코드 쪽에서 주석을 사용해 설명한 곳이 많은데, 테스트 코드를 개선하여 주석을 어떻게 제거할 수 있을지 고민해보면 좋을 것 같아요~
| private List<Card> createCards(String input) { | ||
| if (input.equals("블랙잭")) { | ||
| return List.of(Card.of(Rank.ACE, Suit.SPADE), Card.of(Rank.J, Suit.HEART)); // 블랙잭 | ||
| } | ||
| if (input.equals("승리")) { | ||
| return List.of(Card.of(Rank.J, Suit.SPADE), Card.of(Rank.Q, Suit.HEART), | ||
| Card.of(Rank.ACE, Suit.DIAMOND)); // 21 | ||
| } | ||
| if (input.equals("무승부")) { | ||
| return List.of(Card.of(Rank.TEN, Suit.DIAMOND), Card.of(Rank.TEN, Suit.CLOVER)); // 20 | ||
| } | ||
| if (input.equals("패배")) { | ||
| return List.of(Card.of(Rank.TEN, Suit.HEART), Card.of(Rank.SEVEN, Suit.CLOVER)); // 17 | ||
| } | ||
| return List.of(Card.of(Rank.J, Suit.SPADE), Card.of(Rank.Q, Suit.CLOVER), Card.of(Rank.K, Suit.HEART)); // 버스트 | ||
| } |
There was a problem hiding this comment.
개별 케이스를 상수 List로 선언하는 것도 좋은 방향이 될 것 같습니다. 주석도 필요할지 다시 한번 고민해보면 좋을 것 같아요~
There was a problem hiding this comment.
개별 케이스를 상수 List로 선언하는 것도 좋은 방향이 될 것 같습니다. 주석도 필요할지 다시 한번 고민해보면 좋을 것 같아요~
상수 List로 선언하면 주석 변수명으로 주석 또한 없앨 수 있겠네요.
BlackjackResult와 비슷한 방식으로 상수 List 선언하여 수정했습니다!
There was a problem hiding this comment.
개별 케이스를 상수 List로 선언하는 것도 좋은 방향이 될 것 같습니다. 주석도 필요할지 다시 한번 고민해보면 좋을 것 같아요~
추가로 궁금한 점이 있습니다.
테스트 코드에서 winCards, drawCards처럼 다른 테스트에서도 함께 사용하는 상수들은 Fixture로 공통 관리하는 방향이 더 나아 보이는데, 공통되는 부분이 3곳 이상이라 Fixture로 분리해도 괜찮을지 리뷰어님의 의견이 궁금합니다.
There was a problem hiding this comment.
Fixture로 분리해서 사용하는 것도 좋아보입니다. 다음에는 비슷한 상황에 적용해보면 좋을 것 같아요~
verus-j
left a comment
There was a problem hiding this comment.
안녕하세요 와이제리~
미션 진행하시느라 고생하셨습니다. 테스트 케이스 피드백을 이전에 드렸는데, 당시에 생각했던 프로덕션 코드의 문제도 같이 잘 수정해주셔서 더 이상 피드백을 남길 게 없는 것 같아요. 질문의 답변은 오늘 중으로 슬랙에 남겨놓겠습니다! 남은 우테코 일정도 화이팅입니다~
| public void addInitialCards(List<Card> cards) { | ||
| cards.forEach(this::addCard); | ||
| } |
There was a problem hiding this comment.
초기에 카드 여러장을 받기위해서 만들었지만, Hand의 addInitialCards 메서드만 봤을 때는 카드 리스트를 추가하는걸로 보입니다. 메서드 명을 범용적인 addCards로 수정하는게 더 좋아보여요~
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| public class Hand { |
체크 리스트
test를 실행했을 때, 모든 테스트가 정상적으로 통과했나요?어떤 부분에 집중하여 리뷰해야 할까요?
1️⃣
Controller의 책임은 어디까지라고 보시나요?사이클1 때에도 Controller 자체가 많이 복잡했습니다. 한눈에 파악하기 어려워, 입력 생성, 출력, 플레이어/딜러 진행 책임을 분리해 각각의 클래스로 관리하는 방향으로 책임 분리를 해보려고 합니다.
MVC 패턴을 더 잘 적용하면서도 관리하기 쉬운 구조로 만들려면, 이러한 방향으로 분리하는 것이 괜찮을지 궁금합니다.
2️⃣ 비즈니스 규칙에서 도메인이 책임져야 할 부분과
Controller,View가 책임져야 할 부분의 기준이 궁금합니다.구현을 하면서 늘 가장 고민되는 부분 중 하나는, 어떤 코드를 도메인에 두어야 하는지입니다. 예를 들어 사이클 1 구현에서 딜러가 16 이하이면 카드를 추가로 받는 규칙이 있었는데, 이 경우 Controller에서 while문을 사용해 dealer.draw()를 호출해야 하는지, 아니면 Dealer 내부에 16 이하일 때 카드를 추가로 받는 규칙을 구현해야 하는지 고민이 되었습니다.
또 다른 예시로는, 추가 카드를 y, n으로 입력받아 플레이어에게 카드를 추가하는 부분이 있습니다. 입력받은 y를 플레이어에게 전달해 Player 내부에서 y, n에 대한 판단을 하고 카드를 추가해야 하는지, 아니면 Controller에서 그 역할을 담당해야 하는지도 고민되었습니다.
저는 두 예시 모두 출력 흐름과 관련이 있다고 생각해 Controller에서 구현했는데, 이것이 명확한 기준이라고 느껴지지는 않았습니다. 이 부분에 대해 리뷰어님께서는 어떤 기준으로 판단하시는지도 궁금합니다.
3️⃣ 기능 추가와 관련해 질문드리고 싶습니다!
이번 사이클2에서는 블랙잭 배팅 기능이 추가되었습니다. 배팅 기능을 넣기 위해 두 가지 방법을 고민했습니다.
첫 번째는 플레이어와 딜러가 필드로 배팅 금액을 가지도록 하는 방식입니다. 플레이어가 자신의 배팅 금액을 직접 가지고 있는 것도 같은 책임 안에 포함될 수 있다고 생각했습니다.
두 번째는 이번 프로그래밍 요구사항 중 하나인 “인스턴스 변수 3개를 넘지 않는다”는 규칙을 지키기 위해, 플레이어와 배팅 금액을 필드로 가지는 PlayerBet 클래스를 만들어 사용하는 방식입니다. 다만 두 번째 방법은 기존 클래스를 수정하기보다 새로운 클래스를 생성해 함께 사용해야 하는 부분이 많아 보였습니다.
위 두 가지 방법의 단점은, 첫 번째는 책임이 많아져 클래스가 무거워질 수 있다는 점이고, 두 번째는 책임이 가벼워지는 대신 기능이 여러 곳으로 퍼질 수 있다는 점이라고 생각했습니다.
저는 두 번째 방법을 선택했고, 앞으로 구현하면서 최대한 기능을 분리해 보려고 합니다. PlayerBet과 같이 클래스를 구성한 방식에 대해 리뷰어님께서는 어떻게 생각하시는지 궁금합니다.