-
Notifications
You must be signed in to change notification settings - Fork 56
[자동차 경주] 홍성우 미션 제출합니다. #43
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
base: main
Are you sure you want to change the base?
Changes from all commits
7dfc3e3
201dd79
0433c6a
551fa67
1782755
dde0d83
036fc23
4750c2f
b866161
f52d3e1
60c13d8
34e8bc3
e5602eb
8c98e4e
3e0bd2d
19093f3
d1d605e
4aa104c
2b0634d
2220522
9f475b3
5b895b2
1266eb8
b171b90
e82cdec
3c0c132
8e8d659
bec9b3d
b7f4cae
2ba8669
ee522df
2990ecf
22ad36c
3dabc1a
30d5e35
fcfabf1
e21bb04
ddfca01
7762fc7
2473b01
53a3558
e9f7f5f
5fa8a3a
1f2e800
32f95aa
5469556
55ad183
157c6cb
67f62cc
d0de7d4
dcff15e
ee6b9ea
b1eda47
1e93d97
f94302c
b7d94f4
d519bd1
69c7cf1
f05f9bb
d1b406b
a780a09
130c158
732324d
d091238
3aaf317
1c4933f
afe15d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,107 @@ | ||
| # kotlin-racingcar-precourse | ||
|
|
||
| ## 자동차 경주 게임 | ||
|
|
||
| --- | ||
| > 주어진 횟수동안 n대의 자동차가 전진 또는 멈추는 프로그램으로, 최종적으로 가장 멀리 간 자동차가 우승한다 | ||
|
|
||
| - 각 자동차들은 이름을 부여할 수 있다. | ||
| - 전진하는 자동차를 출력할 때, 자동차의 이름을 같이 출력한다. | ||
| - 자동차 이름은 쉼표로 구분한다. (이름은 5자 이내) | ||
| - 사용자가 몇 번의 이동을 할 것인지 입력한다. | ||
| - 전진 조건은 0-9 사이의 무작이 값을 구한 후 무작위 값이 4이상일 경우이다. | ||
| - 경주 게임을 완료한 후 누가 우승했는지 알려준다. (우승자는 한 명 이상일 수 있다) | ||
| - 사용자가 잘못된 입력값을 입력할 경우 `IllegalArgumentExcetpion`을 발생시킨다. | ||
|
|
||
| ### 실행 결과 예시 | ||
| ```text | ||
| 경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분) | ||
| >>> pobi,woni,jun | ||
| 시도할 횟수는 몇 회인가요? | ||
| >>> 5 | ||
|
|
||
| 실행 결과 | ||
| pobi : - | ||
| woni : | ||
| jun : - | ||
|
|
||
| pobi : -- | ||
| woni : - | ||
| jun : -- | ||
|
|
||
| pobi : --- | ||
| woni : -- | ||
| jun : --- | ||
|
|
||
| pobi : ---- | ||
| woni : --- | ||
| jun : ---- | ||
|
|
||
| pobi : ----- | ||
| woni : ---- | ||
| jun : ----- | ||
|
|
||
| 최종 우승자 : pobi, jun | ||
| ``` | ||
|
|
||
| ## 구현할 기능 | ||
|
|
||
| --- | ||
| ### view | ||
| **`InputManager`** | ||
| - 사용자에게서 자동차들의 이름을 부여받는다 | ||
| - 사용자에게서 이동의 횟수를 부여받는다 | ||
|
|
||
| **OutputManager** | ||
| - 가이드를 출력한다 | ||
| - 라운드별 실행 결과를 출력한다 | ||
| - 최종 우승자를 출력한다 | ||
|
|
||
| ### model | ||
| **InputValidator** | ||
| - 입력하는 값들에 대해서 조건을 만족하는지 확인한다 | ||
| - 차 이름이 조건을 만족하는지 확인 | ||
| - 이름은 `String` 형태로 주어진다 | ||
| - 이름은 5자가 넘지 않는다 | ||
| - 공백이 주어지는지 확인한다 | ||
| - `null`이 아니다 | ||
| - 이동 횟수가 조건을 만족하는지 확인 | ||
| - 이동 횟수는 `null`이 아니다 | ||
| - 이동 횟수는 양수로 주어진다 | ||
|
|
||
| **(interface)NumberGenerator** | ||
| - 수를 생성하는 `generate`에 대한 규칙이다 | ||
|
|
||
| **RandomNumberGenerator** | ||
| - 0-9까지의 수 중 랜덤 숫자를 내놓는다 | ||
| - `camp.nextstep.edu.missionutils.Randoms`의 `pickNumberInRange()`를 사용한다 | ||
|
|
||
| **Car** | ||
| - 생성될 때 입력한 이름이 조건에 맞는지 확인한다 | ||
| - 랜덤 번호를 생성하고 이 번호가 기준을 넘는다면 앞으로 전진한다 | ||
|
|
||
| **Judge** | ||
| - 각 차의 거리를 비교해 우승자를 가린다 | ||
|
|
||
| ### Controller | ||
|
|
||
| - 자동차의 이름을 받아 생성한다 | ||
| - 반복할 횟수를 입력받는다 | ||
| - 차를 움직이고, 매 라운드 결과를 출력한다 | ||
| - 우승자를 가리고 출력한다 | ||
|
|
||
| ## 개인적인 목표 | ||
|
|
||
| --- | ||
| 1. MVC 패턴을 지키겠다 | ||
| 2. 의미있는 이름을 짓도록 노력하겠다 | ||
| 3. 각 함수들이 하는 일이 작고 명확하게 하겠다 | ||
| 4. 좋은 커밋 메세지를 작성하겠다 | ||
| 1. 제목과 본문을 한 줄 띄워 작성 | ||
| 2. 제목은 영문 기준 50자 이내로 작성 | ||
| 3. 제목 첫 글자는 대문자 | ||
| 4. 제목 끝에 `.`금지 | ||
| 5. 본문은 영문 기준 72자마다 줄바꿈 | ||
| 6. 본문은 `무엇을`, `왜`에 중점으로 작성 | ||
| 5. 테스트 코드를 작성 할 때 `AssertTrue`, `AssertThat` 등 기존에 써본 것들 뿐만 아니라 새로운 것들을 시도하겠다 | ||
| 6. Kotlin 컨벤션을 지키면서 작성하겠다 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,9 @@ | ||
| package racingcar | ||
|
|
||
| import racingcar.domain.Judge | ||
| import racingcar.view.InputView | ||
| import racingcar.view.OutputView | ||
|
|
||
| fun main() { | ||
| // TODO: 프로그램 구현 | ||
| RacingController(InputView(), OutputView(), Judge()).run() | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,25 @@ | ||||||||||||||
| package racingcar | ||||||||||||||
|
|
||||||||||||||
| class InputValidator { | ||||||||||||||
| fun validateCarName(carNames: List<String>) { | ||||||||||||||
| require(carNames.isNotEmpty()) { "자동차의 이름을 입력하셔야 합니다" } | ||||||||||||||
| for (carName in carNames) { | ||||||||||||||
| require(carName.isNotBlank()) { "자동차의 이름은 빈칸일 수 없습니다" } | ||||||||||||||
| require(carName.length <= MAX_CAR_NAME_LENGTH) { "자동차의 이름은 5글자 이하여야 합니다" } | ||||||||||||||
|
Comment on lines
+7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 위의 부분은 // Car.kt - init
require(name.length < MAX_NAME_LENGTH) { "자동차 이름의 길이는 5자 이하여야 합니다" }
require(!name.contains(" ")) { "자동차 이름엔 공백이 포함되면 안됩니다" }그리고 조건 또한 |
||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| fun validateTotalMovement(totalMovement: String) { | ||||||||||||||
| require(totalMovement.isNotEmpty()) { "이동 횟수를 입력하셔야 합니다" } | ||||||||||||||
| require(totalMovement.isNotBlank()) { "빈칸으로 주어지면 안됩니다" } | ||||||||||||||
| try { | ||||||||||||||
| totalMovement.toInt() | ||||||||||||||
| } catch (e: NumberFormatException) { | ||||||||||||||
| throw IllegalArgumentException("정수를 입력하셔야 합니다") | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+15
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| companion object { | ||||||||||||||
| const val MAX_CAR_NAME_LENGTH = 5 | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| package racingcar | ||
|
|
||
| import racingcar.domain.Car | ||
| import racingcar.domain.Judge | ||
| import racingcar.domain.RandomNumberGenerator | ||
| import racingcar.view.InputView | ||
| import racingcar.view.OutputView | ||
|
|
||
| class RacingController(val inputView: InputView, val outputView: OutputView, val judge: Judge) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
class RacingController {
fun handleCarNames() // 입력 + 검증
fun handleRepeatTime() // 입력 + 검증
fun race() // 게임 실행 + 출력
private fun moveCar() // 게임 로직
private fun printCurrentCarState() // 출력
}위의 리뷰와 같은 부분이 있지만, Controller가 입력처리, 검증, 게임 실행, 출력까지 모두 담당하고 있어요. 게임 로직은 별도의 도메인 클래스로 분리하는게 좋다고 생각이 들어요! 제가 생각하는 Controller의 역할은 흐름을 제어하는 것인데요🤔 성우님은 어떤 역할이라고 생각하시나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 추가로 제가 생각하기에는 외부에서 접근하지 않아도 되는 파라미터라고 생각해요. 때문에 private val을 사용하는게 좋다고 생각이 들어요 😊 |
||
| fun run() { | ||
| val carNames = handleCarNames() | ||
| val repeatTime = handleRepeatTime() | ||
|
|
||
| outputView.printTextOfResult() | ||
| val raceResult = race(carNames, repeatTime.toInt()) | ||
| val winners = judge.judgeWinner(raceResult) | ||
| outputView.printWinner(winners) | ||
| } | ||
|
|
||
| fun handleCarNames(): List<String> { | ||
| outputView.printCarNameInputGuide() | ||
| val inputFromUser = inputView.getCarNameFromUser() | ||
| val carNames = Separator().separateName(inputFromUser) | ||
| InputValidator().validateCarName(carNames) | ||
| return carNames | ||
| } | ||
|
|
||
| fun handleRepeatTime(): String { | ||
| outputView.printMovementTimeInputGuide() | ||
| val repeatTime = inputView.getMovementTimeFromUser() | ||
| InputValidator().validateTotalMovement(repeatTime) | ||
| return repeatTime | ||
| } | ||
|
Comment on lines
+20
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // fun handleCarNames
val carNames = Separator().separateName(inputFromUser)
InputValidator().validateCarName(carNames)
// fun handleRepeatTime
InputValidator().validateTotalMovement(repeatTime)위의 함수에서 해당하는 부분을 보면 매번 함수 호출시마다 새로운 객체를 생성하고 있어요. 호출 횟수만큼 힙 메모리에 새 객체가 생성되면서 프로그램 실행 중 최소 2번 객체가 생성되는것 같아요. 또한 다른 개발자가 해석하면서 새 인스턴스를 매번 만드는 코드를 보면
라는 의문을 줄 수 있다고 보이는데요😊 싱글톤이나 companion object를 활용하는 방법은 고려 해보셨나요? 저는 싱글톤으로 같은 인스턴스를 사용하는게 좋다고 생각해요! |
||
|
|
||
| fun race(carNames: List<String>, repeatTime: Int): List<Car> { | ||
| val cars: List<Car> = carNames.map { carName -> | ||
| Car( | ||
| name = carName, | ||
| RandomNumberGenerator() | ||
| ) | ||
| } | ||
|
|
||
| repeat(repeatTime) { | ||
| moveCar(cars) | ||
| printCurrentCarState(cars) | ||
| } | ||
| return cars | ||
| } | ||
|
Comment on lines
+35
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
라는 요구사항이 있었는데요! 제가 생각했을때는 지금 |
||
|
|
||
| private fun moveCar(cars: List<Car>) { | ||
| for (car in cars) { | ||
| car.moveForward() | ||
| } | ||
| } | ||
|
|
||
| private fun printCurrentCarState(cars: List<Car>) { | ||
| for (car in cars) { | ||
| outputView.printCurrentLocation(car.name, car.distance) | ||
| } | ||
| println() | ||
| } | ||
|
Comment on lines
+56
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package racingcar | ||
|
|
||
| class Separator { | ||
| fun separateName(names: String): List<String> = names.split(NAME_SEPARATOR) | ||
|
|
||
| companion object { | ||
| const val NAME_SEPARATOR = "," | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package racingcar.domain | ||
|
|
||
| class Car(val name: String, val numberGenerator: NumberGenerator) { | ||
| var distance: Int = INITIAL_CAR_DISTANCE | ||
|
|
||
| init { | ||
| require(name.length < MAX_NAME_LENGTH) { "자동차 이름의 길이는 5자 이하여야 합니다" } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요구사항은 "이름은 5자 이하만 가능"으로 되어있어요. |
||
| require(!name.contains(" ")) { "자동차 이름엔 공백이 포함되면 안됩니다" } | ||
| } | ||
|
|
||
| fun moveForward() { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Car에 대한 테스트 코드가 없는 것 같아요!
|
||
| val randomNumber = numberGenerator.generateNumber() | ||
| if (randomNumber >= MOVE_FORWARD_CONDITION_NUMBER) { | ||
| distance++ | ||
| } | ||
| } | ||
|
Comment on lines
+11
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 바뀔수있는 요구사항이라 추상화 시켰으면 좋을꺼 같아요! |
||
|
|
||
| companion object { | ||
| private const val MAX_NAME_LENGTH = 5 | ||
| private const val INITIAL_CAR_DISTANCE = 0 | ||
| private const val MOVE_FORWARD_CONDITION_NUMBER = 4 | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,19 @@ | ||||||||||||||||||||||||||||||||||||||||||
| package racingcar.domain | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| class Judge { | ||||||||||||||||||||||||||||||||||||||||||
| fun judgeWinner(gameResult: List<Car>): List<String> { | ||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 승자 판단 알고리즘 상당히 인상적이네요! |
||||||||||||||||||||||||||||||||||||||||||
| val winners = mutableListOf<String>() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| var maxDistance = 0 | ||||||||||||||||||||||||||||||||||||||||||
| for (cars in gameResult) { | ||||||||||||||||||||||||||||||||||||||||||
| if (cars.distance == maxDistance) winners.add(cars.name) | ||||||||||||||||||||||||||||||||||||||||||
| else if (cars.distance > maxDistance) { | ||||||||||||||||||||||||||||||||||||||||||
| winners.clear() | ||||||||||||||||||||||||||||||||||||||||||
| winners.add(cars.name) | ||||||||||||||||||||||||||||||||||||||||||
| maxDistance = cars.distance | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return winners | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+4
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
이렇게 작성해도 좋을 것 같습니다💪🏻 |
||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package racingcar.domain | ||
|
|
||
| interface NumberGenerator { | ||
| fun generateNumber(): Int | ||
| } | ||
|
Comment on lines
+3
to
+5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 인터페이스를 만들어 주시고 테스트에서는 활용해주시지 않은 것 같아요. class FixedNumberGenerator(private val value: Int) : NumberGenerator {
override fun generateNumber(): Int = value
}성우님은 |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package racingcar.domain | ||
|
|
||
| import camp.nextstep.edu.missionutils.Randoms | ||
|
|
||
| class RandomNumberGenerator : NumberGenerator { | ||
| override fun generateNumber(): Int = Randoms.pickNumberInRange(RANDOM_MIN_NUMBER, RANDOM_MAX_NUMBER) | ||
|
|
||
| companion object { | ||
| const val RANDOM_MIN_NUMBER = 0 | ||
| const val RANDOM_MAX_NUMBER = 9 | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package racingcar.view | ||
|
|
||
| import camp.nextstep.edu.missionutils.Console | ||
|
|
||
| class InputView { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. object 말고 class 를 사용하신 이유가 있으실까요?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 마찬가지로 저도 궁금합니다!
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| fun getCarNameFromUser(): String = Console.readLine() | ||
| fun getMovementTimeFromUser(): String = Console.readLine() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package racingcar.view | ||
|
|
||
| class OutputView { | ||
| fun printCarNameInputGuide() { | ||
| println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)") | ||
| } | ||
|
|
||
| fun printMovementTimeInputGuide() { | ||
| println("시도할 횟수는 몇 회인가요?") | ||
| } | ||
|
|
||
| fun printTextOfResult() { | ||
| println() | ||
| println("실행 결과") | ||
| } | ||
|
|
||
| fun printCurrentLocation(name: String, distance: Int) { | ||
| print("$name : ") | ||
| repeat(distance) { | ||
| print("-") | ||
| } | ||
| println() | ||
| } | ||
|
Comment on lines
+17
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코틀린이면 한스트링에 변수를 삽입 가능했을텐데 나누신 이유가 뭘까요?? 가독성 부분에서 나누신걸까요? |
||
|
|
||
| fun printWinner(winners: List<String>) { | ||
| val result = winners.joinToString(separator = ", ") | ||
| print("최종 우승자 : $result") | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| package racingcar | ||
|
|
||
| import org.junit.jupiter.api.Test | ||
| import org.junit.jupiter.api.assertThrows | ||
|
|
||
| class InputValidatorTest { | ||
| @Test | ||
| fun `자동차의 이름이 없다면 IllegalArgumentException을 발생시킨다`() { | ||
| // given | ||
| val carName = mutableListOf<String>() | ||
|
|
||
| // when & then | ||
| assertThrows<IllegalArgumentException> { InputValidator().validateCarName(carName) } | ||
| } | ||
|
Comment on lines
+7
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 테스트에서 변경하지 않는 리스트를 |
||
|
|
||
| @Test | ||
| fun `자동차의 이름이 5글자를 초과하면 IllegalArgumentException을 발생시킨다`() { | ||
| // given | ||
| val carName = listOf<String>("thisistest", "arguments") | ||
|
|
||
| // when & then | ||
| assertThrows<IllegalArgumentException> { InputValidator().validateCarName(carName) } | ||
| } | ||
|
|
||
| @Test | ||
| fun `자동차의 이름이 공백이라면 IllegalArgumentException을 발생시킨다`() { | ||
| // given | ||
| val carName = listOf<String>("pluto", " ") | ||
|
|
||
| // when & then | ||
| assertThrows<IllegalArgumentException> { InputValidator().validateCarName(carName) } | ||
| } | ||
|
|
||
| @Test | ||
| fun `이동 횟수가 정수가 아니면 IllegalArgumentException을 발생시킨다`() { | ||
| // given | ||
| val repeatTime = "String" | ||
|
|
||
| // when & then | ||
| assertThrows<IllegalArgumentException> { InputValidator().validateTotalMovement(repeatTime) } | ||
| } | ||
|
|
||
| @Test | ||
| fun `이동 횟수가 빈칸이라면 IllegalArgumentException을 발생시킨다`() { | ||
| // given | ||
| val repeatTime = "" | ||
|
|
||
| // when & then | ||
| assertThrows<IllegalArgumentException> { InputValidator().validateTotalMovement(repeatTime) } | ||
| } | ||
|
|
||
| @Test | ||
| fun `이동 횟수가 공백으로 주어지면 IllegalArgumentException을 발생시킨다`() { | ||
| // given | ||
| val repeatTime = " " | ||
|
|
||
| // when & then | ||
| assertThrows<IllegalArgumentException> { InputValidator().validateTotalMovement(repeatTime) } | ||
| } | ||
| } | ||
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.
코드 패키징을 분리하신 걸 보니,
InputValidator와Separator가 루트 패키지에 있네요!두 코드는 입력 처리 관련이니
view패키지에 있는 게 자연스럽다고 생각해요! 성우님이 이렇게 배치하신 이유가 궁금해요😊