대외활동/우아한 테크코스 6기

[우아한 테크코스 6기 - 프리코스] 3주차 회고

oxdjww 2023. 11. 14. 03:35
728x90
반응형

Overview


우아한 테크코스 6기 프리코스 중 3주차 로또를 구현하고, 이에 대한 회고이다.


Github Link

3주차를 시작하며

3주차 미션을 시작하며 리마인드한 점이 있었다.

코드를 작성할 때, 내 행동과 선택에 항상 이유가 있어야 한다는 것이다.

클래스를 분리하는 연습을 하기 전, 이번 과제에도 MVC 패턴을 적용하여 해결하려 했다.
많은 레퍼런스들이 MVC 패턴을 적용하여 프리코스의 과제를 해결했고, 나 또한 몇 차례 써보았기에 맹목적으로 사용했다.

하지만 정작 나는 MVCModel에 대한 정의도 제대로 못 내리는 상태였다.

코드리뷰를 하며 동료들의 코드를 보던 중, domain이라는 패키지 안에 다양한 비즈니스로직을 수행하는 클래스들을 볼 수 있었다. MVCModel은 찾을 수 없고 domainservice만이 존재하니, 이 구조에 의문점을 가졌다.

몇 차례의 검색을 통해 어플리케이션의 비즈니스 로직을 담당하는 Model 안에 역할이 나뉘어 있다는 것을 깨달았다. 세부적으로 객체를 담는 domain, 메인 비즈니스 로직 구현을 위한 service, 메모리나 데이터베이스에 접근을 하기 위한 repository로 구분된다는 아주 기본적인 개념이였다.

막연하게 domain이 그저 model과 유사한 개념으로 쓰이는 것으로 인지하고, 남들이 쓰는 MVC패턴을 적용하여 2주간 과제를 해왔던 나를 반성할 수 있었다.

그 과정을 통해 나는 앞으로 나와 경쟁하리라 다짐했다.

동료들과 코드리뷰를 진행할 때, 누가봐도 모듈의 분리가 잘 되었고, 자바 문법을 적절히 잘 활용하며 컨벤션을 잘 지킨 클린 코드를 많이 볼 수 있었다.
이런 코드를 보며 ‘이유’를 찾지 않은 체 그저 ‘아 이렇게 쓰면 되는구나’라고 무작정 나에게 적용하며 너무 성급했던 것 같다.

프리코스의 반이 지난 지금, 3주차부터는 비교대상을 남에게 두지 않을 것이다. 정말 요구사항에 충실하며 내 코드에 부족함을 파악하고 이를 더 나은 코드로 발전시킬 수 있는 방법을 찾는 것에 초점을 맞추며 남은 기간동안 더더욱 성장하고자 한다.

1. 클래스(객체)를 분리하는 연습

이번 구현에서, 클래스를 정말 세세하게 나누려고 최대한 노력하였다.

우선 주어진 로또의 숫자 개수가 6개인 것에서 힌트를 획득하여, Bonus를 따로 구현하였다.
그리고 처음에는 Bonus 클래스와 주어진 Lotto 클래스를 같이 가지는 Record를 만들어 하나의 로또 티켓으로 활용하려 했다.

하지만 이 로또 자체도 일급 컬렉션이란 개념을 사용해서 여러개를 묶어야 했고, 굉장히 복잡한 구조가 될 것 같아 설계를 고민했다.

이 때 객체지향의 핵심적인 원리인 역할에 대해 고민해볼 수 있었고, 이를 통해 답을 찾았다.

어쨌든 프로그램은 주어진 비즈니스 문제를 해결하기 위한 도구이다.
그렇기에 프로그램 내의 많은 기능을 통해 문제를 해결해야 하고, 객체지향 프로그래밍에서는 객체가 주체가되어 메서드로 행동을 한다.

그렇다면 객체는 클래스에 의해 생성되므로, 역할을 부여받고, 이에 맞는 책임을 갖는다.
그리고 하나의 책임은 여러 개의 행동으로 구현될 수 있다.


그리고 깨달은 바를 미션에 이렇게 적용했다.


로또와 보너스가 같이 있으면 어떤 역할을 수행할 수 있는가?

→ 없다.

로또는 당첨 로또와 비교를 할 때만 보너스를 필요로 한다.

그렇기에 계속 같이 다닐 이유가 없는 것이다.

책임 : 당첨 로또 결과 출력

행동 : 당첨 로또와 내 로또 비교, 보너스 번호 확인

역할/책임/행동으로 미션을 이해하고, 하나하나 분리했다.

그렇기에 model에서 domain/service로 나눌 수 있었다.

domain에서는 정말 순수하게 객체와 직접적으로 관련된 메서드(행동)들만 하게 했다.
그리고 복잡한 비즈니스 로직은 service에서 최대한 구현하려 했다.

domain은 최대한 domain의 특징에 맞는 책임만 지도록 하는 것이다.

소감을 적으며 코드를 다시 보는데, 사실 객체를 거의 entity처럼 getter 위주로 사용하여 service를 구현한 것을 확인할 수 있었다.
이렇게 하는 것이 맞는 방법인지는 모르겠다.. ‘객체가 행동을 하게해라’라는 원칙에 대해서 다시 한 번 생각해볼 기회를 얻은 것 같다.

시간이 부족해 리팩토링을 다 하지는 못 했는데 , NumberChecker domainservice를 구현하지 못 한 점이 개인적으로 아쉽다.

하지만 클래스를 분리하고, 매직넘버를 지우면서 enum을 활용할 수 있는 기회를 얻어 좋았다.

Controller도 이전과 다르게 3개를 구현하였다.

여태는 MainControllerGameController 하나만 구현하여 모든 Controller관련 로직을 하나에 넣었는데, 이렇게 도메인(엔티티)에 따른 Controller를 호출하고, 의존성을 갖는 구조로 설계하니 한결 보기 좋다!

하지만 Validator interface를 적극 활용하지 못한 점과, 테스트 코드를 많이 구현하지 못한 점이 매우 아쉽다.

2. 도메인 로직에 대한 단위 테스트를 작성하는 연습

테스트 코드를 통한 디버깅

테스트 코드를 구현하며 디버깅할 수 있었다.

로또 생성 시 번호가 1~45 사이의 값이 아니면 예외가 발생하게끔 코드를 구현하였는데, 테스트 코드를 적으며 모든 번호가 유효 범위 밖이여야만 예외가 발생하는 모습을 확인할 수 있었다.

단 하나라도 유효 범위 밖이면 예외가 발생해야 하는데, 이를 찾아서 매우 기뻤다
핵심 도메인 로직과 관련된 테스트 코드를 최대한 작성하려 했고, 이를 통해 intellij Test Coverage95% 이상을 달성하여 뿌듯했다.

앞으로의 테스트코드 활용 계획

추가적으로, 테스트 코드를 마지막에 다 작성하니 숙제같은 느낌이 들었다.

다음부터는 클래스나 메서드를 하나하나 구현할 때마다 테스트를 작성하는 습관을 들이고 싶다.


감사합니다.

728x90
반응형