프리코스 3주차 과제 진행 사항을 다시 되돌아보고자 한다.
목표
학습 목표
- 관련 함수를 묶어 클래스를 만들고, 객체들이 협력하여 하나의 큰 기능을 수행하도록 한다.
- 클래스와 함수에 대한 단위 테스트를 통해 의도한 대로 정확하게 작동하는 영역을 확보한다.
- 2주 차 공통 피드백을 최대한 반영한다.
로또
과제 진행 요구 사항
- 미션은 로또 저장소를 포크하고 클론하는 것으로 시작한다.
- 기능을 구현하기 전
README.md
에 구현할 기능 목록을 정리해 추가한다. - Git의 커밋 단위는 앞 단계에서
README.md
에 정리한 기능 목록 단위로 추가한다.- AngularJS Git Commit Message Conventions을 참고해 커밋 메시지를 작성한다.
- 자세한 과제 진행 방법은 프리코스 진행 가이드 문서를 참고한다.
기능 요구 사항
간단한 로또 발매기를 구현한다.
- 로또 번호의 숫자 범위는 1~45까지이다.
- 1개의 로또를 발행할 때 중복되지 않는 6개의 숫자를 뽑는다.
- 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑는다.
- 당첨은 1등부터 5등까지 있다. 당첨 기준과 금액은 아래와 같다.
- 1등: 6개 번호 일치 / 2,000,000,000원
- 2등: 5개 번호 + 보너스 번호 일치 / 30,000,000원
- 3등: 5개 번호 일치 / 1,500,000원
- 4등: 4개 번호 일치 / 50,000원
- 5등: 3개 번호 일치 / 5,000원
- 로또 구입 금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 한다.
- 로또 1장의 가격은 1,000원이다.
- 당첨 번호와 보너스 번호를 입력받는다.
- 사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 로또 게임을 종료한다.
- 사용자가 잘못된 값을 입력할 경우
IllegalArgumentException
을 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다.Exception
이 아닌IllegalArgumentException
,IllegalStateException
등과 같은 명확한 유형을 처리한다.
입출력 요구 사항
입력
- 로또 구입 금액을 입력 받는다. 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다.
14000
- 당첨 번호를 입력 받는다. 번호는 쉼표(,)를 기준으로 구분한다.
1,2,3,4,5,6
- 보너스 번호를 입력 받는다.
7
출력
- 발행한 로또 수량 및 번호를 출력한다. 로또 번호는 오름차순으로 정렬하여 보여준다.
8개를 구매했습니다.
[8, 21, 23, 41, 42, 43]
[3, 5, 11, 16, 32, 38]
[7, 11, 16, 35, 36, 44]
[1, 8, 11, 31, 41, 42]
[13, 14, 16, 38, 42, 45]
[7, 11, 30, 40, 42, 43]
[2, 13, 22, 32, 38, 45]
[1, 3, 5, 14, 22, 45]
- 당첨 내역을 출력한다.
3개 일치 (5,000원) - 1개
4개 일치 (50,000원) - 0개
5개 일치 (1,500,000원) - 0개
5개 일치, 보너스 볼 일치 (30,000,000원) - 0개
6개 일치 (2,000,000,000원) - 0개
- 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%)
총 수익률은 62.5%입니다.
- 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다.
[ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.
실행 결과 예시
구입금액을 입력해 주세요.
8000
8개를 구매했습니다.
[8, 21, 23, 41, 42, 43]
[3, 5, 11, 16, 32, 38]
[7, 11, 16, 35, 36, 44]
[1, 8, 11, 31, 41, 42]
[13, 14, 16, 38, 42, 45]
[7, 11, 30, 40, 42, 43]
[2, 13, 22, 32, 38, 45]
[1, 3, 5, 14, 22, 45]
당첨 번호를 입력해 주세요.
1,2,3,4,5,6
보너스 번호를 입력해 주세요.
7
당첨 통계
---
3개 일치 (5,000원) - 1개
4개 일치 (50,000원) - 0개
5개 일치 (1,500,000원) - 0개
5개 일치, 보너스 볼 일치 (30,000,000원) - 0개
6개 일치 (2,000,000,000원) - 0개
총 수익률은 62.5%입니다.
프로그래밍 요구 사항 1
- JDK 21 버전에서 실행 가능해야 한다.
- 프로그램 실행의 시작점은
Application
의main()
이다. build.gradle
파일은 변경할 수 없으며, 제공된 라이브러리 이외의 외부 라이브러리는 사용하지 않는다.- 프로그램 종료 시
System.exit()
를 호출하지 않는다. - 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 등의 이름을 바꾸거나 이동하지 않는다.
- 자바 코드 컨벤션을 지키면서 프로그래밍한다.
- 기본적으로 Java Style Guide를 원칙으로 한다.
프로그래밍 요구 사항 2
- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
- 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다.
- 3항 연산자를 쓰지 않는다.
- 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.
- JUnit 5와 AssertJ를 이용하여 정리한 기능 목록이 정상적으로 작동하는지 테스트 코드로 확인한다.
- 테스트 도구 사용법이 익숙하지 않다면 아래 문서를 참고하여 학습한 후 테스트를 구현한다.
프로그래밍 요구 사항 3
- 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.
- 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다.
- else 예약어를 쓰지 않는다.
- else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
- 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
- Java Enum을 적용하여 프로그램을 구현한다.
- 구현한 기능에 대한 단위 테스트를 작성한다. 단, UI(System.out, System.in, Scanner) 로직은 제외한다.
- 단위 테스트 작성이 익숙하지 않다면
LottoTest
를 참고하여 학습한 후 테스트를 작성한다.
- 단위 테스트 작성이 익숙하지 않다면
라이브러리
camp.nextstep.edu.missionutils
에서 제공하는Randoms
및Console
API를 사용하여 구현해야 한다.- Random 값 추출은
camp.nextstep.edu.missionutils.Randoms
의pickUniqueNumbersInRange()
를 활용한다. - 사용자가 입력하는 값은
camp.nextstep.edu.missionutils.Console
의readLine()
을 활용한다.
- Random 값 추출은
사용 예시
- 1에서 45 사이의 중복되지 않은 정수 6개 반환
Randoms.pickUniqueNumbersInRange(1, 45, 6);
Lotto 클래스
- 제공된
Lotto
클래스를 사용하여 구현해야 한다. Lotto
에numbers
이외의 필드(인스턴스 변수)를 추가할 수 없다.numbers
의 접근 제어자인private
은 변경할 수 없다.Lotto
의 패키지를 변경할 수 있다.
public class Lotto {
private final List<Integer> numbers;
public Lotto(List<Integer> numbers) {
validate(numbers);
this.numbers = numbers;
}
private void validate(List<Integer> numbers) {
if (numbers.size() != 6) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 6개여야 합니다.");
}
}
// TODO: 추가 기능 구현
}
주로 고민한 사항
- 효율적인 test 코드 작성하기
저번 주차에서 여러 코드들을 보면서 효율적으로 test 코드를 작성하는 방법을 많이 배웠다. 해당 방법들을 적극적으로 적용해 보면서 test 코드 작성에 익숙해지고자 하였다.
문제 해결 요소
- @ParameterizedTest를 이용한 효율적인 테스트 코드 작성
이전 주차 코드 리뷰를 진행하면서 @ParameterizedTest라는 것을 처음 접했다. 해당 코드를 이용하면 하나의 로직으로 여러 값들을 테스트할 수 있는 것이 인상적이었고 이번 test 코드를 작성할 때 적극적으로 적용해 보았다.
아쉬웠던 사항
- method의 return 유형도 신경 쓰자
createSingleLotto라는 method를 이용하여 로또 번호를 생성하는 함수를 작성하였는데, 이번 코드 리뷰에서 "메서드명은 createSingle'Lotto'인데 실제로 반환하는 것은 Lotto가 아닌 List여서 어색해 보인다"는 의견을 받았다. 함수 작명뿐만이 아니라 return 유형도 같이 고려하지 못한 점이 아쉬운 점으로 남았다.
- 이번에 알게 된 toString()의 본래 목적
이번 코드 리뷰에서 언급된 내용이다. toString을 오버라이딩하는 것은 좋지만 toString 메서드는 디버깅을 위해 인스턴스의 종합 요약 정보를 만드는 것이 목적이라고 한다. 물론 여기서는 Lotto 클래스의 유일한 멤버인 List의 원소를 보여주는 문자열이 View의 요구사항과 일치했기 때문에 구현이 잘못된 것은 아니지만 toString 메서드에 View 로직을 반영하는 것은 바람직하지 않다고 한다. View의 요구사항이 변했을 때 도메인 로직이 같이 수정되어야 하기 때문이다.
개선하기 위해 할 수 있는 것은?
- 다양한 자바 라이브러리를 공부해 보자
이번 코드 리뷰를 진행하면서 entrySet(), EnumMap, Enum.values(), test의 @MethodSource 등 공부하면 좋은 키워드들을 많이 알려주셨다. 해당 키워드를 기반으로 학습을 추가로 진행해 볼 예정이다.
- 함수/클래스 작명뿐만이 아닌 return 유형도 같이 고려하자
이번 코드리뷰를 진행하면서 return 유형도 적절히 지정하는 것이 중요하다는 것을 느꼈다. 함수/클래스 이름뿐만이 아니라 return 유형도 고려하여 코드를 작성하는 것을 의식하면서 진행해볼 예정이다.
마무리하며...
3주 차 과제는 이전 1주 차, 2주 차 때보다 난이도가 올라갔다는 것을 크게 느꼈다. 초반에는 어떻게 구현할지 엄두도 나지 않았지만, 하나씩 해결해가다 보니 어떻게 구현하면 될지 길이 잡히는 느낌을 받은 것이 신기했다. 하지만 객체지향적 관점에서 효율적으로 작성했는지는 잘 모르겠다는 생각이 들었다. 이제 4주 차 과제만 남았다. 마지막까지 파이팅 하자!
'개발노트 > 우아한테크코스' 카테고리의 다른 글
[우아한테크코스] 7기 최종 합격 회고록 (0) | 2025.01.08 |
---|---|
[우아한테크코스] 7기 프리코스 4주차 회고록 (0) | 2024.11.11 |
[우아한테크코스] 7기 프리코스 2주차 회고록 (1) | 2024.11.04 |
[우아한테크코스] 7기 프리코스 1주차 회고록 (0) | 2024.10.27 |