본문 바로가기
설계 이모저모

2023년 우테코 프리코스 1주차 후기

by 민휘 2023. 10. 26.

두둥 대망의 첫 미션~! 주제는 <숫자야구>였습니다. 알고보니 저번 프리코스에서도 나온 미션이더라고요! 나중에야 알았음.. ㅇㅅㅇ

이번 포스팅에서는 제가 어떤 방식으로 접근했는지, 무엇에 초점을 두며 구현했는지, 구현을 마친 후 반성한 점에 대해서 이야기해보겠습니다.

우선 제가 제출한 PR는 여기에 있습니다.

 

[숫자 야구 게임] 민휘 미션 제출합니다. by Mingadinga · Pull Request #1675 · woowacourse-precourse/java-baseball

 

github.com

 

 

1주차 미션 목표!

  • 책임 할당을 기반으로 OOP 제대로 적용하기
  • 확실한 단위 테스트 작성하기

 

객체 다이어그램 초안

책임주도설계 방식으로 객체 초안을 설계했습니다. 필요한 메시지를 식별하고, 책임을 만들어 적절한 객체에 할당했어요. 이때 객체의 응집도는 높이고 결합도는 낮추려고 했는데, 막상 구현해보니 결합도를 관리하는 것이 생각보다 어려웠습니다. 특히 리팩토링하면서 구조가 많이 바뀌었어요.

 

단위 테스트를 통해 설계 변경

테스트를 객체의 명세서처럼 쓰고 싶어서, 기능의 큰 맥락 안에서 각 객체의 기능을 최소한의 코드로 작성하고 단위 테스트를 작성했습니다. 예를 들어 컨트롤러가 게임시작을 위해 난수를 생성하고 게임 상태를 변경하는 부분은 메시지 호출을 미리 선언하고, 실제 동작하는 부분은 todo 주석으로 다음 커밋에서 구현하도록 했습니다. 무슨 말이냐면.. 코드로 확인하세요

미션은 mockito를 사용할 수 없어서, 모킹을 위해 인터페이스를 도입해 다형적으로 동작하도록 설계를 고쳐가면서 작성했습니다. 그 과정에서 설계가 어느정도 유연해진 것 같습니다. 대표적으로 테스트에서는 Console을 통해 입력 받을 수 없어서, InputComponent를 인터페이스로 분리하고 테스트에서 모킹하여 사용했습니다. 또 사용자가 정답을 맞췄는지 확인하는 조건, 정답을 맞춘 후 계속 진행하는지 여부를 모킹해 사용할 수 있도록 GameController와 GameView가 인터페이스를 참조하도록 했습니다.

기능 구현을 마친 후 생성자 위주로 리팩토링을 조금 해봤는데, 미리 작성해둔 테스트가 많은 도움이 되었습니다. 코드 구조를 바꾸더라도 요구사항이 제대로 동작하는지 확인할 수 있었어요.

 

최종 구현 다이어그램

인텔리제이 다이어그램 기능을 사용해 컴포넌트 간의 관계를 확인해보았습니다.

흠.. 역시 객체 생성을 선택하는 부분 때문에 지저분해지네요. 스프링 컨테이너를 사용할 수 없다보니 사용할 구현체를 객체에서 직접 선택해야하기 때문인 것 같아요. (스프링 그립습니다)

개인적으로 Scoring도 인터페이스로 빼는게 구현 상 더 자연스러웠을 것 같은데, 우선은 요구사항과 테스트 코드를 문제없이 동작하기 때문에 그대로 남겨두었습니다. 만약 Scoring 요구사항이 내일 바뀔 것을 반영하고 싶다면 인터페이스로 빼는 설계를 선택하는게 좋을 것 같아요.

 

코드 리뷰 후 반성한 부분

1주차 미션 제출 후 하루 동안 코드 리뷰를 진행했는데요, 다양한 접근방법을 보면서 많이 배웠습니다. 프리코스 최고~~🙌 나와 다른 시각을 가진 분들의 의견을 듣는게 굉장히 재미있었어요. 여러 코드를 읽으면서 내가 고쳐야할 부분 & 이건 내 코드에 반영하고 싶은 부분을 정리해봤습니다.

  • 클래스 개수가 너무 많음! 추상화와 복잡도의 균형을 맞출 것
  • 뷰가 게임 흐름 제어의 책임을 일부 맡고 있음, 철저하게 분리해야 유지보수하기 쉬울 것
  • 요구사항에서 사용되는 상수값(매직 넘버)을 주입 방식으로 사용할 수 있도록 유연하게 관리할 것 : 출력 문자열, 입력의 의미를 나타내는 정의 클래스 등

 

그리고 이건 1주차 미션을 하면서 다음번 미션에서 개선하고 싶은 부분입니다.

  • 인터페이스를 먼저 식별하고, 인터페이스에 의존하는 코딩하기 : 코드를 추가했을 때 변경되는 범위를 제한하기 위함
  • 커밋을 더 크게 관리하기 : 너무 작게 쪼갠 커밋은 무슨 의미인지 파악하기가 어려움. 구현할 기능에 집중하고, 직접 관련되지 않는 부분은 인터페이스로 선언하기
  • 비즈니스 로직을 도메인으로 옮기기 : Digit, Number, Input 등 단순한 문자열 값이더라도, 관련한 비즈니스 로직이 식별된다면 도메인 클래스로 옮겨서 응집도 높이기
  • 적용 가능한 패턴이 있다면 참고하기 : 응집도, 결합도를 평가하며 설계를 하다보니 유지보수 측면에서 놓치는 부분이 있었음. 떠오르는 패턴이 있다면 유연하게 사용하기

 

설계를 검증하는 유일한 방법은 구현이라고 하죠! 저도 구현을 하면서 실제 의존관계를 뜯어 고친 경우가 많았습니다. 고민도 많이 하고, 배움도 많은 시간이었어요. 다음 미션이 기대됩니다 ><