-
[우아한테크코스 5기] 프리코스 3주차 로또 후기백엔드/우아한테크코스 5기 2022. 11. 16. 00:51반응형
프리코스 3주차 로또 미션 링크
https://github.com/woowacourse-precourse/java-lotto
제가 제출한 코드 링크
https://github.com/70825/java-lotto/tree/70825
이번 로또 미션은 프리코스 미션 자체만 보면 새로운 미션이지만, 구글링하면 얻을 수 있는 정보가 굉장히 많아서 기초적인 지식을 많이 얻을 수 있었습니다.
1. 현직자분들이 많이 수강하는 nextstep - 클린코드, TDD에서 진행하는 로또 미션
2. 우테코 정규과정 1단계로 진행하는 로또 미션
3. 우테코 정규과정을 진행하는 분들의 미션 회고 글
숫자야구 미션에서는 코드가 깔끔하지 못하다는 생각이 계속 남아있었습니다. 하지만 이번 미션은 전반적으로 깔끔하게 코드를 작성한 것 같아 프리코스 진행하면서 처음으로 만족스러웠네요.
1. 일급 컬렉션 사용
일급 컬렉션에 대해 검색하신 분들이라면 파악하셨겠지만, 기본으로 주어지는 Lotto 클래스가 일급 컬렉션으로 코드가 작성되어 있습니다.
아래는 일급 컬렉션을 공부하면서 간단하게 정리한 내용입니다.
스터디를 진행하면서 노션에 정리해놨는데, 다른 블로그 글에서 가져온게 많아 그대로 가져오기가 좀 그렇네요.
https://jojoldu.tistory.com/412
https://tecoble.techcourse.co.kr/post/2020-05-08-First-Class-Collection/
언제 일급 컬렉션을 쓰면 좋을까?
- 같은 객체들을 한 곳에서 관리해야 할 때
ex) 로또 번호들을 로또로 관리, 로또 종이들을 로또 종이 묶음으로 관리 - 객체들의 불변을 보장해야 할 때
→ 컬렉션에서 특정 객체의 값을 변경할 수 있는 메소드가 없어야 할 때 - 객체지향적으로 리팩토링하기 쉬운 코드를 만들어야 할 때
→ 코드가 짧고... 이해하기 쉽고... 코드 중복이 없고...
일급 컬렉션 사용 방법
public class Car { private String name; private String oil; ... } // 일급 컬렉션으로 자동차들을 관리 public class Cars { // 멤버 변수는 cars 단 하나만 사용해야함 private List<Car> cars; public Cars(List<Car> cars) { this.cars = cars; } ... } // 사람은 자동차를 여러 개를 가질 수 있으므로 cars로 저장 public class Person { private String name; private Cars cars; ... }
일급 컬렉션은 멤버 변수를 단 하나만 사용하는 것을 명심하자
일급 컬렉션의 장점
- 비스니스에 종속적인 자료구조
→ 우리가 원하는 비즈니스 요구 사항에 필요한 자료구조 - 컬렉션의 불변성을 보장함
→ setter만 만들지 않으면 객체의 값을 수정할 수 없음 - 상태와 행위를 한 곳에서 관리할 수 있음
→ 로또 미션 기준으로 로또 객체를 만들 때, 바로 검증을 진행하기 때문에 코드가 깔끔해짐 - 컬렉션이 이름을 가지고 있어서 관리하기가 편함
→ List<Lotto> 대신 Lottos를 해두면 Lottos에 List<Lotto>와 관련된 메소드가 존재하므로 유지보수하기 편함
2. Enum, EnumMap 사용
Enum을 통해 1등, 2등, 3등, 4등, 그 외를 지정해주었습니다.
그런데 로또를 여러 개 샀을 때 1등이 몇 번 됐는지, 2등이 몇 번 됐는지, ... 이 값을 구하려면 다른 자료구조가 필요하더라구요.
처음에는 HashMap을 사용하려다가 EnumMap이라는 것을 발견하여 적용하였습니다.
아래 링크는 공부했던 글들입니다.
왜 enum을 사용해야 하는지 파악했지만, 실제로 코드 작성하는게 굉장히 어렵더라구요.
그리고 각 등수를 파악하는데 필요한 코드는 BiPredicate 인터페이스를 통해 만들었습니다.
https://www.nextree.co.kr/p11686/
https://techblog.woowahan.com/2527/
https://steady-coding.tistory.com/362
https://creampuffy.tistory.com/146
https://yeonyeon.tistory.com/195
3. validate 코드 재작성
- [1주차 프리코스] 입력 형식이 올바르면 true / 올바르지 않으면 false를 반환하도록 boolean 메소드를 작성
- [2주차 프리코스] 굳이 boolean을 반환해야 할 이유가 있을까? 라는 의문이 들어서 void 메소드를 작성
- [3주차 프리코스] 굉장히 좋은 validation 코드를 발견해서 전부 아래 방식으로 통일
2주차에 제가 작성한 코드와 비교해보니 많이 부족하다는 생각이 들었고, 이후 아래 내용까지 추가하여 더 깔끔하게 코드를 작성했습니다.
4. 예외 처리 별도 관리
우테코 정규과정 팀프로젝트 코드를 보고 있다가 예외처리를 Exception 폴더에 전부 넣어서 관리하는 것을 발견했습니다. 그래서 저도 제 코드에 적용해보니 확실히 보기 깔끔해졌습니다.
package lotto.exception; public class DuplicateLottoNumberException extends IllegalArgumentException { private static final String ERROR_MESSAGE = "[ERROR] 번호가 중복되는 로또 번호가 존재합니다."; public DuplicateLottoNumberException() { super(ERROR_MESSAGE); } }
private void validateDuplicate(List<Integer> numbers) { Set<Integer> nonDuplicateNumbers = new HashSet<>(numbers); if (nonDuplicateNumbers.size() != 6) { throw new DuplicateLottoNumberException(); } }
단점은 이제 예외처리에도 이름을 잘 적어야 한다는 것이였습니다.
5. 자바 8 기능 사용
객체지향 생활 체조 원칙 규칙 1 - 한 메서드에 오직 한 단계의 들여쓰기만 한다.
로또 미션 프로그래밍 요구 사항 - 들여쓰기 깊이는 최대 2까지만 허용한다.
이번에는 stream을 적극적으로 사용해서 들여쓰기 깊이를 최대한 0으로 만들었습니다.
그 결과 모든 메소드의 들여쓰기 깊이를 1 이하로 만들어서 미션 요구 사항을 지키고도 남았습니다.
처음에는 stream 사용이 어색해서 이걸 사용하는게 정말 좋은 것일까? 라는 생각도 들었는데, 지금은 가독성 때문에 사용하는 것이 무조건 맞다는 생각이 드네요.
6. JUnit 적용
테스트 코드는 많이 작성하지 못했지만, 그래도 중요한 부분은 습득하고 넘어간 것 같습니다.
- @ParameterizedTest
- @ValueSource
- @CsvSource
- @MethodSource
그동안 알고 있었던 어노테이션도 있어서 이제 단위 테스트를 할 때 필요한 어노테이션은 대부분 배운 것 같다는 느낌이 드네요.
7. MVC 패턴 적용
이번 미션에서는 View와 나머지 로직들을 분리하라는 요구사항이 있어서 MVC 패턴을 적용하였습니다.
domain
- generator
- LottoGenerator (로또를 여러개 생성하는 객체)
- LottoNumbersGenerator (로또를 1개 만들어주는 객체)
- Lotto (로또)
- Lottos (로또 여러개를 관리하는 객체)
- Money (돈, 로또를 몇 개 살 수 있는지 구하는 객체)
- Prize (enum, 1등, 2등, 3등, 4등, 5등, 꽝)
- PrizeResult (EnumMap과 관련한 객체)
- Rate (수익률을 얻는 객체)
- WinningLotto (당첨 번호, 보너스 번호를 관리하는 객체)
exception
- 다양한 예외 처리를 관리해주는 곳
controller
- LottoController (프로그램의 전반적인 흐름을 관리하는 곳)
view
- 크게 입력을 받는 곳은 input, 출력만 하는 곳은 output으로 접두사를 넣어서 관리함
- input의 경우엔 Console.readLine()을 감싼 메소드를 만들어서 각 input 뷰들이 상속할 수 있도록 함
8. 프로그래밍 요구사항 구현
지킨 요구사항
- 들여쓰기 깊이는 최대 2까지만 허용한다.
- 3항 연산자를 쓰지 않는다.
- 메소드가 한가지 일만 하도록 만든다..
- 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.
- else 예약어를 쓰지 않는다.
- Java Enum을 적용한다.
지키지 못한 요구사항
- JUnit 5와 AssertJ를 이용하여 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인한다
- 도메인 로직에 단위 테스트를 구현해야 한다. 단 UI 로직은 제외한다.
지키지 못한 요구사항은 전부 테스트 코드 작성이라 다음 미션에 제대로 만들어서 코드 커버리지를 올릴 생각입니다.
9. 아쉬운 점
- 테스트 코드가 부실함
다음 미션부터는 시간이 널널해져서 테스트 메소드를 최대한 많이 만들어서 코드 커버리지를 높일 수 있도록 해볼 예정입니다.
- 클래스 / 메소드 / 변수 이름 잘 정하기
MVC 패턴으로 인해 이름을 지어야 할 상황이 많았는데, 최대한 명확하게 만들어봤지만 좀 부족한 것 같아서 공부를 해봐야 할 것 같습니다.
마지막 프리코스 미션은 완전히 새로운 미션으로 알고 있는데, 다음 미션 목표는 아쉬운 점이 더 없는 수준으로 열심히 만들 예정입니다. 다들 화이팅..!!
반응형'백엔드 > 우아한테크코스 5기' 카테고리의 다른 글
[우아한테크코스 5기] 최종 합격 후기 (10) 2022.12.29 [우아한테크코스 5기] 1차 합격 (1) 2022.12.14 [우아한테크코스 5기] 프리코스 마지막 4주차 다리 건너기 후기 (2) 2022.11.23 [우아한테크코스 5기] 프리코스 2주차 숫자 야구 후기 (4) 2022.11.08 [우아한테크코스 5기] 프리코스 1주차 온보딩 후기 (0) 2022.11.01 - 같은 객체들을 한 곳에서 관리해야 할 때