본문 바로가기
Developer/후기

[FE] 우아한 테크코스 6기 프리코스 3주차 회고: 로또 게임

by 청량리 물냉면 2023. 11. 8.
반응형

 

시작

이번 과제에서는 이전 과제에서 목표로 삼았던 함수 분리와, 각 함수별 테스트 작성 클래스(객체)분리도메인 로직에 대한 단위 테스트 작성이라는 목표가 추가되었다.

또한 함수가 단일 기능을 하도록 최대 15라인으로 함수 길이를 제한하고(함수를 분리하는 나만의 기준 만들기), 테스트 작성 이유에 대한 정리가 필요하다.

 

기능 요구 사항

 

구현 기능 목록

구현한 기능 목록은 다음과 같다.  

 

입력받기 

[ ✔ ]  로또 구입 금액 입력받기 (1000원 단위로)

[ ✔ ]  당첨 번호 입력받기 (쉼표 기준으로 구분)

[ ✔ ]  보너스 번호 입력받기

 

예외 

[ ✔ ]  로또 구입 금액 입력: 1000원 단위로 끊어지지 않는 경우
[ ✔ ]  당첨 번호 입력: 숫자 중복 입력
[ ✔ ]  당첨 번호 입력: 6개보다 적거나 많은 당첨번호 입력
[ ✔ ]  로또금액, 당첨번호, 보너스 번호: 입력 없음
[ ✔ ]  로또금액, 당첨번호, 보너스 번호: 숫자가 아닌 문자(알파벳, 기호 등등) 입력
[ ✔ ]  로또금액, 당첨번호, 보너스 번호: 0 이하의 수 또는 음수 입력
[ ✔ ]  당첨번호, 보너스 번호: 1 ~ 45 범위를 벗어난 숫자 입력

 

게임 진행하기

[ ✔ ]  1 ~ 45 중 중복되지 않는 6개의 숫자를 뽑기
[ ✔ ]  일치하는 번호 개수 구하기
[ ✔ ]  등수 계산하기
[ ✔ ]  수익률 계산하기

 

결과 출력하기 

[ ✔ ]  구매한 로또 개수와 로또 번호 출력
[ ✔ ]  게임 종료 후, 일치하는 번호의 개수와 당첨금, 수익률 출력

 

폴더 구조  설계

lotto
  ├── App.js
  ├── index.js
  ├── Lotto.js
  ├── WinningLotto.js
  ├── lottoGame
  │   ├── LottoGame.js
  │   ├── LottoGameUtils.js
  │
  ├── utils
  │   ├── UserInput.js
  │   ├── InputValidate.js
  │   ├── constants.js
  │
  ├── errors
  │   ├── InputError.js

📄 App.js ...게임 시작부터 종료까지 루틴을 관리하는 로직

📄 Lotto.js ... 랜덤 로또 클래스
📄 WinningLotto.js ... 당첨 로또 클래스(사용자 입력)

 

📂 lottoGame 로또 게임 진행에 필요한 파일을 관리하는 폴더
ㄴ📄 LottoGame.js ...로또 게임에 필요한 함수들을 관리하는 클래스

    ㄴ➰ generateLotto() ...구입 금액에 따라 로또를 발행하는 함수

    ㄴ➰ calculateWinners() ...최종 결과 계산하는 함수 (추후 분리할 예정)

ㄴ📄 lottoGameUtils.js ...LottoGame 클래스 내부의 유틸리티 함수를 관리하는 파일

    ㄴ➰ generateRandomNumber() ...랜덤 숫자 생성하는 함수

    ㄴ ascendingSort() ...오름차순 정렬 함수

 

📂 utils 유틸들을 모아놓은 폴더

ㄴ📄 UserInput.js ...유저에게 입력을 받고 입력받은 값을 검증 후 리턴하는 함수들이 저장된 클래스

    ㄴ➰ getPurchaseAmount() ...구매 금액 입력

    ㄴ➰ getLottoNumbers() ...당첨 번호 입력

    ㄴ getBonusNumber() ...보너스 번호 입력

ㄴ📄 constants.js ...상수값을 관리하는 함수

 

📂 errors  예외 처리 파일을 관리하는 폴더

ㄴ📄 InputError.js

    ㄴ➰ lottoAmountError() ...자동차 이름 입력받을 시, 에러 종류에 따라 에러 메시지 리턴

    ㄴ➰ lottoNumberError() ...시도횟수 입력받을 시, 에러 종류에 따라 에러 메시지 리턴

    ㄴ➰ commonError() ...공통 에러 발생 시, 에러 종류에 따라 에러 메시지 리턴

 

챌린징

분명히 모든 구현항목을 구현했는데 예기치 않은 문제로~ 라는 에러가 떴다.

이를 해결하기 위해 모든 코드를 뜯어보는 과정에서 수익률 세자리수마다 콤마 찍는 문제도 해결했고, 2등 당첨 시 랭크가 제대로 산정되지 않는 문제도 해결했다. 그럼에도 정작 예기치 않은 문제 오류는 계속되었다...

디스코드에 관련 에러의 해결방안을 찾아보고 테스트 코드 추가 및 삭제까지 온갖 시도를 통해서도 오류는 해결되지 않아서 좌절하던 차에, 아래 블로그를 보게 되었다.

 

10/31 wooteco: 예기치 못한 오류로 테스트 실패!

화요일! 과제 제출이 열렸고, 룰루랄라 PR 작성 후 지원 플랫폼에서도 제출을 마쳤다. 그리고 예제 테스트를 실행했더니 아니 글쎄 예기치 못한 오류로 인해 테스트가 실패했다고 뜨는 게 아닌가

