[로또] 김다현 미션 제출합니다. - #153
Open
daahyunk wants to merge 33 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
javascript-lotto-precourse
프로젝트 개요
간단한 로또 발매기를 구현한다. 사용자는 금액을 입력해 로또를 구입하고 당첨 번호 및 보너스 번호를 입력해 당첨 결과와 수익률을 확인할 수 있다.
구현 목표
객체 간 협력을 통해 로또 발매 및 결과 계산을 수행한다.
기능 목록
1. 구입 금액 입력
사용자로부터 로또 구입 금액을 입력받는다.
구입 금액은 1,000원 단위로 나누어 떨어져야 한다.
구입 금액은 0보다 커야 하며 숫자여야 한다.
예외 상황 발생 시
[ERROR]로 시작하는 메시지를 출력하고 해당 단계부터 재입력받는다.[ERROR] 구입 금액은 숫자여야 합니다.[ERROR] 구입 금액은 0보다 커야 합니다.[ERROR] 구입 금액은 1,000원 단위여야 합니다.2. 로또 발행
(ex. 8000원 입력 -> 8개 구매)
[ERROR] 로또 번호는 6개여야 합니다.[ERROR] 로또 번호는 중복될 수 없습니다.3. 발행 결과 출력
4. 당첨 번호 입력
[ERROR] 당첨 번호 형식이 올바르지 않습니다.출력 후 재입력.5. 보너스 번호 입력
[ERROR] 보너스 번호가 올바르지 않습니다.출력 후 재입력.6. 당첨 결과 계산
LottoRank(enum 객체)를 통해 관리한다.7. 당첨 통계 출력
예외 처리 원칙
[ERROR]로 시작한다.process.exit()를 사용하지 않는다.테스트 시나리오
1. 구입 금액 검증 (ValidationTest.js)
"8000""abc"[ERROR] 구입 금액은 숫자여야 합니다.발생"0","-1000"[ERROR] 구입 금액은 0보다 커야 합니다.발생"1500"[ERROR] 구입 금액은 1,000원 단위여야 합니다.발생2. 로또 발행 (LottoMachineTest.js)
8000[43, 8, 21, 23, 42, 41]→ 발행 시[8, 21, 23, 41, 42, 43]으로 정렬[1,2,3,4,5][ERROR] 로또 번호는 6개여야 합니다.[1,2,3,3,4,5][ERROR] 로또 번호는 중복될 수 없습니다.3. 발행 결과 출력 (OutputViewTest.js)
"8개를 구매했습니다."출력[8, 21, 23, 41, 42, 43][8, 21, 23, 41, 42, 43]형태로 출력4. 당첨 번호 입력 (WinningNumbersTest.js)
"1,2,3,4,5,6"[1,2,3,4,5,6]배열로 변환"1,2,3,4,5"[ERROR] 당첨 번호 형식이 올바르지 않습니다.발생"1,2,3,4,5,6,7"[ERROR] 당첨 번호 형식이 올바르지 않습니다.발생"1,2,3,3,4,5"[ERROR] 당첨 번호 형식이 올바르지 않습니다.발생"0,2,3,4,5,6","1,2,3,4,5,46"[ERROR] 당첨 번호 형식이 올바르지 않습니다.발생5. 보너스 번호 입력 (BonusNumberTest.js)
"7""abc"[ERROR] 보너스 번호가 올바르지 않습니다.발생"0","46"[ERROR] 보너스 번호가 올바르지 않습니다.발생"1"(당첨 번호에 1 포함 시)[ERROR] 보너스 번호가 올바르지 않습니다.발생6. 당첨 결과 계산 (ResultCalculatorTest.js)
[1,2,3,4,5,6], 당첨 번호:[1,2,3,4,5,6], 보너스:71등반환 (2,000,000,000원)[1,2,3,4,5,7], 당첨 번호:[1,2,3,4,5,6], 보너스:72등반환 (30,000,000원)[1,2,3,4,5,8], 당첨 번호:[1,2,3,4,5,6], 보너스:73등반환 (1,500,000원)[1,2,3,4,8,9], 당첨 번호:[1,2,3,4,5,6], 보너스:74등반환 (50,000원)[1,2,3,8,9,10], 당첨 번호:[1,2,3,4,5,6], 보너스:75등반환 (5,000원)[1,9,10,11,12,13], 당첨 번호:[1,2,3,4,5,6], 보너스:70원)[ [1,2,3,4,5,6], [1,2,3,4,5,7], [1,2,3,4,8,9] ]"25375625.00%"(소수 둘째 자리 반올림) 반환보조 시나리오 (LottoRank enum)
6개 일치rank: 1, prize: 2,000,000,0005개 + 보너스 일치rank: 2, prize: 30,000,0005개 일치rank: 3, prize: 1,500,0004개 일치rank: 4, prize: 50,0003개 일치rank: 5, prize: 5,0002개 이하rank: null, prize: 07. 당첨 통계 출력 (ApplicationTest.js)
"3개 일치 (5,000원) - 1개","총 수익률은 62.5%입니다."등 포함"1000j")[ERROR]메시지 출력 및 프로그램 재실행"8개를 구매했습니다."메시지 출력 확인"총 수익률은 62.5%입니다."정확히 출력프로젝트 구조
회고
이번 3주차 로또 미션에서는 지난 주차에 하지 못했던 테스트 주도 개발(TDD) 방식을 적용하며 기능 구현보다 설계와 구조에 집중하는 과정을 경험했다. 각 기능을 작은 단위로 나누고 테스트를 먼저 작성한 뒤 통과시키는 과정을 반복하면서 코드 품질을 점진적으로 개선할 수 있었던 것 같다.
새롭게 시도한 것
Red → Green → Refactor 사이클 적용
테스트를 작성하고 최소한의 코드로 통과시킨 후 리팩토링하는 과정을 명확히 구분해 진행했다.
그러다보니 코드의 의도와 구조를 우선적으로 고민하게 되었다.
JavaScript 문법 활용
Set을 이용한 중복 검증,Array.from으로 배열 생성,every를 통한 범위 검증 등 JavaScript 내장 메서드를 활용하여 검증 로직을 간결하고 읽기 쉽게 구현했다.도메인 중심 설계
Lotto,LottoMachine,WinningNumbers,BonusNumber,ResultCalculator등 각 클래스가 하나의 역할만 담당하도록 단일 책임(SRP)에 근거하여 설계했다. 검증 로직은utils/validation.js, 상수는constants.js로 분리해 재사용성과 일관성을 확보했다.하드코딩 제거 및 상수화
UI 메시지, 배열 조인 구분자 등 모든 문자열 상수를
constants.js에서 중앙화했다. 이를 통해 메시지 변경 시 단일 지점에서만 수정할 수 있고 확장이 용이해졌다.어려웠던 부분
테스트를 먼저 작성해야 한다니...
지금까지는 기능을 먼저 구현한 후 테스트를 작성하는 방식에 익숙했기 때문에 테스트 주도 개발(TDD) 방식으로 테스트를 먼저 작성하는 것이 매우 낯설었다. 어떤 테스트를 먼저 작성해야 하는지, 어느 수준의 테스트부터 시작해야 하는지 판단하기가 어려워 처음에 시간이 많이 소요됐다.
실패한 접근
테스트 스펙을 먼저 읽지 않고 구현한 문제
ApplicationTest.js에서 기대하는 동작 방식을 미리 파악하지 않고 개별 단위 테스트부터 구현했다. 결과적으로 테스트에서 기대하는 인터페이스와 다른 코드를 구현해놓는 바람에 마지막 단계에서 수정을 했어야 했다.배운 점 / 느낀 점
이번 미션을 TDD 기반으로 진행하면서, 지난 주차까지만 해도 기능부터 만들고 나중에 테스트하는 줄 알았던 내가 TDD라는 개념을 이해하고 "이게 뭘 해야 하지?"를 먼저 정의한 후에 코드를 작성하는 방식으로 바뀌었다는 점에서 우선 한 단계 성장했다고 느꼈다. 덕분에 코드 짜기 전에 머리로 한 번 더 정리하게 되고 결과적으로 코드도 더 깔끔해졌다.
테스트가 귀찮은 작업이 아니라 리팩토링할 때 안전망 같은 역할을 한다는 것도 느꼈다. 코드 구조를 바꾸거나
LottoMachine,ResultCalculator같은 클래스들 사이 관계를 손볼 때 테스트가 있으니까 뭐가 깨졌는지 바로 알 수 있어서 좋았다. 그냥 "이렇게 바꿔도 되나?" 고민하는 시간이 확 줄었다.처음엔 테스트 작성이 느리고 답답했는데 하나씩 통과할 때마다 쾌감이 들기도 하고...ㅋㅋ 내 코드가 더 확신이 생기는 느낌이었다. 앞으로도 이런 식으로 검증하면서 코드 짜는 연습을 더 해봐야겠다.