본문 바로가기
Backend 🧦/우테코 5기 프리코스 💡

[우아한테크코스 백엔드5기] 프리코스 3주차 로또 회고

by 서니서닝 2022. 12. 13.
728x90

🔗 미션 링크

3주 차 미션 : https://github.com/woowacourse-precourse/java-lotto
작성한 코드 : https://github.com/woowacourse-precourse/java-lotto/pull/666


📃 미션

  • 로또 : 자동으로 구입한 로또의 당첨여부와 수익률을 출력한다.
  • 미션은 java-lotto 저장소를 Fork & Clone하여 Pull-Request하여 제출한다.
  • 기능을 구현하기 전 docs/README.md에 구현할 기능 목록을 정리 추가한다.
  • Git 커밋 단위는 기능 목록 단위로 추가한다.
  • 커밋 메시지 컨벤션 가이드를 참고해 커밋 메시지를 작성한다.
  • indent depth는 2까지 허용
  • 3항 연산자 사용X
  • 함수가 한가지 일만 하도록
  • JUnit5와 AssertJ를 이용하여 테스트 코드로 확인
  • 추가요구사항
    • 함수의 길이가 15라인을 넘어가지 않도록
    • else예약어 쓰지않음
    • Java Enum 적용
    • 도메인 로직에 단위테스트 구현, 단 UI로직은 제외
      • 핵심로직와 UI로직 분리
    • Lotto 클래스를 활용하여구현

🔧 2주차 피드백

  • README를 상세히 작성한다
  • 기능목록을 재검토한다
    • 기능 목록을 클래스 설계와 구현, 함수(메서드) 설계와 구현과 같이 너무 상세하게 작성하지 않는다. 클래스 이름, 함수(메서드) 시그니처와 반환값은 언제든지 변경될 수 있기 때문이다. 너무 세세한 부분까지 정리하기보다 구현해야 할 기능 목록을 정리하는 데 집중한다. 정상적인 경우도 중요하지만, 예외적인 상황도 기능 목록에 정리한다. 특히 예외 상황은 시작 단계에서 모두 찾기 힘들기 때문에 기능을 구현하면서 계속해서 추가해 나간다.
  • 기능 목록을 업데이트한다
    • readme는 변경될 수 있음. 죽은 문서가 아닌 살아있는 문서로 만들기
  • 값을 하드 코딩하지 않는다
    • 문자열, 숫자 값을 하드코딩하지 말고 상수(static final)을 만들고 이름을 부여
  • 구현 순서도 코딩 컨벤션이다
    • 클래스는 상수, 멤버변수, 생성자, 메서드 순으로 작성한다.
  • 변수 이름에 자료형은 사용하지 않는다
  • 한 함수가 한 기능만 담당하게 한다
    • 한 함수 내에서 안내 문구 출력, 사용자 입력, 유효값 검증 등 여러 일을 하고 있다면 적절히 분리
  • 함수가 한가지 기능을 하는지 확인하는 기준을 세운다
  • 테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해본다
  • 처음부터 큰 단위의 테스트를 만들지 않는다
    • 큰단위 테스트 : 숫자 야구 게임을 시작해서 사용자가 숫자를 입력하면, 컴퓨터 숫자와 비교하여 결과를 알려준다.
    • 작은 단위 테스트:
      • 사용자의 숫자가 컴퓨터의 숫자와 하나도 일치하지 않으면 낫싱을 출력
      • 사용자의 숫자가 컴퓨터의 숫자와 1개는 일치하고, 위치가 다르면 1볼을 출력

작성한 ReadMe

# java-lotto

---
## 프로젝트 소개
로또 게임을 진행한다.
사용자가 1000원 단위의 로또를 구입할 시 당첨번호와 보너스 번호를 비교하여 당첨내역과 수익률을 알려준다.

## 개발환경
JDK 11


## 기능 목록
- [x] 로또 구입 금액을 입력하면, 구입 금액에 해당하는 만큼 로또를 발행
  - [x] 구입 금액으로 발행된 로또 개수 확인
  - [x] 개수만큼 로또 발행
    - [x] 1 ~ 45 사이 랜덤으로 숫자 6개 생성
  - [x] 생성된 로또 출력
- [x] 당첨 번호를 입력받음
- [x] 보너스 번호를 입력받음
- [x] 사용자가 구매한 로또 번호와 당첨 번호를 비교
  - [x] 당첨 번호 6개 비교
  - [x] 보너스볼 비교
- [x] 당첨 내역을 출력
  - [x] 3개 일치
  - [x] 4개 일치
  - [x] 5개 일치
    - [x] 보너스볼 일치
  - [x] 6개 일치
- [x] 수익률을 출력
  - [x] 수익률 계산(당첨금액/구매금액)*100
  - [x] 수익률은 소수점 둘째 자리에서 반올림
