본문 바로가기
우테코 6기 프리코스

[우테코] 3주차 회고

by ♡˖GYURI˖♡ 2023. 11. 23.

3주차 미션

3주차 미션은 로또였다!

 

<추가된 요구 사항>

  • 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.
    • 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다.
  • else 예약어를 쓰지 않는다.
    • 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
    • else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
  • Java Enum을 적용한다.
  • 도메인 로직에 단위 테스트를 구현해야 한다. 단, UI(System.out, System.in, Scanner) 로직은 제외한다.
    • 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 분리해 구현한다.
    • 단위 테스트 작성이 익숙하지 않다면 test/java/lotto/LottoTest를 참고하여 학습한 후 테스트를 구현한다.

 

이 중 가장 어려웠던 것은 else 예약어 쓰지 않기... 아니 어떻게 if-else없이 처리하지?? 라는 의문부터 들었다. 배울 때 if-else를 같이 배웠으니 당연히 사용할 때도 함께여야 한다는 내 고정관념이 깨지는 순간이었다... 

 

또 미리 작성된 채로 제공된 Lotto 클래스가 있었는데,

  • Lotto에 필드(인스턴스 변수)를 추가할 수 없다.

라는 문구를 보고 필드? 인스턴스 변수? 그게 뭔데... 부터 시작해야 했었다.

분명 배웠는데 왜 항상 기억이 안 나는건지🥹

 

 

PR 리뷰

ENUM 에서 함수형 인터페이스를 사용할 수 있는지 몰랐네요..! 2등과 3등 당첨을 구분하는게 조금 어려웠는데 이런 방법도 있구나 알아갑니다.
Enum 함수형 인터페이스 사용방법이 정말 감탄스럽네요..
로직의 흐름은 전체적으로 잘 이해됩니다!다만 요구사항중 에러발생한 부분에서 입력을 다시받는건 구현이 안된 것 같네요, 4주차엔 한번 고민해보시고 다른 코드도 리뷰하면서 적용해보시면 좋을 것 같습니다!
저는 계속 고민하고 있는 부분인데, View 에서 Domain의 getter 함수를 사용하는게 좋은 방법은 아니라고 생각이 듭니다.
4주차엔 한번 다른 방법을 고민해보고 적용해보시는건 어떨까요?
혹시 InputView 를 따로 만든다음 다른 InputView 에서 extends 한 이유가 따로 있을까요? 따로 이유가 생각나지 않아서 질문드려요..!
Ticket 을 클래스화 하는건 어떘을까요?
로또 숫자 범위나 사이즈의 경우 generator 등 따른 클래스에서도 사용되는 것 같은데 enum으로 처리해두는 게 어떨까요?
enum을 접근제한자를 통해 사용 패키지를 제한하면 Enum 처리가 괜찮을 것 같습니다
클래스 이름 관련해서, MainController는 너무 일반적이고 포괄적인 이름인 것 같습니다. 도메인 이름을 포함하면 좀 더 구체적일 것 같습니다. LottoController처럼요.
지금 메서드 추춣하신 것들을 보면 거의 다 객체를 생성하는 로직들을 담고 있는 것으로 보입니다. 저는 객체 생성은 컨트롤러보다는 객체 자신에게 있다고 보는데요. 정적 팩토리 메서드를 이용해서 매개변수들을 받고 바로 객체를 생성하면 불필요한 코드들도 줄고 책임이 명확해 질 것 같습니다.
변수 ,클래스, 함수 이름을 지을 때 코드를 보는 사람 모두가 알고 있지 않다고 생각되면 줄임말을 사용하지 않는 것이 좋습니다. 여기서는 calc 보다는 그대로 calculate를 사용하는 것이 더 적절해보여요. 이름이 길어진다고 해도 줄임말을 사용해 의미가 불분명해지는 것보다는 나을 것 같습니다.
if문은 긍정 조건문인 것이 의도를 파악하기 더 쉬운 것 같아요
generateLotto()를 호출할 때마다 객체를 생성하고 있어요
0.1을 매직넘버로 의미를 부여해주면 가독성이 더 좋아질 것 같아요!
반복되는 상수네요 enum으로 처리해서 재사용하면 좋겠어요!
wrapper class로 선언하신 이유가 있을까요??
Lotto 클래스에 isContain()가 있던데 이 메서드를 호출해서 검증하면 어떨까요?
중복되는 로직이 반복되고 있어요 분리가 필요하지 않을까 생각합니다!
merge() 메서드를 사용하면 더 간결하게 리팩토링할 수 있어요!
PATTERN을 String으로 선언하고 위처럼 사용하면 더 간결하게 처리할 수 있습니다!
view에 너무 많은 책임이 있는 것은 아닐까?하는 고민을 해보면 좋겠습니당
IllegalArgumentException을 상속한 각각의 커스텀 예외들은 모두 메시지로 "[ERROR]"를 포함하고 있는데요.이 경우 해당 메시지의 세부 사항이 변경되었을 때 일일이 수정을 해 주어야 하는 단점이 있을 것 같아요.해당 값을 별도의 상수 클래스로 분리해 사용하면 좋을 것 같습니다.
이런 부분들 역시 요구사항의 변경에 유연하게 대처하기 위해선 상수를 활용해 줄 수 있을 것 같아요.
해당 클래스는 내부적으로 Randoms 클래스를 사용하는 클래스인데요.이 클래스의 경우 다음의 두 가지 이유로 의존성을 낮추는 것을 추천드립니다!

