[3주차 미션에 들어가기 전]
2주 차 공통 피드백을 읽으며 테스트를 작성하는 이유, 메서드가 한 가지 기능을 하는지 확인하는 기준을 세우라는 피드백이 기억에 남습니다.

피드백을 읽으며 제가 2주차에서 겪었던 문제가 떠올랐습니다. 자동차 경주 미션을 진행하면서 저는 ‘일단 돌아가는 코드를 만들고, 리팩터링 하자’는 생각으로 코드를 짜기 시작했습니다.
그 결과, 자동차 객체 생성부터 자동차 이동, 게임을 n회 반복하는 기능까지 모두 하나의 메서드 안에 구현하게 되었습니다.
제가 작성한 코드에서 크게 두 가지 문제를 느꼈습니다.
- 에러의 원인을 찾기 어려웠다.
테스트 코드를 실행했을 때 오류가 발생했지만, 어디서 문제가 생겼는지 바로 파악하기 어려웠습니다. 결국 출력값을 계속 확인하며 디버깅을 해야해서 많은 시간을 소모했습니다. 처음부터 기능을 작은 단위로 나누고 각 단위별로 테스트를 작성했다면 에러를 빨리 찾을 수 있었을 것입니다. - 리팩터링의 기준을 세우기 어려웠다.
리팩터링을 진행하면서 모든 기능이 한 메서드에 섞여 있어서 어떤 기준으로 코드를 분리해야할지 막막했습니다. 고민 끝에 자동차 생성, 이동, 게임 반복의 세 가지 기능으로 분리하려고 하자 강한 결합으로 인해 또 다른 에러가 발생했습니다. 이 경험을 통해 처음부터 작은 기능 단위로 함수를 만드는 것이 얼마나 중요한지 깨달았습니다.
이러한 시행착오를 겪으며, 에러의 원인을 빠르게 찾고 안정적으로 리팩터링하기 위해서는 테스트 코드가 필요하다는 저만의 이유를 찾을 수 있었습니다.
또한 3주 차 미션에서는 같은 실수를 반복하지 않기 위해 처음부터 README에 예외 상황을 포함한 구현 기능 목록을 상세히 기록하기로 했습니다. 자동차 경주 미션을 통해 메서드에 반복문과 조건문이 중첩될수록 코드의 결합도가 높아지고 분리가 어려워진다는 점을 배웠습니다.
따라서 3주 차부터는 “메서드가 한 가지 기능만 수행하는가?"를 검증하기 위해
메서드 안에서 반복문이나 조건문이 중첩되는지
하나의 책임만 수행하는지
를 기준으로 정했습니다.
[가장 오래 고민했던 부분 - 재사용 가능한 입력값 검증 로직]
지난 미션에서 예외 처리 로직이 여러 곳에 중복되어 있는 것이 마음에 걸렸고, 이를 개선하고 싶었습니다. 그래서 이번 주차의 새로운 도전 테마는 “재사용성을 높이는 것”으로 정했습니다.
로또 미션에서는 사용자의 입력값이 여러 가지 형태로 주어졌습니다. 로또 구입 금액, 당첨 번호, 보너스 번호가 있었는데, 이 세 입력값 모두에서 유효성 검증이 필요했습니다.
예외 상황을 정리하던 중 공통점이 있다는 것을 발견했습니다.

- 입력값이 숫자가 아닐 때
- 공백이거나 null인 경우
이러한 경우는 모든 입력값에서 동일하게 처리되어야 했습니다.
또한 당첨 번호와 보너스 번호의 경우에는 추가로
- 숫자가 1~45 범위에 속하는지
- 중복된 값이 존재하지 않는지
에 대한 공통적인 유효성 검사가 필요했습니다.
여러 곳에서 반복되는 동일한 검증 로직들을 재사용할 수 있다면 훨씬 효율적일 것이라는 생각이 들었습니다. 그래서 입력값 검증을 전담하는 Validator 클래스를 따로 만들고, 검증 메서드들을 static으로 선언해 어디서든 호출할 수 있도록 구성했습니다.

이렇게 분리하고 나니 코드가 훨씬 깔끔해졌고 검증의 책임은 Validator임을 명확하게 할 수 있었습니다. 예외 처리가 필요한 부분에서는 Validator.validateNotBlank()처럼 호출만 하면 되어서 코드의 가독성도 높아졌습니다. 수정이 필요할 때 Validator 클래스만 고치면 되기 때문에 유지보수가 훨씬 쉬워졌습니다.
테스트도 한결 편해졌습니다. Validator의 각 메서드에 대한 개별적 테스트 코드를 작성하고 검증했습니다. 만약 저번 주차처럼 테스트 코드가 한 메서드 안에 뭉쳐있고 중복되는 코드가 있었다면 테스트 코드 작성이 어려웠을 것입니다.
이번 시도를 통해 중복되는 코드를 줄여서 코드를 더 유연하고 관리하기 쉽게 만드는 것이 재사용성의 핵심이라는 점을 깨달았습니다.

