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단계 로또 제출합니다. #22

Merged
merged 56 commits into from
Feb 18, 2023

Conversation

tmdgh1592
Copy link
Member

@tmdgh1592 tmdgh1592 commented Feb 16, 2023

안녕하세요 제리님!
제리님께 리뷰받게되어 영광입니다 :)
우선 리뷰요청 버튼이 의도치않게 3번 눌려 푸시가 여러번 날아갔을텐데 죄송하다는 말씀드립니다.

최대한 TDD + 페어프로그래밍으로 미션을 수행하려고 하다보니 시간에 쫓겨 코드에 미숙함이 많이 묻어나오고 있습니다. 😥
step2를 진행하면서 리뷰어님께서 주시는 리뷰를 바탕으로 개선해보기 위해 노력하겠습니다!

이번 미션에서는 일급 컬렉션, 불변, 원시값을 포장한 클래스를 적용해보고자 신경썼습니다.
그럼에도 놓친 부분이 많은 것 같아 궁금한 부분에 대해 질문을 드리고 싶습니다.

  1. Rank(당첨 등수)을 Key로 갖고, 해당 Rank를 몇개 맞추었는지에 대한 정수값을 Value로 하는 Map을 사용했습니다.
    + 구매한 로또 객체를 List로 반환하는 로직이 있습니다.
    이 경우에도 모두 일급컬렉션으로 감싸주는 것이 좋은지 궁금합니다!
  2. 특별한 비즈니스 로직을 가지고 있지 않은 원시값, 컬렉션의 경우에도 모두 포장해줄 필요가 있는지 궁금합니다!
  3. 테스트하기 위한 다양한 값을 주입해주기 위해 @MethodSource를 자주 사용하였는데, 가독성이 많이 떨어지는 느낌을 받았습니다.
    @MethodSource가 필요하지 않은 경우에는 @valuesource 또는 @CsvSource를 사용하였는데, List와 같은 인자를 받기 위해서는 제가 알고 있는 선에서는 + 구글링해본 결과 @MethodSource밖에 떠오르지 않아 더 나은 개선책이 있는지 궁금합니다!
  4. 도메인 모델에서 public으로 외부에서 접근할 수 있는 메서드는 모두 테스트 코드 작성이 필요한지 궁금합니다!
  5. Controller가 도메인 모델을 멤버 변수로 가지고 있는 것이 바람직한 형식인지 궁금합니다!
    찾아보는 글마다 내용이 달라 혼란이 생겨 질문드립니다..!

긴 질문글 읽어주셔서 감사합니다🙂

- lotto 패키지 내 Number 관련 클래스는 lotto.number 패키지로 이동
- Rank 클래스는 Rank 패키지로 분리
@vagabond95
Copy link

vagabond95 commented Feb 16, 2023

  1. 일급 컬렉션, 원시값으로 굳이 감싸는 이유는 무엇일까요? 이전에 감싸주셨던 이유가 해당 케이스들에도 포함된다면 같이 감싸주시면 될 거 같아요 :)

  2. 저도 얘기주신 방법에서 크게 벗어나지는 않고 있는데요, 추가로 괜찮은 방법이 떠오른다면 공유드리겠습니다 :)

  3. 테스트 코드를 작성하는 이유, 테스트 코드를 통해 무엇을 하고자하는 것인지에 대해 고민해보시면 좋겠어요.

  1. 컨트롤러의 역할을 어떻게 이해하고 있는지,
  2. MVC 에서 Model 에 도메인 모델도 포함되는지 고민해보시면 될 것 같아요. 아키텍처에 대한 세부 디테일은 개인차가 있기 때문에 해당 아키텍처가 추구하는 바가 무엇인지를 인지하는 것이 우선이라고 생각됩니다.

Copy link

@vagabond95 vagabond95 left a comment

Choose a reason for hiding this comment

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

전반적으로 가독성이 뛰어났다는 느낌을 많이 받았어요.
그만큼 세세하게 각 클래스 함수의 역할과 네이밍, 구조등을 신경써주신 것 같습니다 👍

질문 주신 내용을 비롯하여 구현 내용에 대하여 몇가지 코멘트를 남겼어요.
확인 후 리뷰요청 부탁드릴게요!

.editorconfig Outdated
@@ -0,0 +1,97 @@
root = true

Choose a reason for hiding this comment

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

이러한 파일들은 .gitignore 로 관리 부탁드려요~

Copy link
Member Author

Choose a reason for hiding this comment

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

외부에 드러나면 좋지 않은 파일에 대해 .gitignore 파일에 추가해두었습니다!


fun IntRange.generateDistinctRandomNumbers(count: Int): List<Int> = shuffled().take(count)

fun Int.divideByThousand(): Int {

Choose a reason for hiding this comment

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

이 부분은 money 에 대한 원시값을 포장하고, 해당 클래스 내부에서 처리되는 것이 더 적절하지 않을까요?

Choose a reason for hiding this comment

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

divideByThousand 라는 네이밍은 비교적 common 한데,
오류 메세지는 '입력값' 이라는 내용을 내포하고 있는 부분 자체가 common 한 케이스를 다루지 않는 증거가 되는 것 같아요.

Copy link
Member Author

Choose a reason for hiding this comment

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

함수를 작성하면서 약간 모호하다는 생각을 하였는데 말씀해주신 것처럼 common에서 다루기에는 '입력값'이라는 오류 메세지는 적합하지 않은 것 같습니다!
해당 로직은 별도의 Money라는 래퍼 클래스로 옮겼습니다!

}