● 제어할 수 없는 값을 사용한다.
● 외부 API를 사용한다.

자세한 이유에 대해서는 제 설명보다, 우아한 테크 세미나 영상을 하나 공유 드릴게요.
[우아한테크세미나] 테크 리더 3인이 말하는 "개발자 원칙"
첫 번째 세션인 "제어할 수 없는 것에 의존하지 않기" 입니다.

비즈니스 로직이 사용하는 부분 중 제어할 수 없는 부분은 추상화를 제공하여 테스트를 진행할 때는 적절한 다른 클래스로 갈아끼울 수 있습니다!
메서드 명이 중복되고 있는데요, 같은 메서드를 오버로딩 하는 것 역시 하나의 방법이지만 메서드의 역할을 더 잘 나타내기 위해선 디테일한 부분을 나타낼 수있도록 서로 다른 메서드명을 주는 것도 좋을 것 같아요.
저는 getter 사용시에는 외부에서 해당 객체의 변경을 일으킬 수 없도록 조심하는 편인데요.이 경우 역시 getLottos()를 통해 가져온 List에 값을 추가하는 등의 변경이 가능할 것 같습니다.다음과 같이 불변 리스트를 반환해 보는 건 어떨까요?
또는, 수정을 하더라도 해당 객체는 영향 받지 않도록 새로운 객체를 생성하여 반환해 줄 수도 있을 것 같아요.
저는 특별한 논리적인 의미를 가지지 않는 상수들은 추출하지 않고 매직 넘버로 그대로 사용하는 편입니다.
만약 해당 값들이 논리적인 의미를 가진다면, 그 의미를 잘 나타낼 수 있도록 네이밍을 해보는 건 어떨까요?
해당 메서드도 정확히 말하면 Ticket을 받아오는 게 아니라 Ticket의 수량을 받아오는 것이기 때문에 
getTicketSize() 정도의 네이밍을 고려해 보시면 좋을 것 같아요.
enum의 필드로 BiPredicate를 사용하고, 해당 필드를 사용해 각각의 결과를 판별하는 것은 정말 마음에 드네요!! 👍
EnumMap을 활용한 것도 좋아요!! 👍
정-말 사소한 이야기지만, private 메서드인 updatePrizeCount가 public 메서드인 calcPrizeResult에게만 딱 한번 호출이 된다면, updatePrizeCount 메서드가 calcPrizeResult 메서드 바로 아래에 위치하면 좀 더 일기 편해진다고 생각해요!
result가 int형으로 정의되어 있는데요.1등의 상금이 20억임을 고려하면 1등이 2번 이상 당첨되었을 경우 오버플로우의 위험이 존재할 것 같아요! 제가 놓치고 있는 부분이 있을까요?
InputView를 상속하는 모든 클래스가 공통적으로 getValue()와 같은 동일한 일부 메서드를 구현하고 있는데요. 이 경우 차라리 InputView를 인터페이스나 추상 클래스로 만들어서 getValue()의 구현을 강제시키는 것이 더 좋을 것 같다고 생각합니다!
enum을 접근제한자를 통해 사용 패키지를 제한하면 Enum 처리가 괜찮을 것 같습니다
정말 사소하지만 this.numbers = sorted(numbers); 처럼 한번에 작성해도 될 것 같습니다!
입력 기능마다 클래스를 분리해서 각각 유효성검사를 진행하는 방법은 좋은 방법이라고 생각이되는데 생성해야되는 객체가 많이지는 것에 고민이 되네요.. 어떻게 생각하시나요??
입력에서 변환하지 해주는 부분은 비즈니스 로직이 아닐까 생각되는 것 같습니다!
해당 클래스에서 메서드가 모두 static으로 사용하고 계시는데 이유가 있나요..??

 

  • 요구사항 중 에러 발생 시 재입력을 받아야 한다는 것이 구현되지 못함
  • View의 책임이 너무 큼
  • Ticket의 클래스화
  • Enum 처리
  • 클래스명, 메서드명의 구체화
  • if 내 조건문은 긍정문으로

등등 이번 주에도 다양한 리뷰를 받았다. 4주차에도 MVC 패턴 내에서 책임을 어떻게 나눠야할지가 제일 큰 고민이었고 3주차의 이 리뷰들을 참고하여 최~대한 나누려고 노력했지만 여전히 어려운 점이다ㅠ

 

 

 

스스로에게 하는 피드백

  1. 코드를 더 간결하고 이해하기 쉽게 작성하자!
  2. enum과 상수를 적극 활용하자!
  3. 클래스명과 함수명을 더 구체적으로 작성하자!
  4. 책임을 더 쪼개자!
  5. 각각의 책임이 어디로 할당되어야 할지 더 깊은 고민을 해보자!
  6. 요구사항을 꼼꼼히 읽자ㅠㅠ!!

 

 

https://github.com/woowacourse-precourse/java-lotto-6/pull/644

 

[로또] 임규리 3주차 미션 제출합니다. by IM-GYURI · Pull Request #644 · woowacourse-precourse/java-lotto-6

이번 미션을 진행하면서 제일 고민되었던 점은 '과연 이 코드가 남들에게도 잘 읽힐까?'였습니다. 저는 제 코드라 익숙하지만 다른 분들이 보시기에는 어떨지 궁금해요! 함수명, 클래스명, 코드

github.com