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

가위바위보 게임 [STEP 1] Wan #8

Open
wants to merge 8 commits into
base: rft_2_wannn
Choose a base branch
from

Conversation

hsw1920
Copy link

@hsw1920 hsw1920 commented Mar 20, 2024

@zdodev
안녕하세요 소대 완 입니다!
벌써 3주차라니 아쉽습니다..
갑작스런 개인 일정때문에 지난주부터 코스에 더 많은 시간을 투자하지 못하고 있다는게 너무 아쉽습니다.. ㅠㅠ..
week2의 코멘트도 아직 적용하여 Step2를 진행하지 못하고 있지만.. 먼저 week3 PR 올리겠습니다..! (이후 꼭 혼자서 진행해보겠습니다!)

미션 요구사항에 따라
최대한 RED-GREEN-REFACTOR에 맞추어 개발을 진행하였습니다 !
하지만 TDD, Unit Test가 이번이 처음이어서 잘 작성한건지 사실 의문스럽네요 ;)

내용

개발 과정은 먼저 요구사항에 대한 테스트 코드를 작성하며 해당 비즈니스 로직을 구현하였고,
요구된 모든 기능이 구현된 뒤 기획의 변경을 염두에 두어 리팩터링을 진행하였습니다.
비즈니스 로직은 UI와 분리하였기에 UI는 Step1에서 구현하지 않았습니다.

TestCode는

  1. user, computer의 대결결과
  2. 요구사항인 RandomHand의 테스트
  3. 삼세판 테스트
  4. 리셋 테스트
    의 순서로 진행하였고, 로직또한 위 순서에 따라 구현되었습니다.

이후 기획의 변경을 저는 Game 종류가 변경될 수 있다. 라고 생각하고 진행하며 리팩터링을 진행하였습니다.

고민했던 점

사실 User에 집중해야할 지, Game에 집중해야할 지 판단이 명확하게 서질 않았습니다.
일단 저는 Game은 User가 반드시 참여한다고 생각하였기에 Game이 User에 의존하도록 구현하였습니다.

설계에 대한 고민

1-1. Game은 가위,바위,보를 사용하는 게임으로 생각하여 HandGameable 프로토콜을 구현하여 이를 채택시켰습니다.
1-2. 이후 Game이 추가된다면 유저가 참여한 상태에서 HandGameable 프로토콜을 따르는 다른 Game의 구현체를 교체하는것으로 생각하였습니다!
1-3 User와 Score또한 Game관련의 최소한의 프로토콜이 존재하며 다른 Game으로 교체된다면 각 User와 Score의 다른 구현체로 교체하는 것을 생각했습니다.

2-1. User는 Game을 Play하는 사람이며 각자 자신의 Score와 Hand를 가지도록 구현하였고 이를 모두 프로토콜로 구현하였습니다.
2-2. User가 각자 자신의 Score와 Hand를 관리할 대한 책임이 있다고 생각했습니다.

확장성에 대한 고민

위 1-3에 작성한대로 각 구현체들은 Game관련 protocol을 따르게 됩니다.
지금 당장은 전혀 문제가 없어보입니다.

하지만 이후 Game이 추가된다면 결국 새로운 구현체가 생성이 될 것입니다.
최초 작성한 protocol의 요구사항이,
추후 구현될 다른 Game에서 필요치 않은 경우를 생각하게 되었습니다.
이런 경우에는 결국

  1. 최초 작성한 protocol의 요구사항을 줄임
  2. 새로 구현된 구현체에 빈 메서드나 프로퍼티를 둠.
    둘 중 하나일 것이라고 생각하는데요.

저라면 1번을 택하고 기존 구현체에 extension으로 다른 구현체에 필요 없는 메서드, 프로퍼티를 기본구현할 것 같은데
이런 부분은 최소한의 고려만 하고 상황에 따라 그때 그때 판단하는 것이 나은지 궁금합니다.

테스트 코드에 대한 고민