- [] 예외 상황시 에러문구 출력
  - [x] 로또 구입 금액이 1000원으로 나누어 떨어지지 않을 경우
  - [x] 로또 번호가 1부터 45 사이 숫자가 아닐 경우
  - [x] 로또 번호에 중복이 있을 경우
  - [x] 로또 번호의 개수가 6개가 아닐 경우
  - [x] 보너스 번호의 개수가 1개가 아닐 경우
  - [x] 로또 번호에 숫자가 아닌 문자가 들어왔을 경우
  - [x] 보너스 번호에 숫자가 아닌 문자가 들어왔을 경우
  - [x] 로또 구입 금액이 숫자가 아닌 문자가 들어왔을 경우

## 고려사항
- [x] 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현
- [x] else 예약어를 쓰지 않는다.
- [x] Java Enum을 적용한다.
- [x] 도메인 로직에 단위 테스트를 구현해야 한다. 
  - [x] UI(System.out, System.in, Scanner) 로직은 제외한다.
- [x] Random 값 추출은 `camp.nextstep.edu.missionutils.Randoms`의 `pickUniqueNumbersInRange()`를 활용한다.
- [x] 사용자가 입력하는 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용한다.
- [x] 제공된 `Lotto` 클래스를 활용해 구현해야 한다.
  - [x] `Lotto`에 매개 변수가 없는 생성자를 추가할 수 없다.
  - [x] `numbers`의 접근 제어자인 private을 변경할 수 없다.
  - [x] `Lotto`에 필드(인스턴스 변수)를 추가할 수 없다.
  - [x] `Lotto`의 패키지 변경은 가능하다.
