2주차 피드백 📝
3주차 과제를 수행하기 전, 2주차 과제에 대한 피드백이 도착했다.
2주차 피드백은 기능 목록 작성, 코드 컨벤션, 간단한 리팩토링, 테스트에 대한 내용들이었다.
2주차 피드백은 다음과 같다.
1. README.md를 상세히 작성한다.
2. 기능 목록을 재검토한다.
3. 기능 목록을 업데이트한다.
4. 값을 하드 코딩하지 않는다. (상수로 선언하여 이름에 변수의 역할을 명시)
5. 구현 순서도 코딩 컨벤션이다. (클래스는 상수, 멤버 변수, 생성자, 메서드 순으로 작성)
6. 변수 이름에 자료형은 사용하지 않는다. (carNameList 등)
7. 한 함수가 한 가지 기능만 담당하게 한다. (한 함수에서 여러 일을 하는 경우 분리)
8. 함수가 한 가지 기능을 하는지 확인하는 기준을 세운다.
9. 테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해본다.
10. 처음부터 큰 단위의 테스트를 만들지 않는다.
"기능 목록을 업데이트한다" 라는 부분의
"죽은 문서가 아니라 살아있는 문서를 만들기 위해 노력한다." 라는 대목이 인상깊었다.
나의 2주차 과제에서 기능 목록은 첫 커밋 이후 쭉 죽어있었다...
부끄럽다.
3주차 과제를 진행할 때는 기능 목록 문서를 죽이지 않으리라 다짐했다.
3주차 과제 - 로또 💸
3주차 과제는 로또 게임을 구현하는 과제였다.
로또 게임의 기능 요구 사항과 프로그래밍 요구 사항은 다음과 같다.
기능 요구 사항 🚀
• 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]"로 시작하는 에러 메시지를 출력 후 종료한다.
프로그래밍 요구 사항 🖥️
- ✅ 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.
- 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다.
- ✅ else 예약어를 쓰지 않는다.
- 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
- else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
- ✅ Java Enum을 적용한다.
- ✅ 도메인 로직에 단위 테스트를 구현해야 한다. 단, UI(System.out, System.in, Scanner) 로직은 제외한다.
- 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 분리해 구현한다.
- 단위 테스트 작성이 익숙하지 않다면 test/java/lotto/LottoTest를 참고하여 학습한 후 테스트를 구현한다.
프로그램 구현 👩💻
기능 목록
기능 구현 전, 내가 정의한 기능 목록은 다음과 같다.
1. 로또를 몇 장 살 것인지 구입금액을 입력받는다(장 당 1000원).
- 숫자가 아닌 문자를 입력하는 경우
- 입력값이 1000원 단위로 나누어 떨어지지 않는 경우 예외를 throw한다.
2. 구매한 로또 한 장당 1~45 사이의 랜덤한 번호 6개를 할당한다.
- 로또를 생성했을 때, 기존 로또 중에 번호가 모두 같은 로또가 존재할 경우 재생성한다.
3. 1~45 사이의 쉼표로 구분된 당첨 번호 6개를 입력받는다.
- 입력한 숫자가 1~45의 범위를 벗어나는 경우
- 숫자가 아닌 문자를 입력하는 경우
- 중복된 숫자를 입력하는 경우
- 6개 미만 혹은 초과되는 숫자를 입력하는 경우 예외를 throw한다.
4. 1~45 사이의 보너스 번호 한 개를 입력받는다.
- 입력한 숫자가 1~45의 범위를 벗어나는 경우
- 숫자가 아닌 문자를 입력하는 경우
- 입력한 당첨 번호 6개와 중복되는 경우 예외를 throw한다.
5. 당첨 결과를 출력한다.
- 각각의 로또 번호를 당첨 번호, 보너스 번호와 비교하여 당첨 결과를 도출한다.
6. 수익률을 출력한다.
- 당첨 결과를 바탕으로 당첨 금액을 환산한다.
- 로또 구매 금액과 당첨 금액으로 수익률을 계산한다.
살아있는 기능 목록 문서를 만들기 위해 초반 기능 목록은 가볍게 구현할 기능과 예외 처리 사항을 기록하였고 구현 과정을 거치며 미처 파악하지 못한 빠진 부분을 추가하거나 수정했다.
(+ 하나의 기능을 구현할 때 마다 체크박스에 표시를 했다. 기능 목록을 상시로 확인하니 저번 주차처럼 누락되는 일이 없어 좋았다.)
기능 구현
이번 과제에서는 MVC패턴을 적용해보려고 했다.
한 번도 이렇게 짜본 적이 없어 초반에 객체지향과 MVC에 대한 내용을 검색하며 익히는 시간을 가졌다.
그 중 도움이 많이 되었던 유튜브 영상을 하나 추천하겠다.
https://www.youtube.com/watch?v=ogaXW6KPc8I
MVC 패턴의 다섯 가지 규칙을 지키기 위해 체크리스트 형식으로 만들어 개발하면서 꾸준히 확인했다.
처음에 구상단계에서는 어떻게 분리해야할 지 감이 잘 오지 않았지만, 구현을 하면서 클래스의 기능이 명확해지니 초반보다는 비교적으로 분리하기가 쉬웠다(사실 맞는 지는 잘 모르겠다,,,)
내가 구현한 기능들은 다음과 같다.
구성요소 | 클래스 | 기능 |
Model | Buyer | 구매자 역할을 하는 클래스, 로또를 구매하고 랜덤한 번호를 선택한다 |
Lotto | 기본 생성되어 있는 클래스, 로또를 생성한다 | |
LuckyLotto | Lotto를 상속받는 클래스, 당첨 로또를 생성한다(기존 6자리 숫자 + 보너스 번호 추가) | |
Result | 결과 나타내는 클래스, 당첨 결과를 바탕으로 수익률을 계산한다 | |
View | Input | 사용자 입력을 받는 클래스 |
Output | 사용자에게 출력하는 클래스 | |
Controller | LottoController | 프로그램의 전반적인 흐름을 제어한다. |
예외처리
2주차 과제에서 예외 처리 해야될 부분을 한 개 빼먹고 제출한게 너무 아쉬워 예외 처리 사항은 꼼꼼하게 작성했다.
작성할 당시에는 완벽하다고 생각했는데, 구현 과정에서 빠진 부분이 계속 보였다.
특히, 2번 기능은 사용자 입력을 받는 부분이 없어 따로 예외가 없다고 생각했는데,
랜덤으로 6개의 숫자를 뽑을 때 극악의 확률로 6자리 숫자가 모두 같은 로또가 중복 생성 될 수도 있겠다는 생각이 들어 해당 예외가 발생할 경우에는 6자리의 번호를 다시 뽑아 로또를 재생성하도록 했다.
예외처리에서 조금 애를 먹었던 부분이 있었다.
기본적으로 제공되었던 테스트 케이스를 돌려보았을 때, 예외 테스트에서 항상 실패가 떴다.
왜지? "[ERROR]"라는 문자열이 포함된 예외를 throw하도록 했는데?
try {
inputNumber = Integer.parseInt(input);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("[ERROR] 숫자 이외의 값을 입력할 수 없습니다.");
}
이 부분은 같이 우테코에 참여한 친구의 도움을 받아 해결했다.
IllegalArgumentException의 생성자 매개변수인 문자열은 '에러 로그'가 아니라 '에러 세부사항'일 뿐이다.
throw한 IllegalArgumentException을 catch하여 로그 메세지를 띄우도록 해야 예외 테스트에 통과할 수 있다.
IllegalArgumentException은 프로젝트의 최상위 클래스인 Application에서 catch하도록 했다.
public class Application {
public static void main(String[] args) {
LottoController lottoController = new LottoController();
try {
lottoController.run();
} catch (IllegalArgumentException e) {
System.out.println("[ERROR] 에러가 발생하여 종료합니다.");
}
}
}
아쉬웠던 점🤔
얕은 지식
이번 과제를 진행하면서 MVC모델과 객체지향 프로그래밍에 대해 여러 글들을 찾아보았다.
다 읽어보긴 했지만 사실은 제대로 이해하지 못한 상태이다.
일단 추상적인 개념이 너무 많기도 하고... 많은 내용을 얕게 공부해 제대로 이해하지 못했다.
아직도 Controller가 어떤 녀석인지 잘 모르겠다🥲 이런 식으로 짜는게 아닌 것 같은데...
객체 지향 프로그래밍과 MVC에 대해서는 더 심도있게 공부하고 게시글로 정리할 예정이다.
다음 과제 때는 저 두 가지 부분에 대해 숙지하고, 프로그래밍 시 체크할 사항들을 리스트로 만들어 계속 들여다보면서 상기해야겠다.
클래스 분리
확실히 저번 주차 과제보다는 클래스를 잘 분리한 것 같다.
딱 한가지 아쉬웠던 것은,
로또 추첨 결과를 저장하는 Result 클래스에 수익률 계산 메소드까지 끼워넣었는데 충분히 두 클래스로 분리할 수 있을 것 같다.
나중에 시간이 된다면 꼭 리팩토링하고싶다.
Enum
이번 과제는 연관성이 있는 상수들을 정의할 때 Enum을 사용하라는 요구사항이 있었다.
Java에서 Enum을 써본 적이 없기 때문에, 책을 뒤져서 Enum에 대한 기초적인 지식을 숙지하고 구현했다.
나는 간단하게 상수에 당첨 등수와 당첨 금액을 정의했는데,
다른 분들의 코드를 보니 Enum을 잘 활용하여 더 효율적인 코드를 짜신 분들이 있었다...
이 부분은 더 깊게 알아봐야 할 것 같다.
'도전' 카테고리의 다른 글
[SSAFY/싸피] 9기 전공자 합격 후기 (6) | 2022.12.23 |
---|---|
[우아한 테크코스] 웹 백엔드 2주차 회고 및 피드백 (0) | 2022.11.09 |