[다음에 다르게 접근해보고 싶은 부분 - DTO를 활용한 출력]
이번 로또 미션을 진행하면서 당첨 결과를 어떻게 표현할지 고민이 많았습니다. 저는 Rank라는 Enum을 정의해서 관리하기로 결정했습니다.
제가 Enum을 선택한 이유는 다음과 같습니다.
- 유한하고 명확하게 구분되는 값들이기 때문입니다
이런 유한한 상태 집합을 표현할 때는 Enum이 가장 자연스럽다고 생각했습니다.
로또의 등수(1등, 2등, 3등, …)는 명확하게 정해져 있고, 새로운 등수가 추가될 가능성이 거의 없습니다. - 각 등수에 관련된 속성(matchCount, bonusMatch, prize 등)을 함께 관리할 수 있습니다.
Enum 내부에 각 등수별 조건(몇 개 일치, 보너스 여부)과 상금 정보를 함께 정의해두면, 로직을 분리하지 않고 한눈에 파악할 수 있습니다. 미션을 진행하면서 Rank.SIX_MATCH.getPrize()처럼 바로 참조할 수 있어 사용이 편리했습니다. - 출력을 용이하게 하기 위해서 입니다.
Rank별 당첨 개수가 담긴 Map<Rank, Integer>로 관리해서 Enum을 사용한 설계는 로직이 깔끔해졌습니다. 상금 계산이나 출력에서도 Rank를 그대로 Map의 Key로 사용하는 등 여러 부분에서 일관성이 생겼다. Enum의 장점을 최대한 살린 선택이었다고 생각했습니다.
그러나 이번 미션을 진행하며 다른 분들의 2주 차 코드를 리뷰하다 보니, DTO를 활용해 라운드별 실행 결과를 표현한 패턴이 눈에 들어왔습니다.
DTO를 사용하면 각 라운드별 실행 결과를 객체 단위로 깔끔하게 포장할 수 있었습니다. 라운드마다 모든 Car 객체의 현재 상태를 저장해두고, 게임이 종료된 후 한 번에 출력할 수 있었습니다. DTO를 통해 구현한 코드를 보니, 비즈니스 로직에서 데이터 전달과 관리가 훨씬 명확하다 느껴졌습니다.
또한 코드 리뷰 과정에서 record를 처음 접해서 찾아봤습니다. record를 활용하면 DTO를 불변 객체로 간단히 정의할 수 있었습니다. 데이터의 안전성을 확보하면서도 코드가 훨씬 간결해진다는 장점이 있었습니다.
이번 미션에서는 이미 정의되어 있는 Lotto 클래스와 기존 구조로 인해 바로 적용하지는 못했지만, 다음 미션에서는 DTO나 record를 활용해 데이터 구조를 더욱 명확히 표현해보고 싶습니다.
[3주차를 마무리하며 느낀 점]
저번 주차 미션을 진행하면서 MVC 패턴을 적용하는 과정에서 각 라운드별 실행 결과를 어떻게 출력하는 것이 좋은 구조일까 하는 고민이 생겼습니다. 혼자 고민하다가 방향이 명확히 잡히지 않아 디스코드 토론하기에 질문 글을 올려 다른 분들과 의견을 나누었습니다.

생각보다 많은 분들이 같은 지점에서 고민하고 있었고, 각자 다른 방식으로 문제를 해결하고 있었습니다. 어떤 분은 DTO를 이용해 라운드별 스냅샷을 저장한 뒤 한 번에 출력하는 방식을 사용했고, 또 어떤 분은 옵저버 패턴을 적용해 출력 로직을 독립시킨 구조를 보여주었습니다. 이벤트 기반으로 설계했다는 분의 접근 방식도 매우 인상 깊었습니다.
다른 사람들의 접근 방식을 보면서 내가 가진 사고의 폭이 많이 넓어졌습니다. 처음에는 ‘Car 객체가 직접 출력 메시지를 가지면 되지 않을까?’라는 단순한 생각이었지만, 다양한 방법으로 구현된 코드들을 보면서 사고의 폭을 넓힐 수 있었습니다. 특히 DTO나 브로드캐스터, 옵저버 패턴 같은 개념을 다른 사람들이 구현한 코드를 통해서 접하니 훨씬 이해하기 쉬웠습니다.
이 경험을 통해 단순히 정답을 찾는 질문보다 다른 사람들의 사고 과정을 이해하고 비교해보는 대화가 훨씬 더 큰 배움이 된다는 걸 느꼈습니다. 커뮤니티 안에서 서로의 코드를 보고 의견을 주고받는 과정이 사고의 깊이를 키워주는 시간이었습니다.
제가 올린 글에서 사람들이 댓글로 서로 소통하며 새로운 지식을 얻어가는 모습을 보면서, ‘아, 배우는 건 나만이 아니구나’ 하는 생각이 들었습니다. 제가 시작한 작은 질문이 누군가에게 배움의 계기가 되고, 또 그 대화가 다시 저에게 새로운 통찰을 주는 걸 보며 ‘성장은 함께 나눌 때 더 커진다’는 제 삶의 모토를 직접 실천하고 있다는 느낌이 들어 정말 뿌듯했습니다. 3주차 미션이 끝나면 고민했던 부분을 올려서 또 다같이 토론하고 싶습니다.
'우아한테크코스 8기' 카테고리의 다른 글
| [우아한테크코스 8기] 최종 코딩테스트 후기 (3) | 2026.02.03 |
|---|---|
| [우아한테크코스 8기] 1차 합격 했어요! (1) | 2025.12.30 |
| [우아한테크코스 8기] 프리코스 오픈미션 회고 (0) | 2025.12.02 |
| [우아한테크코스 8기] 프리코스 2주차 회고 (0) | 2025.10.29 |
| [우아한테크코스 8기] 프리코스 1주차 회고 (0) | 2025.10.21 |