private fun judgeEitherSecondOrThird(matchBonus: Boolean): Rank {
if (matchBonus) return SECOND

Choose a reason for hiding this comment

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

특정 등수에 대해 조건문을 두지 않고, 일관된 방식으로 등수를 구하도록 리펙토링 해볼 수 있을까요?
현재와 같은 구조는 보너스번호를 가지는 등수가 추가될 때 마다 if 문이 계속 추가되어야하는 구조가 될 거 같아요.

Copy link
Member Author

Choose a reason for hiding this comment

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

enum의 values() 메서드를 활용하여 등수를 구하는 로직을 리팩터링하였습니다!

package domain.rank

enum class Rank(val countOfMatch: Int, val winningMoney: Int) {
FIRST(6, 2_000_000_000),

Choose a reason for hiding this comment

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

언더스코어로 가독성 확보 👍

fun validateNumeric(value: String): Int =
value.toIntOrNull() ?: throw IllegalArgumentException(NOT_NUMERIC_EXCEPTION_MESSAGE)

fun validateWinningNumbersIsNumeric(value: List<String>): List<Int> {

Choose a reason for hiding this comment

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

이렇게 domain 의 요구사항에 가까운 검증 함수는 해당 클래스에 선언되는게 더 적절하지 않을까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

제시해주신 피드백과 기능 목록 문서를 다시 살펴보면서, domain 요구사항과 관련된 검증 함수를 ui 레이어에서 다루는 것은 적합하지 않아보임을 깨달았습니다!
숫자인지에 대한 여부를 각 domain 모델에서 다루도록 리팩터링하였습니다.

tmdgh1592 and others added 17 commits February 17, 2023 15:11
- LottoController에서 멤버 변수를 사용하지 않는 구조로 변경
- initWinningLottoNumbers()를 호출되지 않은 상태에서 matchLottos()를 호출할 수 있도록 변경
- LottoGameController 메서드를 분리하면서 LottoGame에서 LottoMachine 객체를 생성자로 받지 않도록 변경
@tmdgh1592
Copy link
Member Author

tmdgh1592 commented Feb 17, 2023

안녕하세요 제리님 : )
제리님께서 제공해주신 피드백과 페어의 리뷰어분의 피드백을 기반으로 리팩터링을 마치고, 2차 피드백을 요청드리게 되었습니다!

감사드리게도 질문드린 내용에 대한 답변과 더불어 피드백을 통해 궁금한 점이 많이 해결되었습니다!
다만 4번 질문에 대해서는 4. 라고만 작성되어 있어서 제가 잘 이해하지 못했습니다..!
혹시 스스로 생각해봤으면 좋겠다는 의미에서 공백으로 남겨주신건지 글이 지워진건지 여쭤봐도 될까요..?! 🙂

@vagabond95
Copy link

앗 포메팅이 제대로 되지 않았나 봅니다. 4. 하위에 적은 내용이 4번 질문에 대한 답변이었어요.
아키텍처에 대해 제 생각을 조금 더 남겨보자면, MVC, MVP, MVVM 등 여러 형태의 아키텍처가 등장하곤하는데 결국 궁극적으로 이러한 아키텍처들이 출현하게된 이유는 무엇인지 / 공통점은 무엇인지를 고민하시다보면 MVC 각각에 속하는 구현에 대한 감이 잡히실 수 있을거 같습니다 :)

Copy link

@vagabond95 vagabond95 left a comment

Choose a reason for hiding this comment

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

코멘트 드렸던 부분 모두 잘 반영해주셨네요 👍
TDD 방식으로 요구사항을 진행해주신 부분도 좋았습니다 ㅎㅎ

1단계는 크게 피드백 드릴 부분이 없어 머지하도록 하겠습니다. 남긴 코멘트는 다음 단계 진행 시 참고 부탁드려요~!

FIFTH.countOfMatch -> FIFTH
else -> MISS
}
fun valueOf(countOfMatch: Int, matchBonus: Boolean): Rank {

Choose a reason for hiding this comment

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

rank 의 각 element 가 보너스 번호 검사 여부를 알고 있다면, 아래 조건문도 제거할 수 있지 않을까요? :)

Copy link
Member Author

Choose a reason for hiding this comment

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

그 부분에 대해서 페어와 함께 이야기를 나눈적이 있습니다!
그러다가 지금의 방식으로 구현하게 된 이유가 만약, 5등에 당첨된 경우에도 matchBonus가 true이거나 false인 2가지 경우가 있을 수 있는데, 이러면 각 등수별로 element를 하나씩 더 추가해야만 하는 문제가 있다고 생각했습다.

이런 경우에도 valueOf를 위해 element들이 추가되는 것이 더 나은지 궁금합니다!


import util.common.constant.ERROR_PREFIX

class Money(val amount: Int) {

Choose a reason for hiding this comment

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

Money 에 대한 비즈니스 로직을 스스로 처리할 수 있게 되었네요 👍

@vagabond95 vagabond95 merged commit 24ae24c into woowacourse:tmdgh1592 Feb 18, 2023
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