- [x] JDK 11 버전에서 실행 가능해야 한다.
- [x] 프로그램 실행의 시작점은 `Application`의 `main()`이다.
- [x] `build.gradle` 파일을 변경할 수 없고, 외부 라이브러리를 사용하지 않는다.
- [] [Java 코드 컨벤션](https://github.com/woowacourse/woowacourse-docs/tree/master/styleguide/java) 가이드를 준수하며 프로그래밍한다.
- [x] 프로그램 종료 시 `System.exit()`를 호출하지 않는다.
- [x] 프로그램 구현이 완료되면 `ApplicationTest`의 모든 테스트가 성공해야 한다.
- [x] 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 이름을 수정하거나 이동하지 않는다.
- [x] indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
- [x] 3항 연산자를 쓰지 않는다.
- [x] 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.
- [x] JUnit 5와 AssertJ를 이용하여 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인한다.

📊 다이어그램

📖 3주차를 통해 배운 내용

  • README
  • 테스트 코드
    • TDD의 필요성
  • UI와 도메인
  • ENUM

3주차가 되었지만, 여전히 익숙해지는 것 보다 새로 배우는게 훨씬 많은 주차였다.

나에게 있어서 ReadMe작성하는 것이 어찌보면 가장 많이 머리를 써야 했던 부분이였다. ReadMe를 수정해선 안된다고 생각하여, 처음에 실수없이 빠진 것 없이 설계하려고 노력했기 때문이다. 이 때문에, commit한거 다시 다 되돌리고 다 엎고 그런적도 많았다..^^.. 내 커밋 기록들이 마감 며칠전에 몰려있는 것은 이런 이유,,

남탓을 하고 싶은 것은 아니고, 1주차 쯤인가? 슬랙에 질문이 올라왔었다. 구현을 하면서 처음에 짠 기능 목록에 수정이 필요할 것 같은데, 수정을 해도 되는가에 대한 문제에 대해서 말이다.
그 당시 많은 사람들의 의견은 '처음 작성한 기능 목록이 구현하면서 계속 바뀌게 된다면 기능 목록을 작성하는 것에 의미가 없을 것 같다. 구현하면서 부족한 점이 보여도 변경하지 않고 계속 진행했다.' 였다.

예전엔 누가 나와 다른 의견을 제시하면 미운5살마냥 '아닌데?? 내가 맞는데??' 하면서 자존심 상해서 내 의견을 고집하곤 했는데(지금도 그럴수 있음), 그렇게 살아선 나에게 아무런 도움이 되지 않는 것 같아 나와 다른 의견을 인정하고 수용하려고 노력했다. 그래서 그 의견 또한 별 생각 없이 수용했다. 아무래도 난 처음 기능 목록을 작성하는 사람이니까 잘 모른다고 생가했음. 이렇게 회고로 쓰니까 조금 부끄러운 것 같다. 잘 모르면 공부를 해야지..ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 어이없어서 웃기네 사실 안웃김

피드백에서 Readme를 바꿔도된다고 하셨을 때엔 아 무작정 수용이 좋지만은 않을 수 있다! 라는 생각이 들었다.
근데 결국은 우테코 피드백을 다 받아들이는 것 또한 무작정 수용이 아닌가 생각했다. 결국 코딩에서 명확한 100% 정답은 없다고 생각하여, 일단은 피드백대로 Readme를 살아있는 문서화 시켜보고 판단하기로 마음먹었다.
결론은 이게 나와 더 잘 맞았다. 처음 작성한 기능목록을 변경할 수 없을 때에는 1.코드를 다 엎느라 시간 오래걸림 2. 중간에 오류를 발견해도 고칠 수 없음 3. 처음부터 잘해야한다는 부담감 총체적 난국이였다. 이 모든게 사라지니까 오히려 프로젝트가 탄탄해지는 느낌..? 오히려 프로젝트를 더 넓게 볼 수 있었다.

또한 이번 주차 피드백으로 야구 게임 피드백 영상을 주셨는데,(저번 주차 수업같앗음) 그걸 보고 ReadMe를 좀 자세히 적어봐야겠다!고 마음먹자말자 그렇게 적지 말라는 피드백이 있어서 조금 웃겼다.. 마음이 들켜버렸음

여하튼 ReadMe에 나름 프로젝트 소개도 넣고, 고려사항도 넣었다. 뭐 여러 다른 프로젝트마냥 소개를 적어야하나하고 이것저것 찾아봤는데, 그정도로 적을 건 없는 것 같아 넣지 않았다.


이번 주차는 좀 부끄럽게도 생각이 다 읽힌 느낌이였는데, 그 연장선으로 TDD가 있었다. 커뮤니티상에서 자주 등장했는데, 아무래도 테스트를 해본 경험이 없다 보니 저런 용어에 좀 로망을 가졌던 것 같다. 저는 TDD위주로 개발했어요~^^* 뭐 이런느낌..? 그런데 이 주차 코수타에서 명언이 나왔다. TDD는 쓰레기다 ..뭐 그런.. 그래서 바아로 그만뒀다.

위에서 판단하고 수용하는 내가 되자! 라고 마음먹자말자 모든 말을 수용하는 것같아 우습긴한데, 일단은 나보다 훨씬 경험많은 현직 개발자 분이시니까 당장 필요한게 아니면 일단 받아들이고, 내가 향후 필요할때 배워보고 판단해도 괜찮을 것 같다고 생각했다.

아무튼 저번 주차는 Application Test내에 모든 것을 다 테스트 했는데, 이번 주차는 단위테스트를 하려고 노력했다.
Alt+Enter를 누르면 테스트 파일이 만들어지는 것 알고 계셨나요? 전 처음 배웠습니다. 또한 여러 Input값을 주고 테스트 하고 싶을 때 사용하는 법도 배웠다.
저번 주차에 JUnit5와 AssertJ를 쓰는 테스트코드를 처음 짜봐서 가장 많이 공부를 했지만, 가장 잘 하지 못했던 부분이였다. 그리고 이번주차 또한 마찬가지였다.

영상을 보면서 테스트 코드 짤 수 있겠는데?! 하고 자신감넘쳐서 짰다가 축소했다.. 그래도 저번보다는 좀 더 명확한 테스트 코드가 된 기분이였다.


개인적으로 우테코를 하면서 느낀게, 자연스럽게 패턴화를 도와주는 것 같다고 생각했다. UI로직과 핵심로직을 나누라는 것, 도메인이라는 단어를 쓴 것이 그러했다. 그냥 내가 한창 설계 패턴 공부하던차라서 더 그럴수도 있지만, 내 기분은 그랬다. 그래서 이번 피드백을 받았을 때 잘 나아가고 있다는 생각을 했던 것 같다. 물론, 여전히 MVC패턴을 정확하게 적용하고 있지는 못하지만, 발전하는 과정이라고 생각한다. 처음부터 만족스러운 결과가 나오긴 어렵고, 그렇게 집착하다보면 아무것도 못하게되기 때문이다. 일단은 뭐라도 해야 발전할 수 있다.
이 말을 하는 이유는 내가 이틀동안 아무것도 안하고 누워서 쉬었기 때문이다. 뭔가 해야 발전한다... 코드 리팩토링 하러 가야지..

아무튼 아쉬운 점은 enum을 사용하라는 요구사항을 만족하기위하여 어거지로 enum을 만든 것이다. 사용을 하기 위한 사용이랄까? 그러다 보니 100%활용하지 못한 것 같다.

또한 이번 주차 가장 핫 토픽은 역시
runException test 부분의 에러였던 것 같다. 그 전 까지는 throw new 로 모든 것을 해결했는데, 이번 주차에서는 그게 통하지 않았다. [ERROR]라는 문구가 나오고 종료됐어야 했는데, 분명 나오는데..?? 라고 생각하며 오류 관련 소스코드를 하나하나 다 열어서 찾아봤다.

결국 내가 찾은 답은 try catch문이였다. 에러 메세지를 출력하고 종료 ..!
그렇지만 뭔가 주먹구구식으로 해결한 기분이 들어 찜찜했다. 이런 사람들이 많아서 도움이 위로 받긴 했지만, 아슬아슬 했던 한 주였다.

728x90

댓글