티스토리 뷰

프리코스 3주차

2주차와 동일한 부분

2주차와 동일한 부분이 있어서 해당 부분은 2주차 글로 참고 하도록 하겠습니다.

  • 진행방식
  • 미션 제출 방법
  • 과제 제출 전 체크리스트 - 0점 방지
  • 프로그래밍 요구 사항(추가된 요구사항은 아래에 적어 두었습니다.)

https://takim0070.tistory.com/26

 

우테코 프리코스 2주차 회고 - 숫자 야구

프리코스 2주차 1주차와 동일한 부분 1주차와 동일한 부분이 있어서 해당 부분은 1주차 글로 참고 하도록 하겠습니다. 진행방식 미션 제출 방법 과제 제출 전 체크리스트 - 0점 방지 프로그래밍

takim0070.tistory.com

 

기능 요구 사항

로또 게임 기능을 구현해야 한다. 로또 게임은 아래와 같은 규칙으로 진행된다.

- 로또 번호의 숫자 범위는 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]"로 시작하는 에러 메시지를 출력 후 종료한다.

입출력 요구 사항

입력

  • 로또 구입 금액을 입력 받는다. 구입 금액은 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%입니다.

 

프로그래밍 요구사항(추가된 요구사항만 있음)

  • 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.
    • 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다.
  • else 예약어를 쓰지 않는다.
    • 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
    • else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
  • Java Enum을 적용한다.
  • 도메인 로직에 단위 테스트를 구현해야 한다. 단, UI(System.out, System.in, Scanner) 로직은 제외한다.
    • 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 분리해 구현한다.
    • 단위 테스트 작성이 익숙하지 않다면 test/java/lotto/LottoTest를 참고하여 학습한 후 테스트를 구현한다.

라이브러리

  • camp.nextstep.edu.missionutils에서 제공하는 Randoms  Console API를 사용하여 구현해야 한다.
    • Random 값 추출은 camp.nextstep.edu.missionutils.Randoms의 pickUniqueNumbersInRange()를 활용한다.
    • 사용자가 입력하는 값은 camp.nextstep.edu.missionutils.Console의 readLine()을 활용한다.

사용 예시

List<Integer> numbers = Randoms.pickUniqueNumbersInRange(1, 45, 6);

 

과제 진행 요구 사항

  • 기능을 구현하기 전 docs/README.md에 구현할 기능 목록을 정리해 추가한다.
  • Git의 커밋 단위는 앞 단계에서 docs/README.md에 정리한 기능 목록 단위로 추가한다.

3주차 공통 피드백

  • 함수(메서드) 라인에 대한 기준
    • 이 기준은 main() 함수에도 해당된다.
  • 발생할 수 있는 예외 상황에 대해 고민한다.
    • 로또 구입 금액에 1000 이하의 숫자를 입력
    • 당첨 번호에 중복된 숫자를 입력
    • 당첨번호에 1~45 범위를 벗어나는 숫자를 입력
    • 당첨 번호와 중복된 보너스 번호를 입력
  • 비즈니스 로직과 UI 로직을 분리한다
  • 연관성이 있는 상수는 static final 대신 enum을 활용한다.
  • final 키워드를 사용해 값의 변경을 막는다.
  • 객체의 상태 접근을 제한한다.
  • 객체는 객체스럽게 사용한다.
    • Lotto에서 데이터를 꺼내지(get) 말고 메시지를 던지도록 구조를 바꿔 데이터를 가지는 객체가 일하도록 한다.
    • 예 : int matchCount(Lotto other) 이런식으로 Lotto 클래스의 멤버변수에 접근하지 않도록 한다.
  • 필드(인스턴스 변수)의 수를 줄이기 위해 노력한다.
    • 계산 가능한 값들에 대한 불필요한 필드를 없애보자
    • 예 : sum, count 가 있다면 average 필드는 필요 없다. getAverage를하면 return sum / count;를 하면 된다.
  • 성공하는 케이스 뿐만 아니라 예외에 대한 케이스도 테스트한다.
  • 테스트 코드도 코드다.
  • 테스트를 위한 코드는 구현 코드에서 분리되어야 한다.
    • 테스트를 위한 편의 메서드를 구현 코드에 구현하지 마라. 아래의 예시처럼 테스트를 통과하기 위해 구현 코드를 변경하거나 테스트에서만 사용되는 로직을 만들지 않는다.
      • 테스트를 위해 접근 제어자를 바꾸는 경우
      • 테스트 코드에서만 사용되는 메서드
  • 단위 테스트하기 어려운 코드를 단위 테스트하기
    • 단위 테스트를 할 때 테스트하기 어려운 부분은 분리하고 테스트 가능한 부분을 단위 테스트한다.
  • private 함수를 테스트 하고 싶다면 클래스(객체) 분리를 고려한다.

 

3주차 회고

함수 라인 제한(15줄)

일단 이 제한사항을 봤을 때 처음 든 생각이 있습니다.

public void doSomthing() {// 1라인
// 2라인
}// 3라인

이렇게 함수 시그내처부터 닫히는 중괄호까지 계산하는 건지 아니면

public void doSomthing() {
//1라인
}

함수 구현만 라인으로 보는지에 대해서 궁금했습니다.

아고라에도 의견들이 있었는데요.

 

저는 기왕하는 김에 조금 더 어려운 것으로 해보자는 생각을 했습니다.

그 이유는

  1. 함수 라인 제한이 있을 때 메서드 분리 or 클래스 나누어야 한다는 생각이 든다.
  2. 제한사항을 정말 어렵게 해야 1번을 더 열심히 수행 한다.
  3. 프리코스의 취지에 맞게 '배움'을 기준으로 한다면 어렵게 하는게 옳다.

이런 생각으로 저는 함수 시그내처까지 포함해서 라인을 체크하기로 했습니다.

장점은 제가 생각한데로 클래스를 나누거나 메서드를 분리하는데 도움이 되었습니다.

단점으로는 그거에만 신경쓰다보니 공통 피드백에 있는 몇가지들을 놓쳤습니다.

 

예외처리

  • 로또 구입 금액에 1000 이하의 숫자를 입력
  • 당첨 번호에 중복된 숫자를 입력
  • 당첨번호에 1~45 범위를 벗어나는 숫자를 입력
  • 당첨 번호와 중복된 보너스 번호를 입력

우선 공통 피드백에서 언급된 예외상황들을 처리하기는 했지만 처리하는 곳이 올바르지 못하다는 생각을 했습니다.

UserInput을 받을 때 저기 있는 모든 상황들을 체크할수 있는데 그러지를 못했습니다.

예를 들어 1000이하의 숫자는 UserInput에서 예외가 발생하지만 0을 입력하면 Lotto의 Controller에서 예외 처리를 하고 있습니다. 아직 의문이긴 하지만 어디에서 예외처리 해야할지 고민 중입니다.

그래도, 특별히 공통 피드백에서 언급이 없어서 그대로 두는게 옳다고 생각합니다.

왜냐하면, 로또를 1장도 안 사는 경우는 UserInput이 잘못되었다기 보다는 Lotto 구매 절차상의 문제이기 때문에 하나도 구매하지 않는 룰을 가질 수 있다면 Lotto Controller에서 수정하는게 옳다고 보기 때문입니다.

 

UI 로직과 비니지스 로직

MVC 구조로 뭔가 작성하려고 했는데 제대로 수행하지 못했습니다.

그래서, MVC 구조에 대한 명확한 정립이 필요할 것 같아서 우아한Tech 유튜브 채널에 [테코톡]이 있어 그걸 참고하기로 했습니다.

제가 놓쳤던 부분이 View에서 Controller를 참조하고 있거나 하는 부분이 있었습니다.
그래서 View는 모델을 참조할 순 있어도 Controller를 참조하진 않는다. Model이 Controller를 참조하거나 View를 참조하지 않는다. 이걸 확실히 지켜서 4주차에 적용하려고 합니다.

 

객체를 객체스럽게 사용

이 부분을 제가 전혀 하지 못했습니다.

저는 Lotto 클래스에 getNumbers() 메서드만 만들었습니다. 

확실히 Lotto 클래스에서 이게 맞는지 아닌지 등등을 확인할 수 있고 내부의 데이터를 오픈하지 않는 방법으로 4주차를 준비해야 할거 같습니다. 😅😅

 

느낀점

  • ApplicationTest 코드 중에 예외처리에 관련해서 하루 꼬박 사용한 것이 있었습니다.
    • 에러 메시지를 출력하고 프로그램을 종료 한다는 것이었는데 어떻게 처리해야 할 지 몰랐습니다.
    • 마지막에 생각해 낸것이 main() 함수에서 try-catch를 해서 catch에서 에러 메시지 출력하면 되는 거였습니다.
public class Program {
	public static void main() {
    	try {
        	Somthing...
        } catch (Exception e) {
        	System.out.println(e.getMessage());
        }
        // 다른곳에서 catch하지 않고 여기서만 catch하면 에러 메시지 출력 후
        // 프로그래밍 종료 되는 거였죠..
    }
}

 

  • 함수 라인 15라인도 만만치 않았지만 열 제한 120도 만만치 않았습니다.
  • 클래스를 UI 로직와 비지니스 로직으로 분리하니 테스트 코드 작성이 수월 했습니다.
    • 물론 테스트 코드 작성이 아직 익숙지가 않아서 뭐가 좋은지에 대해서는 고민이 더 필요 했지만 UI를 분리하라는 조언은 정말 좋았습니다.

제가 작년 우테코 4기에도 지원했지만 프리코스도 못했었는데요.

다른 사람들 후기를 많이 봤었습니다. 다들 하나같이 프리코스만 하더라도 많은 도움이 되었다는 이야기가 많았습니다.

그게 무슨말인지 알 것 같습니다.

제가 부족하다고 느꼈던 부분이

클래스 분리, 에러 핸들링, 테스트 코드 작성 입니다.

프리코스 하기 전에는 이런 것들을 어떻게 훈련해야 하는지 모르고 있었는데 우테코 프리코스를 하니 자연스럽게 훈련이 되더라구요.

그래서 5기에는 지원하는 모든 사람이 프리코스를 경험할 수 있게 해준게 엄청 좋은 결정이라 생각합니다.

그래서 이번주차에는 너무 만족했습니다.

댓글