-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[1단계 - 블랙잭 게임 실행] 재즈(함석명) 미션 제출합니다. #4
base: main
Are you sure you want to change the base?
[1단계 - 블랙잭 게임 실행] 재즈(함석명) 미션 제출합니다. #4
Conversation
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
Co-authored-by: seokmyungham <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컨트롤러 부분이 아주 깔끔하네요.
코맨트 조금 남겼습니다!
public DealerInitialHandDto convertDealerToInitialHandDto() { | ||
String dealerName = getName().value(); | ||
Card first = getFirstCard(); | ||
|
||
return new DealerInitialHandDto(dealerName, first.convertCardToDto()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Entity를 DTO로 변환하는 로직이 Entity에 있으면 View의 출력 요구조건에 따라 Domain 코드가 바뀌게 된다고 생각합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 기존에 동일한 생각을 가지고 있었는데, 확신이 없었던 것 같습니다.
처음에는 dto 변환 로직을 dto가 책임지도록 했다가, 컨트롤러 코드가 너무 길어져서 중간에 수정하게 되었어요.
그런데 이번 리뷰어분도 같은 부분을 지적해주셨고
계속 고민해본 결과, dto 변환 로직을 스스로 책임질 수 있도록 해서
dto가 변경되거나 삭제되어도 도메인은 영향을 받지 않도록 하는 게 맞는 것 같아요
수정해보겠습니다.
void setUP() { | ||
deck = new Deck(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UP 는 어떤 뜻인가요?
어떤 단어의 약자인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트를 위한 객체를 공통으로 사용하기 위해 준비하다 set up
의 의미의 네이밍이었습니다!
public enum GameResult { | ||
|
||
WIN("승"), | ||
LOSE("패"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
지금은 별 문제가 없을것 같지만 2차 구현에서 무승부일때 배팅 금액을 돌려받는다는 구현사항이 있어 같이 생각해보면서 구현하면 좋을것 같습니다!
private String getCommand(Player player) { | ||
String command = inputView.receiveCommand(player.getName().value()); | ||
if (HIT_COMMAND.equals(command) || STAND_COMMAND.equals(command)) { | ||
return command; | ||
} | ||
throw new IllegalArgumentException(HIT_COMMAND + " 또는 " + STAND_COMMAND + "만 입력 가능합니다."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
view에 책임이 아닌가 라는 생각이 듭니다.
입력 키워드를 "y" -> "hit", "n" -> "stand" 로 바꿨을때,
이 부분(controller)이 수정될것 같습니다. 어떻게 생각하시나요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로키 의견에 전적으로 동의합니다.
수정해보겠습니다
private void distributeCardToPlayer(Deck deck, Player player) { | ||
while (canDistribute(player)) { | ||
player.addCard(deck.draw()); | ||
outputView.printPlayerHand(player.convertGamerToDto()); | ||
} | ||
} | ||
|
||
private boolean canDistribute(Player player) { | ||
return player.canReceiveCard() && HIT_COMMAND.equals(getCommand(player)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 재즈 6기 크루 리비입니다 🙌
의도가 잘 드러나는 코드 잘 보았습니다 😀
재즈와 얘기해보고 싶은 부분을 코멘트로 남겨보았어요 👍
이어지는 블랙잭 미션 같이 화이팅해봐요 💪🏻
|
||
private static final String HIT_COMMAND = "y"; | ||
private static final String STAND_COMMAND = "n"; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enum으로 묶는다면 커맨드 관련 책임과 로직을 응집할 수 있을 것 같습니다 💪🏻
컨트롤러가 게임 흐름의 자세한 로직을 아는 것도 완화할 수 있을 것 같고요 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맞습니다! 저도 리비 의견에 전적으로 동의해요.
처음에는 컨트롤러에서 게임 흐름을 처리하니까, 저렇게 사용하고 인지하지 못했던 것 같아요
의사소통을 위한 별도의 Enum을 view패키지 안에 생성하고 view와 controller 사이에서 전달 받도록 수정해야할 것 같습니다 😄
|
||
public BlackjackController() { | ||
this.inputView = new InputView(); | ||
this.outputView = new OutputView(); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
생성자에서 어떤 객체를 주입받을지 fix하고 있네요
DI를 통해 유연성을 확보하는 것이 더 좋지 않을까요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맞아요 프로젝트가 나중에 확장될 가능성을 생각해 본다면
지금 Application
클래스와 같은 외부에서 주입하도록 하는 것이 나을 수도 있을 것 같네요 😊
public CardDto convertCardToDto() { | ||
return new CardDto(cardNumber.getName(), cardShape.getName()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DTO를 운용하기로 결정하셨군요
DTO의 생성 방법이 3가지 있는 것 같아요
- 도메인에서 ToDto 구현하기
- Dto에서 from 구현하기
- Mapper 이용하기
더 자주 바뀌는 객체가 무엇인지 생각해보고 의존방향 결정해봐도 좋을 것 같습니다 😀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
지금 코드 구조에 조금 문제가 있다는 걸 다른 방법들과 함께 간접적으로 알려주셨군요 !!
저도 도메인에서 ToDto 구현하기
와 Dto에서 from 구현하기
사이의 장점 단점들을 인지는 하고 있었는데
확신이 없었기에 이번 미션에서 실수를 저질렀던 것 같아요.
미션 리뷰어(현구막), 로키, 리비 다 같은 부분들을 지적해 주셨고
두 방법 사이에 트레이드 오프는 존재하지만, Dto가 변환로직을 스스로 책임을 지는게 맞다는 걸 크게 느끼게 되었어요.
Mapper 이용하는 방법
은 들어만 보고 모르고 있었던 부분인데
이번 기회에 학습해봐야겠네요!! 리비 알려주셔서 감사해요~ 😊
|
||
ACE("A", 11), | ||
TWO("2", 2), | ||
THREE("3", 3), | ||
FOUR("4", 4), | ||
FIVE("5", 5), | ||
SIX("6", 6), | ||
SEVEN("7", 7), | ||
EIGHT("8", 8), | ||
NINE("9", 9), | ||
TEN("10", 10), | ||
JACK("J", 10), | ||
QUEEN("Q", 10), | ||
KING("K", 10); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분은 재즈의 의견을 물어보고 싶네요
CardNumber
의 name은 뷰로직일까요? 🤔
먼저 저도 비슷한 방식으로 구현했습니다
CardNumber
는 이름을 속성으로 가지고 이름을 가져다가 출력하는 것이 위화감 없어 보인다는 생각이에요 (자동차 경주에서 Car의 이름을 가져다가 출력하듯이)
다만 저는 리뷰어에게서 도메인 속 뷰로직이 존재한다 라는 코멘트를 받았습니다 😅
재즈는 어떻게 생각하시나요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
먼저 저도 비슷한 방식으로 구현했습니다
CardNumber는 이름을 속성으로 가지고 이름을 가져다가 출력하는 것이 위화감 없어 보인다는 생각이에요 (자동차 경주에서 Car의 이름을 가져다가 출력하듯이)
앗 ㅋㅋㅋ 저도 속으로 "이정도는 괜찮나~?...." 생각했었는데 리뷰어분께 같은 코멘트를 받았어요 😭
현재 출력을 위한 이름이 도메인에 포함되어 있는지(재즈)
근데 리뷰를 받고 보니 제 페어 리뷰어분은 또 다른 의견이신 것 같아서 신기했습니다
현재 출력을 위한 이름이 도메인에 포함되어 있는지(상돌)
사실 미션 중간에 조금 꺼림칙하기도 해서,
제가 페어에게 view 패키지 안에 출력으로 변환해줄 수 있는 Enum
을 만들어보는 방법도 제안해봤었는데, 제 페어는 이정도 까지는 괜찮을 것 같다라는 의견이었고 그냥 그대로 진행하게 되었습니다.
제 개인적인 생각은 여기까지는 허용할 수 있다, 이건 안된다는 너무 주관적인 영역인 것 같고 모호하다고 생각해요
그래서 저는 이번 미션도 그렇고 앞으로의 미션도 모두 별도의 변환을 하게끔 설계하기로 다짐하게 되었는데
현재 리비는 어떻게 생각하고 계신가요~??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 별도의 변환이 필요하다고 생각하게 되었네요 👍
숫자들을 TWO처럼 영어로 출력되도록 바꿔주세요
라는 요청을 받으면 어느 패키지를 열어볼까요? 라는 질문을 받은 적 있는데 저라면 뷰를 열어볼 것 같더군요 😂
여기에 설득되어 뷰 레이어에서 따로 변환하도록 할 것 같습니다.
|
||
public class Deck { | ||
|
||
private final LinkedList<Card> cards; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deck에서 LinkedList를 사용하신 이유가 궁금해요 💭
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저두 궁금해요! Queue
나 List
를 사용하는 것이 내부 구현을 바꾸는데 좀 더 용이하지 않을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맨 앞쪽(위쪽)의 카드를 가져온다
라는 의미와 잘 매칭되는 메서드를 먼저 생각해봤는데
Queue
자료구조의 poll()
메서드가 가장 먼저 떠올랐던 것 같아요.
큐 자료구조 특성상 데이터 변경이 일어날 때 리스트보다 성능 상 유리한 점이 많이 와닿았던 것 같습니다.
그리고 Queue
자료구조가 특정 상황과 연관되는 구현체들이 많다고 개인적으로 생각해서
다형성을 포기하고 LinkedList
만 사용해! 라고 뭔가 강제하게 된 느낌인데, 이게 좋은지는 아직 잘 모르겠네요.. ㅎㅎ
|
||
public void initCard(Deck deck) { | ||
addCard(deck.draw()); | ||
addCard(deck.draw()); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
게이머는 시작 카드가 두장이다
라는 규칙 자체를 상수로써 표현할 수 있을 것 같아요
initCard를 실행할 때 해당 상수를 이용하도록 하면 규칙의 변경에 유연하게 대처할 수 있을 것 같습니다 😀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오!! 미처 생각지 못했는데 괜찮은 방법인 것 같습니다 😄
바로 반영해보겠습니다!
public int calculateScore() { | ||
int sum = cards.stream() | ||
.mapToInt(Card::getNumber) | ||
.sum(); | ||
|
||
if (hasAce()) { | ||
return adjustSumWithAce(sum); | ||
} | ||
return sum; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
블랙잭 룰에 맞추어 점수를 계산하는 것
은 Hand
도메인의 책임일까요 🤔
현재의 Hand는 일급 컬렉션 역할을 수행함과 동시에 게임의 룰(채점 방식)을 알고 있다고 생각합니다 😀
채점 방식이 변경되면 Hand
가 변경되어야 하는데 이것에 위화감이 있다는 것이 저의 생각입니다.
그래서 저는 도메인을 순수히 유지하고 블랙잭 게임의 규칙 (ex 점수 계산 로직)등을 외부로 덜어내고자 노력했어요
다만 저도 어떤 것이 정답인지는 모르겠습니다 😂
(파생되는 코드가 많다고 리뷰어에게 코멘트를 받기도 함)
재즈의 의견 궁금합니다 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 리비 말대로 그렇게 생각해 볼 수도 있겠네요~
저는 점수 계산하는 부분에 관해선
블랙잭 게임의 채점 방식은 오랜 시간이 지나도 거의 변하지 않는 룰
처럼 느껴진 부분과
List<Card>
의 정보를 가장 잘 알고있는 Hand가 수행하는게 자연스럽다고 생각했던 것 같아요.
채점 방식이 변경되면 Hand가 변경되어야 하는데 이것에 위화감이 있다는 것이 저의 생각입니다.
저도 맞는 생각이라고 생각해요 😄
근데 저는 블랙잭 게임이 아니라 룰이 매우 복잡하고 변경될 여지가 많을 때 별도의 점수를 계산하는 Rule
이나 Score
객체를 만들 것 같습니다.
근데 이거는 제가 구조를 최대한 가볍게 가져가는 걸 좋아해서 그런 걸 수도 있는 것 같아요. 😂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
근데 저는 블랙잭 게임이 아니라 룰이 매우 복잡하고 변경될 여지가 많을 때 별도의 점수를 계산하는 Rule이나 Score 객체를 만들 것 같습니다.
제가 제일 많이 고민하던 부분인데 재즈의 의견 합리적이네요 👍👍
저도 불필요한 확장을 의식하는 것보다 도메인 명세에 집중해야겠어요 💪🏻
package blackjack.dto; | ||
|
||
public record CardDto(String cardNumber, String cardShape) { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
레코드 적극 활용하셨군요 😀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일단 우선적으로 눈에 보이는 부분만 짚어봤어
주로 내가 코드를 보면서 궁금했던 부분, 내 생각과 조금 달랐던 부분 등 위주로 리뷰 달았어,
내 생각과 다른 부분이 있다면 코멘트 달아줘.
- [x] 딜러의 점수를 입력받아 승,패를 결정한다. | ||
- [x] 플레이어의 점수가 21을 초과하면 딜러의 점수와 무관하게 패배한다. | ||
- [x] 플레이어의 점수가 21 이하이고, 딜러와 동점인 경우 패배한다. | ||
- [x] 플레이어의 점수가 21 이하이고, 딜러의 점수가 21을 초과하면 승리한다. | ||
- [x] 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 크면 승리한다. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나도 무승부를 구현하지 않았는데, 따로 무승부를 구현하지 않은 이유가 있을까?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그냥 최대한 현재 요구사항에 충실하려고 노력했던 것 같아 😄
2단계 요구사항을 보지않고 진행했어서, 만약 2단계에 무승부가 없다면 굳이 에너지를 낭비하게 될 수도 있다는 생각이었어
private static final String HIT_COMMAND = "y"; | ||
private static final String STAND_COMMAND = "n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나는 해당 커멘드가 Controller
보다 InputView
에 있는게 더 좋을 것 같은데, 어떻게 생각해?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 별도의 명령어를 view 패키지의 Enum으로 사용하도록 수정했었는데
정작 컨트롤러는 수정하지 않았었네 😭
바로 수정!!
public class Card { | ||
|
||
private final CardShape cardShape; | ||
private final CardNumber cardNumber; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CardShape
, CardNumber
보다 Shape
, Number
가 더 간결하게 표현할 수 있지 않을까?
Card
안에 쓰였다는 것만으로도 카드의 모양, 숫자를 나타낼 수 있다고 생각해.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나는 간결보다는 명확한 걸 좋아해서 이게 낫다고 생각했어
Enum이 쓰이는 상황에서도 Shape.Heart
보다는 CardShape.Heart
가 더 직관적이라고 생각해
|
||
public class Deck { | ||
|
||
private final LinkedList<Card> cards; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저두 궁금해요! Queue
나 List
를 사용하는 것이 내부 구현을 바꾸는데 좀 더 용이하지 않을까요?
public record Name(String value) { | ||
|
||
private static final int MAX_NAME_LENGTH = 5; | ||
|
||
public Name { | ||
if (value.isBlank() || value.length() > MAX_NAME_LENGTH) { | ||
throw new IllegalArgumentException("이름의 길이는 최소 1글자부터 최대 " + MAX_NAME_LENGTH + "글자까지 가능합니다."); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
타칸의 Record 테코톡 중에 "도메인 객체는 Record를 사용하는 것이 좋지 않다"라고 했었는데,
재즈는 어떻게 생각해? (지금 이걸 보니까 이 정도는 괜찮나 싶기도...?)
public void printInitialHands(DealerInitialHandDto dealerInitialHandDto, List<GamerHandDto> playersInitialHandDto) { | ||
System.out.printf("\n%s와 %s에게 2장을 나누었습니다.\n", dealerInitialHandDto.name(), | ||
joinPlayerNames(playersInitialHandDto)); | ||
|
||
System.out.printf("%s 카드: %s\n", dealerInitialHandDto.name(), formatCardName(dealerInitialHandDto.firstCard())); | ||
printAllPlayerHands(playersInitialHandDto); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개행 문자를 강조하는 편은 아닌데, printf()
를 쓸거면 \n
대신 %n
을 쓰는 건 어떨까?
https://ps3940.tistory.com/65
@Test | ||
@DisplayName("유효한 입력에 대해서는 예외가 발생되지 않는다.") | ||
void validPlayerNamesTest() { | ||
assertThatCode(() -> new Players(List.of("a", "b"))) | ||
.doesNotThrowAnyException(); | ||
assertThatCode(() -> new Players(List.of("a", "b", "c", "d", "e", "f", "g", "h"))) | ||
.doesNotThrowAnyException(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
위의 코드가 assert 문을 통과하지 않으면 아래 코드가 assert문을 통과하는 지 한번에 알 수 없을 것 같아.
assertAll()
로 묶어보는 건 어떨까?
public void addCard(Card card) { | ||
hand.add(card); | ||
} | ||
|
||
public Card getFirstCard() { | ||
return hand.getFirstCard(); | ||
} | ||
|
||
public int getScore() { | ||
return hand.calculateScore(); | ||
} | ||
|
||
public Name getName() { | ||
return name; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
하위 클래스에서 재정의해서 사용하지 않을 메서드는 final
키워드를 붙여서 관리해보는 건 어떨끼?
하위 클래스에서 실수로 재정의하는 것을 방지해줄 수 있을 것 같아.
현구막 안녕하세요~ 이번 블랙잭 게임 리뷰를 부탁드리게 된 재즈라고 합니다😊
세 번째 미션이라 이젠 조금 익숙해지려 하다가도, 사다리 미션보다 난이도가 확 올라간 느낌이라서 또 새롭네요 ㅎㅎ
객체의 역할이 다양해지니까 점점 더 재미있어지는 것 같아요 🔥
게임 로직을 구현하는 방법이 정말 다양할 것 같아서
리뷰 하시는 인지적 비용을 덜어드리고자.. 게임 흐름 명세와 함께 궁금한 부분들 질문드립니다!
블랙잭 게임 흐름
Dealer
와Player
는 공통적으로 추상 클래스 BlackjackGamer를 상속 받습니다.Dealer
,Player
서로 카드를 받는 조건이 다르므로 각각 추상 메서드를 오버라이드합니다.Hand
객체에서 자신의 카드 점수를 계산하고, 딜러의 점수를 플레이어에게 넘겨주어 플레이어는 자신의 승, 패 여부를 결정합니다.Players
에서 이름과 게임 결과를 매핑하여 Dto로 반환합니다.Dealer
로 넘겨주어, 딜러의 게임 결과를 집계하고 Dto로 반환하도록 하였습니다.미션을 진행하면서 궁금했던 점
출력 형식에 의존하는 Enum
CardNumber
CardShape
?이번 미션에서 카드 번호와 카드 문양을 상수로 활용하고자 Enum 클래스로 만들게 되었어요.
현재 두 Enum 모두 문자열 name을 필드로 가지고 있는데요, 페어와 저 모두 문자열
name
은 지금 출력에 의존 하고 있는게 아닐까? 라는 생각을 가지고 있습니다.출력 요구사항이 "J하트" 에서 "JACK하트"로 변경되면 도메인을 수정해야 하기도 하고, 도메인을 지키지 못하고 있다는 느낌이 큰 것 같아요..
페어와 의견을 나눠보면서 현재 Enum에서 문자열 필드를 제거하고, view 패키지에 Enum을 출력 형식으로 변환해줄 수 있는 Enum
CardShapeToSymbol
같은 중간 다리를 하나 추가하는 방법을 제가 제안해봤는데 서로 뭔가 확신이 없는 것 같습니다.현재 CardNumber와 CardShape가 출력 형식에 의존하고 있는 것 같은지, 제가 위에 작성한 방법에 대해 어떻게 생각하시는지 현구막의 의견을 듣고 싶어요!!
Dto를 사용하는 것을 어떻게 생각하시는지, 사용한다면 Dto 생성 로직의 위치
저번 사다리 미션에서 Dto를 사용하면서 조금 번거롭기도 했고 코드를 가볍게 가져가고 싶어 다음 미션에는 Dto를 사용하지 말아야지!! 라고 다짐했는데 이번에도 Dto를 사용하게 되었어요.
도메인을 뷰에 노출시키지 않고 싶으면 컨트롤러에서 도메인의 필드 원시값을 꺼내서 넘겨도 되기는 하지만,
내가 원하는 값들만 모아서 전달할 수 있다는 장점과
Map<String, boolean> 처럼 결과를 넘기게 되었을 때, 이 코드를 처음 보는 개발자가 저 안의 엔트리 값이 뭘 의미하는지 해석하는 인지적 비용을 줄이고 Dto에 이름을 붙일 수 있다는 점이 매력적으로 다가왔던 것 같아요.
그리고 Dto를 사용하면서 getter도 거의 사용하지 않았던 점도 긍정적인 부분이었던 것 같습니다.
그런데 현재 Dto 생성 로직이 도메인 내에 존재하는데,
Dto개수가 늘어남에 따라 중요하지 않은 Dto 생성 로직이 불필요하게 많아지는 것 같다고 느껴요.
Dto 생성 로직을 Dto 내부로 옮기고 컨트롤러에서 getter를 사용해서 생성한다면 걱정을 해결할 수 있지만 지금도 100줄이나 넘는 컨트롤러 로직이 더 복잡해질 것을 우려해서 도메인 내부에서 생성하도록 결정하게 되었습니다.
은총알은 없고 트레이드 오프를 항상 고려해야 하지만
현재 제 코드는 미숙한 부분들이 너무 많다고 느끼고
이번 미션을 진행하면서 개선해야 할 부분들에 대해 현구막께 많은 것을 배우고 싶어요!! 😀
긴 글과 코드 읽어주셔서 감사하고
리뷰 기다리고 있겠습니다!!
감사합니다 😄