-
Notifications
You must be signed in to change notification settings - Fork 252
[1단계 - 사다리 생성] 미아(이종미) 미션 제출합니다. #279
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
Conversation
lxxjn0
left a comment
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 키워드를 많이 사용하신 것 같은데 적절한 상황과 의도를 가지고 사용해보는 것은 어떨까요? final을 많이 사용하면 오히려 가독성을 해치는 경우도 있는 것 같아서요! (과거의 저도 그랬던 것 같아서 의견 전달드려봅니다)
그리고 남겨주신 질문에 대한 답변입니다.
TDD를 잘 하고 있는 것인지
TDD가 개발 과정에서 드러나다보니 제가 파악하기가 어려운 것 같습니다. 커밋의 경우 동작하는 코드 단위가 되어야 한다고 생각하기에 더더욱 TDD 프로세스를 드러내기 어려운 것 같습니다. 하지만 미아가 배운 과정에 맞게 요구사항에 대한 테스트를 작성하고 그에 맞는 프로덕션 코드를 작성한다면 올바른 과정이 맞지 않을까 생각합니다.
원시값에 대한 포장
이건 정답이 없는 부분이라고 생각합니다. 어떤 개발자가 생각하기엔 간단한 유효성 검증이 굳이 객체로 분리할 이유가 없다고 생각할 수도 있고 어떤 개발자는 유효성 검증 하나만으로도 충분히 의미를 가진다고 생각할 수도 있기 때문입니다. 이는 클로버가 더 적절하다고 생각하는 방향으로 결정하셔도 문제가 없을 것 같아요 :)
| public class ContinuousPathException extends RuntimeException { | ||
| private static final String MESSAGE = "연속된 사다리 발판이 존재합니다."; | ||
|
|
||
| public ContinuousPathException() { | ||
| super(MESSAGE); | ||
| } | ||
| } |
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.
프로그램 규모가 작고 예외가 많지 않아 메시지 단위로 정의하였습니다. 약간의 오버헤드와 새로운 예외가 발생할 때마다 클래스를 생성해야 하는 단점이 있을 것 같습니다. 장점은 예외 클래스를 아예 정의해주는 것이 스트링으로 예외 메세지를 적어주는 것보다 가독성이 좋고(깔끔함) 테스트할 때도 해당 예외 클래스의 인스턴스인지 확인하면 돼서 편하다는 것입니다. 스티치는 메시지 단위 예외 클래스의 단점이 더 크다고 생각하시나요 ?!
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.
커스텀 예외를 정의하는 것이 메시지를 적어주는 것보다 가독성 측면에서 더 장점이 있는지는 저도 명확히는 모르겠습니다. 커스텀 예외를 정의하면서 메시지도 드러나게 작성이 가능하니깐요.
저 같은 경우는 커스텀 예외를 예외 로직을 처리하기 위한 목적에 더 가까운 것 같아요. 만약 A라는 예외가 발생할 때 특정한 로직을 수행해야 한다면 그런 경우는 커스텀 예외를 작성해서 처리할 수 있도록 사용합니다.
아래 글을 한번 읽어보시면서 커스텀 예외에 대한 생각을 고민해보면 좋을 것 같아요!!
https://tecoble.techcourse.co.kr/post/2020-08-17-custom-exception/
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.
현재 프로그램에서는 커스텀 예외를 활용했다 말할 수 있는 로직이 없네요..! 불필요한 것 같아 IllegalArgumentException이나 RuntimeException으로 대체하였습니다 감사합니다!
| } | ||
|
|
||
| private void validateDuplicatedNames(final List<String> names) { | ||
| final Set<String> uniqueNames = Set.copyOf(names); |
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의 of 메서드가 아닌 copyOf 메서드를 사용하였는데 특별한 이유가 있을까요?
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.
of 를 사용하려면 가변인자를 매개변수로 넘겨주어야 하는데, List를 바로 Set으로 복사시켜주는 copyOf가 더 적절하다고 판단했습니다 !
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.
copyOf는 결국 새로운 영역에 동일한 데이터를 생성해서 사용하기에 메모리 소비가 발생할 수 밖에 없습니다. 개발자가 사용하는 상황 내에서 데이터 변조의 위험성이 없는 경우에는 굳이 copyOf를 사용해서 얻는 장점이 있는지 모르겠어요.
외부에 제공되는 데이터가 아닌 특정 메서드 내 로컬 변수에서 사용이라면 이런 부분도 고려해보면 좋을 것 같아요
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.
메서드 시그니처에 집중하다 보니 불필요한 메모리 소비를 고려하지 못했네요. step2에서 수정해보도록 하겠습니다 !
| @@ -0,0 +1,27 @@ | |||
| package ladder.domain.ladder; | |||
|
|
|||
| public enum Path { | |||
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.
Path 객체 자체는 도메인 객체가 맞다고 생각합니다. LadderStep에서 하나의 사다리 발판을 나타내기 위해 도입한 enum이기 때문입니다. 단순히 boolean 값으로 표시하는 것보다 가독성과 유지보수성을 고려하면 더 좋을 것이라 판단했었습니다..! 이에 따른 로직도 Path 객체의 메서드로 관리되고 있습니다.
다만, 말씀주신 것처럼 Path의 속성이 출력에만 쓰이고 있습니다. 저는 출력을 넘어서는 도메인으로서의 의미가 있다고 생각했는데, 이렇게 활용하고 싶다면 출력에 쓰이는 shape 속성을 OutputView에서 상수로 관리해야 하는게 맞다고 생각하시나요? 또한 저는 shape로 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.
도메인은 말 그래도 비즈니스의 관심의 영역입니다. 지금의 Path는 비즈니스 상 의미가 있는 값은 맞지만 로직 내에서 비즈니스를 가지는 객체냐고 생각하면 그렇지 않은 것 같아요. 객체가 사용되는 영역과 상황에 맞게 패키지를 관리하는게 적절하지 않을까 생각합니다.
지금은 해당 객체가 결국 view 패키지에서 사용되기에 객체의 위치가 적절하지 않은 것 같아요.
미아가 말한 것처럼 오히려 뷰에서 상수로 관리하는 것이 더 적절할 것 같아요
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에서 사용되는 shape 속성을 OutputView에서 상수로 관리하도록 변경하였습니다. 피드백 감사합니다 👍
| assertEquals(" ", Path.EMPTY.getShape()); | ||
| assertEquals("-----", Path.EXIST.getShape()); |
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.
AssertJ에서 제공하는 메서드를 사용해보는 것은 어떨까요?
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.
assertThat(Path.EMPTY.getShape()).isEqualTo(" ");이 메서드를 추천하신게 맞을까요?
기능은 같은 것 같은데 특별히 AssertJ 메서드를 추천해주신 이유가 궁금합니다!
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.
AssertJ가 제공하는 검증 메서드의 종류가 다양하다보니 여러 상황에서 사용하기에 편하다고 생각합니다. 한번 AssertJ 라이브러리를 공부해보면 좋을 것 같아요!!
- 랜덤한 사다리 스텝을 생성하는 역할만 RandomLadderStepGenerator에게 맡기고, 보정은 LadderStep에서 진행한다. 항상 신뢰도 있는 LadderStep 객체를 사용할 수 있다.
lxxjn0
left a comment
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.
미아, 피드백 반영하시느라 수고 많으셨습니다!!
몇 가지 추가적인 부분에 대한 피드백이 필요할 것 같은데 이는 다음 단계 진행하면서 알려드리는게 좋을 것 같아요!! 다음 단계 코드를 보면서 추가적인 리뷰 전달드리도록 할게요!
| import ladder.view.InputView; | ||
| import ladder.view.OutputView; | ||
|
|
||
| public class LadderGameManager { |
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.
저는 같은 OutputView 객체를 ExceptionManager와 LadderGame에서 사용하도록 생성자 주입을 사용해주었는데요..! 따로 LadderGameManager 클래스를 만들기보다는 main application에서 의존성을 주입해 주는 것이 더 적절하려나요 🤔 step2에서 더 고민해보도록 하겠습니다 ..!
안녕하세요 스티치! 반갑습니다 😊
사다리 타기 미션을 위해 생성한 사다리 관련 도메인들은 다음과 같습니다.
피드백을 받고 싶은 부분은 아래와 같습니다.
Participant(참가자 도메인 클래스)에String name변수가 존재해서Participant에서name에 대한 검증을 진행하고 있습니다. 이 역시 도메인 클래스(Name)로 분리해야 좋은 코드라고 생각하시나요?