테스트코드에서만 필요한 Game 인스턴스의 메서드의 경우에는 어떻게 처리해야할 지 잘 모르겠습니다
일단 HandGameable protocol에 play()로 구현하긴 하였는데, 추후 실제 게임에서는 nextGame()으로 모두 대체가 가능해보이는 것이 고민입니다.

Copy link

@zdodev zdodev left a comment

Choose a reason for hiding this comment

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

안녕하세요. @hsw1920 !

3번째 프로젝트까지 진행해보셨네요!👍

가위바위보와 게임 진행에 대해 많은 고민을 해보신 것 같습니다.
처음이지만 XCTest를 잘 활용해보셨네요!

확정성에 대한 고민에 대한 제 생각도 완과 비슷한 생각입니다.🙂
SOLID 원칙의 ISP 원칙과 비슷한 내용인 것 같습니다!

이후 고민과 궁금한 부분에 대해서 코멘트를 남겨보았습니다!
확인해보고 의견 나눠보면 좋을 것 같습니다~

Comment on lines +43 to +51
mutating func win() {
self._winCount += 1
}
mutating func lose() {
self._loseCount += 1
}
mutating func draw() {
self._drawCount += 1
}
Copy link

Choose a reason for hiding this comment

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

승/무/패 를 Int 타입으로 표현해보셨네요! Int 으로 표현하신 이유가 있을까요?
win(), lose(), draw() 승무패에 대한 메서드를 구현한 것도 좋지만
게임의 결과를 인자를 받는 메서드로 표현해보는 것은 어떨까요? 의견이 궁금합니다!

// Created by 홍승완 on 2024/03/20.
//

enum Hand: CaseIterable {
Copy link

Choose a reason for hiding this comment

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

CustomStringConvertible 프로토콜을 활용해봐도 좋을 것 같습니다!

Comment on lines +19 to +21
var randomHand: Hand {
return random()
}
Copy link

Choose a reason for hiding this comment

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

손패를 잘 구현해보셨네요!👍

var sut: RockPaperScissorsGame?

// MARK: 보로 비겼을 때
func test_paper_draw() throws {
Copy link

Choose a reason for hiding this comment

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

사용자와 컴퓨터의 가위바위보 테스트 코드를 잘 작성해보셨네요!
여기서 더 일반화하여 가위바위보 규칙에 대한 테스트로 작성해보면 어떨까요?
가위바위보 승/무/패 에 대한 규칙을 테스트하는 코드를 작성하면,
사용자의 승패, 컴퓨터의 승패를 더 적은 테스트 코드로 가위바위보 게임 규칙(승무패)을 커버할 수 있을 것 같습니다!

Comment on lines +178 to +183
print(">>>>>>>>>>>RANDOM TEST>>>>>>>>>>>>>>>>>>")
print("| userHand: \(userHand)", "computerHand: \(computerHand) |")
print("| user Win: \(win!) \t|\n",
"| user Lose: \(lose!)\t |\n",
"| user Draw:\(draw!)\t |")
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
Copy link

Choose a reason for hiding this comment

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

어떤 용도로 사용하는 print문 일까요? 불필요한 구문이면 제거하는 것이 어떨까요?

Comment on lines +201 to +204
repeat {
test_nextGame(sut: sut)
} while user.score.winCount < 3
&& computer.score.winCount < 3
Copy link

Choose a reason for hiding this comment

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

삼세판 규칙을 테스트 코드 안에서 구현하셨네요. 특별한 이유가 있을까요?
테스트 코드 안에서 로직을 구현하기 보다는 구현 코드에서 삼세판을 판가름할 수 있는 로직을 테스트하는 것은 어떨까요?

Comment on lines +230 to +234
if userWinCount > computerWinCount {
XCTAssertEqual(sut?.user.score.winCount, 3)
} else {
XCTAssertEqual(sut?.computer.score.winCount, 3)
}
Copy link

Choose a reason for hiding this comment

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

reset 테스트 구문에서 승패에 대한 테스트를 추가로 작성하신 이유가 있을까요?

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.

2 participants