velog.io

파일명 오류라고 하기에 나는 파일명 다 잘 작성했는데? 하다가 이전에 함수 모듈을 만들려다가 클래스로 LottoUtils를 바꾸면서 앞부분을 대문자로 바꾼 적이 있다는 게 떠올랐다. 

이 부분을 고치면서 설마 설마 했는데 정말 테스트 전부 성공했다...! 오류 해결하신 다른 분들이 별 거 아닌 오류였다고 하셨던 거 보면 다들 이런 문제로 고민하지 않으셨나 싶다.

다른 분들은 30분 만에 해결하기도 한다는데 나는 에러 잡는데 10시간도 더 썼다...

대신 그전에 발견하지 못했던 예외도 잡고 오류까지 처리했으니 예기치 못한 에러를 발견했던 게 나쁜 일은 아니었다고 생각한다.

 

소감

이전 과제까지는 게임을 진행하는 로직과 모델만 클래스로 작성한 반면, 이번 과제에서는 클래스 분리가 주요 목표였기 때문에 관련된 함수들을 모아서 클래스로 구현했다. 추가로, 함수의 길이를 15라인 이내로 유지하고, 각 함수가 하나의 기능만 수행하도록 분리하여 작성했습니다. 함수를 구현한 뒤에는 테스트 작성을 통해 결과를 확인해 가며 코드를 수정하였다.

또한 이번 과제를 진행하는 데에는 사용자 입력을 받아 저장하고 이 값을 다른 값과 비교하는 과정이 필요했기 때문에 데이터 type을 일치시키는 데에 많은 시간을 할애했다. 입력 형식이 문자열이었기 때문에, 로또 당첨번호는 'map(Number)'를 사용하여 문자가 담긴 배열의 전체 원소를 숫자로 변환하였고 숫자 하나만 입력받을 때는 'parseInt()'를 사용하여 형식을 맞추었다.
가장 인상 깊은 경험은 'toFixed()'와 'toLocaleString()'을 사용하여 수익률을 출력하는 과정이었다. 처음에는 toFixed()가 문자열을 반환하는 함수인 것을 알지 못하여, toFixed()를 적용해 소수점 아래 1자리에서 반올림한 다음 형변환 없이 toLocaleString()을 적용했더니 에러가 발생했다. 이후 type에 주의하며 toFixed()를 통해 반올림한 결과를 Number()로 형변환 한 뒤 그 결괏값에 toLocaleString()을 적용하니 성공적으로 숫자 3자리마다 쉼표(,)를 출력할 수 있었다. 
이 경험을 통해 함수를 사용할 때 입력 형식과 출력 형식을 잘 이해하고 활용해야 함을 깨달았다.

이번 과제를 통해 이와 같이 많은 것을 구현하고 배웠지만, 가장 기억에 남은 경험은 '예기치 않은 오류'를 해결한 경험이다. 
1주 차에도 동일한 에러를 해결하지 못하고 제출한 적이 있어 처음에는 당황했다. 하지만 이번에는 모든 코드를 수정해 보고, 에러를 점검하며 예외를 테스트하여 오류를 해결했다. 
결과적으로 import 시 파일명 작성 오류라는 간단한 오류였지만 오류를 해결하기 위해 모든 코드를 뜯어보고 예외를 테스트해 보는 과정에서 얻은 것이 많았다.
오류를 해결하기 위해 노력하며 수익률 출력 시 세 자릿수마다 쉼표를 넣어주는 기능을 구현하지 못했다는 것을 깨닫고 해당 부분 코드 구현을 진행하였고, 2등 당첨 시 보너스 번호가 당첨 번호와 제대로 비교되지 않아 등수가 예상대로 산정되지 않는 문제를 발견하고 해결했다. 
처음에는 당황스럽기만 했던 실행 오류였지만 이전에 발견하지 못했던 실수와 오류를 발견할 수 있게 해 주었기에 결과적으로는 개발자로서 성장하기 위한 좋은 기회였다고 생각한다.

현재 프리코스 3주 차로 이제 프리코스는 한 주만이 남아 아쉽긴 하지만 다음 과제도 열심히 진행하며 더 많은 것을 배우고 성장하고 싶다.

 

 

새롭게 학습한 내용

1. 클래스(객체)분리

프로그램 동작에 필요한 하위 기능들을 책임을 가질 클래스에 알맞게 분배하는 것(https://tinyurl.com/yv7efqjh)

 

2. 감시모드 오류

--watch is not supported without git/hg, please use --watchAll

https://mine-it-record.tistory.com/636

 

[Jest] 감시모드(watch/watchAll) - 변경된 파일이 있는 경우 테스트 자동 실행하기

Jest에는 다양한 옵션이 존재하는데, 정확한 명칭은 Jest CLI 옵션이라고 한다. 다양한 옵션 중에 감시 모드 옵션인 watch/watchAll에 대해 알아보고자 한다. Jest CLI 옵션 사용 방법 watch/watchAll 옵션에 대

mine-it-record.tistory.com

 

3. 문자열 배열을 숫자형 배열로 변경

["1", "$", "4"].map(Number)
//[1, NaN, 4]

 

 

소스 코드

https://github.com/Yoonyesol/javascript-lotto-6/tree/yesol

 

GitHub - Yoonyesol/javascript-lotto-6: 우아한 테크코스 6기 FE 3주차 과제

우아한 테크코스 6기 FE 3주차 과제. Contribute to Yoonyesol/javascript-lotto-6 development by creating an account on GitHub.

github.com

 

반응형