Skip to content
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단계] 미플 미션 제출합니다 #119

Open
wants to merge 82 commits into
base: hambeomjoon
Choose a base branch
from

Conversation

HamBeomJoon
Copy link

@HamBeomJoon HamBeomJoon commented Mar 7, 2025

안녕하세요 코니. 잘 부탁드립니다!

셀프 체크리스트

  • 프로그램이 정상적으로 작동하는가?
  • 모든 테스트가 통과하는가?
  • 코딩 스타일 가이드를 준수하였는가?
    • IDE 코드 자동 정렬을 적용하였는가?
    • 린트 검사를 통과하였는가?
  • 프로그래밍 요구 사항을 준수하였는가?
  • README.md에 기능 목록을 정리하고 명확히 기술하였는가?

어떤 부분에 집중하여 리뷰해야 할까요?

  • Deck을 Object로 만들어 싱글턴으로 만들었는데, 테스트에서 Deck의 카드를 모두 뽑았을 때 예외처리를 테스트하면서 카드를 52장 드로우 하니 다른 테스트에서 Deck의 카드를 뽑을 때 에러가 발생했습니다. (coverage 테스트로 실행 했을 때)
    실제로 프로그램을 실행했을 경우는 이런 경우가 발생하지 않는데, 이런 테스트 때문에 object를 다시 class로 변경해야 하는지, 카드를 모두 뽑았을때 예외처리하는 테스트를 제거해야 하는지 궁금합니다!

Copy link

@lee-ji-hoon lee-ji-hoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 미플 블랙잭 리뷰어 코니입니다!

우선 공통 로직을 최소화하기 위해서 최선을 다하신 모습은 좋습니다. 하지만 의문이 가는 부분들이 있어서 리뷰로 남겨뒀는데요. 해당 리뷰에 따라 전체적인 코드가 아예 바뀔 수도 있어서 미플이 한 번 고민해 보면 좋을 것 같습니다.

EIGHT("8", 8),
NINE("9", 9),
TEN("10", 10),
JACK("J", 10),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View에 표현하기 위해서 value가 생긴 것 같은데요.

그러면 만약 J를 이미지로 교체한다고 했을 때 해당 모델의 변경이 생길텐데 이런 변경사항이 생기는게 맞을지 MVC 관점에서 고민해봅시다.

Comment on lines +7 to +10
fun addCard(card: Card) = _cards.add(card)

fun addCards(cards: List<Card>) = _cards.addAll(cards)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

abstract 으로 만들었는데 addCard addCards 이 2개 정말 공존해야 할까요? 사람 입장에서는 한 장씩 받는 것이지 않을까요?


abstract class Person {
private val _cards: MutableList<Card> = mutableListOf()
open val cards get() = _cards.toList()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 값이 open 되어야 할 필요가 있을까요?

그리고 외부로 공개 되어 있는 이유는 지금 이 객체에게 메세지를 던지지 않고 있는 상황이 아닌지 생각해 봅시다.

Comment on lines +3 to +6
enum class ResultType(val value: Char) {
WIN('승'),
TIE('무'),
LOSS('패'), ;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 value도 view에만 표시하기 위한 선언부인데 만약 이 라는 것 말고 디자인에서 승리 라고 띄어주고 싶다고 하면 domain model 까지 변경이 되어야 하는 상황이 와버립니다.

Comment on lines +8 to +21
companion object {
fun judgeScore(
dealer: Dealer,
player: Player,
): ResultType {
val dealerFinalScore = if (dealer.isBust()) 0 else dealer.calculateTotalScore()
val playerFinalScore = if (player.isBust()) 0 else player.calculateTotalScore()
if (dealerFinalScore < playerFinalScore) return WIN
if (dealerFinalScore == playerFinalScore) return TIE
return LOSS
}

const val BUST_NUMBER = 21
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ResultType 이라는 객체를 봤을 때 결과 에 집중을 하고 있는데 여기서 BUST_NUMBER 도 갖고 있고 승부 결과까지 만들고 있네요.

블랙잭이라는 도메인으로 생각했을 때, 블랙잭은 플레이어와 딜러간의 대결일텐데요. 이 부분에 대해서 천천히 고민해봅시다.

import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows

class DeckTest {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deck을 Object로 만들어 싱글턴으로 만들었는데, 테스트에서 Deck의 카드를 모두 뽑았을 때 예외처리를 테스트하면서 카드를 52장 드로우하니 다른 테스트에서 Deck의 카드를 뽑을 때 에러가 발생했습니다. (coverage 테스트로 실행했을 때)
실제로 프로그램을 실행했을 경우는 이런 경우가 발생하지 않는데, 이런 테스트 때문에 object를 다시 class로 변경해야 하는지, 카드를 모두 뽑았을 때 예외처리하는 테스트를 제거해야 하는지 궁금합니다!

위와 같은 질문이 해당 테스트 같은데요. 우선

실제로 프로그램을 실행했을 경우는 이런 경우가 발생하지 않는데, 이런 테스트 때문에 object를 다시 class로 변경해야 하는지,

테스트 때문에 object -> class로 변경을 한다. 이 관점에서 봤을 때 2가지 측면이 있습니다.

  1. 잘못된 테스트이다.
  2. object로 구현하면 안 된다.

이 부분을 기억하고 다음 질문을 보면

카드를 모두 뽑았을 때 예외처리하는 테스트를 제거해야 하는지 궁금합니다!

테스트를 제거한다.라는 관점으로 봤을 때 아까 1번의 상황이라고 판단이 어느정도 되신 것 같은데요.

근데 지금 만약 게임이 1판이 아니고 2판 3판 이뤄진다

위 경우를 생각 해보면 이 테스트가 필요했을지 아닐지 직접 판단하실 수 있을 것이라고 생각합니다.

Comment on lines +12 to +17
private lateinit var dealer: Dealer

@BeforeEach
fun setUp() {
dealer = Dealer()
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트가 독립적으로 수행될 수 있게 잘해주셨습니다. 단 구조적인 리뷰가 진행됨에 따라 테스트가 변경이 많이 될 수도 있기에 테스트는 구조적인 리뷰 반영 혹은 의견을 서로 나누고서 다시 한번 보겠습니다.

Comment on lines +38 to +48
private fun playerDrawOrStay(player: Player) {
val condition: DrawChoice = inputView.readMoreCardCondition(player)
if (condition.isStay()) {
outputView.printPlayerHands(player)
return
}
gameManager.drawCard(player)
outputView.printPlayerHands(player)
if (player.isBust()) return
playerDrawOrStay(player)
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 함수가 단순 플레이어가 draw 하거나 stay를 하겠구나 하고 봤는데요 지금 �너무 어렵게 구현이 되어있는 것 같아요.

return을 2개나 하고 있고 재귀로 호출이 되게끔 만들었는데요.

while과 when문을 적절하게 섞으면   
지금 어떠한 상태 일 때 player의 턴을 종료한다.

라는 것을 조금 더 명시적으로 나타낼 수 있을 것 같습니다.


fun isMoreCard() = calculateTotalScore() < DEALER_MORE_CARD_MINIMUM

companion object {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

companion object 는 어디에 위치를 해야 하는가. 를 확인해보시면 좋을 것 같네요.

https://kotlinlang.org/docs/coding-conventions.html#class-layout

@@ -0,0 +1,14 @@
package blackjack.model

abstract class Person {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사람으로 따지면 "이름" 도 공통이 될 수 있지 않을까요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants