티스토리 뷰

지난 회고 보기

[우아한 테크코스 5기] 프리코스 2주 차 회고 (구현 기능 목록 작성)

이번 과정을 통해 객체지향의 이론을 실전에서 적용하는 것은 굉장히 어렵다는 걸 느꼈습니다.

한 것

객체지향 학습

이번 학습 목표인 객체를 분리하는 연습, UI와 비즈니스 로직을 분리하는 연습인 만큼 다시 한번 객체지향과 디자인 패턴 그중에서 MVC 패턴을 학습하는 계기가 되었습니다.

 

객체를 어떻게 하면 잘 분리할 수 있을 까 고민하다가 객체지향의 핵심인 SOLID 원칙을 학습하고, 이 중에서 단일책임의 원칙(SRP)을 이번 미션에 최대한 적용하려고 노력했습니다.

단일책임의 원칙(SRP):
클래스는 단 한개의 책임을 가져야한다. (여기서 책임변경하려는 이유를 의미)
즉, 클래스를 변경하는 이유는 단 하나여야 한다.
이를 지키지 않으면, 한 책임의 변경에 의해 다른 책임과 관련된 코드에 영향을 미칠 수 있다
→ 이렇게 되면 유지보수가 매우 비효율적


이 과정에서 클래스를 최대한 작게 만들고 클래스끼리의 의존성을 낮추기 위한 많은 고민을 하였습니다.
도메인 클래스의 의존성을 낮추다 보니, 도메인을 결합해주는 로직이 필요했는데 이 부분을 MVC패턴의 Controller를 만들어서 View의 입력을 받고, 도메인의 비즈니스 로직을 실행시켜, 애플리케이션을 동작하게 하였습니다.

 

  1. Model은 Controller와 View에 의존하지 않아야 한다.
  2. View는 Model에만 의존해야 하고, Controller에는 의존하면 안된다.
  3. View가 Model로부터 데이터를 받을 때는, 사용자마다 다르게 보여주어야 하는 데이터에 대해서만 받아야 한다.
  4. Controller는 Model과 View에 의존해도 된다.
  5. View가 Model로부터 데이터를 받을 때, 반드시 Controller에서 받아야 한다.

(의존이란 의미는 쉽게 말해 A, B 파트가 있을 때, A 코드에 B 코드가 존재한다면 A는 B를 의존한다고 말한다.)


또한, 이 과정에서 DTO 사용을 고려해봤지만, 이렇게 하면 해당 프로젝트가 더 복잡해질 것 같았기에 반환값을 자바의 기본 자료형을 반환할 수 있도록 노력하였습니다.

 

아쉬웠던 부분은 핵심 도메인인 Lotto와 당첨 순위를 나타내는 LottoRanking(Enum)은 조금 노출되었다는 점입니다.

(나름대로 이를 보완하기 위해 클래스 내의 메소드들을 최대한 private으로 만들었습니다.)

참고자료:
SOLID 원칙, 어렵지 않다!
MVC(Model, View, Controller) Pattern
(10분 테코톡) 🧀 제리의 MVC 패턴

 

미션 과정

3주 차 미션은 "로또" 구현이였습니다. 기존과 마찬가지로 기능 요구 사항, 프로그래밍 요구 사항, 과제 진행 요구 사항 세 가지를 지키면서 미션을 완료하면 됩니다.

3주 차에서는 추가로 클래스(객체) 분리, 도메인 로직에 대한 단위 테스트 작성, UI와 비즈니스 로직 분리 연습을 목표로 하고 있습니다.

또한, 저번 2주 차 피드백으로 아래 3가지 사항을 유의하며 이번 미션을 진행했습니다.

 

1. 기능 목록을 재검토한다

"2주 차 때, 기능 목록에는 클래스명을 기록했는데, 이 부분은 바뀔 수 있기 때문에 제거하고 정상적인 경우 말고 예외 상황을 기능 목록에 정리한다."

3주차 구현 기능 목록

위 피드백을 적용해 이번 미션때는 구현 기능 목록을 작성할 때, [예외처리] 라는 키워드를 사용하여 예외 상황을 구분하였습니다.

2. 값을 하드 코딩하지 않는다

"문자열, 숫자 등의 값을 하드 코딩하지 마라. 상수(static final)를 만들고 이름을 부여해 이 변수의 역할이 무엇인지 의도를 드러내라."

public static final int EMPTY_COUNT = 0;

private int getTotalReward(Map<LottoRanking, Integer> result) {
    return result.keySet()
        .stream()
        .mapToInt(ranking -> ranking.getReward() * result.getOrDefault(ranking, EMPTY_COUNT))
        .reduce(Integer::sum)
        .orElse(EMPTY_COUNT);
}

지난 미션에서는 큰 틀에서만 상수를 사용하고 있었는데, 나중에 보면 헷갈릴거 같은 부분들은 상수를 만들고 사용하였습니다.

 

3. 테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해본다

이 피드백을 통해, 제가 생각한 테스트를 작성하는 이유는 "단순히 생각한 기능 목록에 대해 방향성을 알 수 있고 잘못된 부분이 있으면 빠르게 수정할 수 있기 때문" 이라고 생각 합니다.

 

(이에 대한 생각의 이유는 아래 배운점에 포함되어 있습니다.)


배운 점

기능 목록을 통해 테스트를 작성하고 기능 설계에 빠른 수정이 가능하다는 걸 배웠습니다.
처음 설계할 때, 입/출력 담당 부분에서 모든 예외 처리를 계획했습니다.

#구현 기능 목록
## 로또 판매원
- [ ] 고객에게 로또 구입 금액에 맞는 로또 개수를 반환한다.

## 로또 자동 발행기
- [ ] 로또 개수만큼 로또를 발행한다.
  - [ ] 로또 발행은 개수만큼 자동으로 발행한다.

## 로또 통계
- [ ] 구매한 로또의 당첨 통계를 계산한다. 
  - [ ] 구매한 로또 번호의 당첨 내역을 계산한다.
  - [ ] 구매한 로또의 수익률을 계산한다. 

## 입력
- [ ] 로또 구입 금액을 입력 받는다. 
  - [ ] [예외처리] 입력이 숫자가 아닌 경우 예외 처리한다.
  - [ ] [예외처리] 1,000원보다 작은 경우 예외 처리한다.
  - [ ] [예외처리] 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다.
- [ ] 당첨 번호를 입력 받는다. 
  - [ ] 입력받은 번호를 쉼표(,)를 기준으로 구분한다.
    - [ ] [예외처리] 쉼표로 구분 되지 않으면 예외 처리한다.
    - [ ] [예외처리] 구분된 숫자가 6개가 아니면 예외 처리한다.
    - [ ] [예외처리] 숫자가 1~45의 수가 아니면 예외 처리한다.
    - [ ] [예외처리] 숫자가 중복 되면 예외 처리한다.
- [ ] 보너스 번호를 입력 받는다.
  - [ ] [예외처리] 숫자가 1~45의 수가 아니면 예외 처리한다.
  - [ ] [예외처리] 숫자가 당첨 번호와 중복 되면 예외 처리한다.

처음 설계한 기능 목록

 

그러나, 테스트를 작성하는 과정에서 2가지 문제점을 발견하였습니다.

1. 예외 처리에 대한 로직을 검증하기 힘들다.

2. View를 담당하는 입/출력에서 비즈니스 로직과 관련된 부분이 노출이 발생한다.

 

이를 해결하기 위해, 도메인에 대한 예외 처리View에 대한 예외 처리 부분을 따로 추출하여 해당하는 클래스에서 담당하게 하였습니다.

#구현 기능 목록
## 로또
- [ ] 1~45 사이의 서로 다른 6개의 숫자로 이루어진다.
  - [ ] [예외처리] 구분된 숫자가 6개가 아니면 예외 처리한다.
  - [ ] [예외처리] 숫자가 1~45의 수가 아니면 예외 처리한다.
  - [ ] [예외처리] 숫자가 중복 되면 예외 처리한다.

## 보너스 번호
- [ ] 1~45 사이의 당첨 번호와 중복되지 않는 숫자 하나이다.
  - [ ] [예외처리] 숫자가 1~45의 수가 아니면 예외 처리한다.
  - [ ] [예외처리] 숫자가 당첨 번호와 중복 되면 예외 처리한다.

## 로또 판매
- [x] 고객에게 로또 구입 금액에 맞는 로또 개수를 반환한다.
  - [ ] [예외처리] 1,000원보다 작은 경우 예외 처리한다.
  - [ ] [예외처리] 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다.

## 로또 발행 
- [ ] 로또 개수만큼 로또를 발행한다.
  - [ ] 로또 발행은 개수만큼 자동으로 발행한다.

## 로또 통계
- [ ] 구매한 로또의 당첨 통계를 계산한다. 
  - [ ] 구매한 로또 번호의 당첨 내역을 계산한다.
  - [ ] 구매한 로또의 수익률을 계산한다. 

## 입력
- [ ] 로또 구입 금액을 입력 받는다. 
  - [ ] [예외처리] 입력이 숫자가 아닌 경우 예외 처리한다.
  
- [ ] 당첨 번호를 입력 받는다.
  - [ ] [예외처리] 숫자와 쉼표로만 구성되어야 한다.
  - [ ] [예외처리] 쉼표로 구분 되지 않으면 예외 처리한다.
    
- [ ] 보너스 번호를 입력 받는다.
  - [ ] [예외처리] 숫자로만 구성되어야 한다.

예외처리를 분리한 기능 목록

 

위 과정을 통해, 테스트를 작성함으로서 변경(코드 로직 변경)과  구상한 설계에 대한 빠른 피드백을 얻을 수 있다는 걸 배웠습니다.


느낀 점

이제 마지막 한 주가 남았다는 게 믿기지 않을 정도로 시간이 정말 빠르게 지나가는 것 같습니다.
리뷰를 작성하면서 현재까지 했던 과제들을 살펴보았는데, 많은 변화가 있었습니다.


기능 목록을 작성하는 것도 기존에는 기능 요구 사항과 차이가 없었다면 현재는 그래도 기능별로 나누어져 있고, 예외 처리도 잘 작성되고 있는 것 같습니다.
또한, 한 주마다 블로그에 회고를 작성하고 있는데, 첫 주차 때는 미션을 하면서 정리한 것을 토대로 회고를 작성하는데 3일 정도가 걸렸지만, 이제는 하루 만에 쓸 수 있을 정도로 글 쓰는 것도 익숙해지고 있습니다.


프리코스 과정이 생각보다 쉽지 않고 부족한 부분을 미션과 피드백을 통해 많이 알게 되었습니다.
남은 한 주도 배운 것을 토대로 부족한 점을 개선할 수 있도록 최대한 노력해보겠습니다.


개선점

회고를 작성하면서 슬랙을 확인해보니 수익률의 출력양식이 다음과 같았습니다.

수익률 예시

"기능 요구 사항의 소수점 둘째 자리에서 반올림한다." 이 부분에만 관심을 두고 보니

예시에 수익률이 세자리 수가 넘어가는 경우 1,000,000.0% 이렇게 ',' 표시를 놓쳤습니다.

미션을 수행하면서 나중에 해야지.. 하고 기록을 해두지 않으니 이런일이 발생한 것 같습니다.

마지막 주차에서는 기능 요구 사항의 예시도 꼼꼼히 확인하고

구현 기능 목록예시까지 확실히 기록해둬야할 것 같습니다..


시간이 지난후 결과

다음주 미션 후 작성 예정..

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함