본문 바로가기
이모저모

[이모저모] 리팩토링 고민

by 희조당 2024. 6. 4.
728x90

Fixtures

현재 각 도메인 별로 Fixture가 존재한다.

생성을 담당하는 Fixture는 도메인 별로 존재하지만, Fixture에서 Persist까지 담당할 필요는 없기 때문에 Fixtures를 만들었다.

일종의 companion object이자 퍼사드 객체이다.

 

현재 기본적인 테스트 설정은 java-test-fixture 플러그인을 사용하는 common 모듈에서 담당하고 있다.

앞서 언급한 Fixture들은 도메인(모듈)을 알아야 하기 때문에 common 모듈에선 해당 정보까지는 모두 알 필요가 없다고 판단했다.

따라서, fixture들을 모든 의존성을 알고있는 client-api 모듈에 배치시켰다.

 

이게 하나의 문제를 이어지는데 바로 admin-api 모듈은 해당 fixture들을 모른다는 점이다.

따라서, 인수 테스트를 담당하는 모듈이 필요하다고 판단되어 api 모듈 하위에 acceptance-test 라는 모듈을 추가해야겠다.

Fixtures (2)

생각해보니 인수 테스트를 위한 모듈을 만들어버리면 추가적인 문제가 발생한다.

배포 시에 인수 테스트만을 돌리기 위해 다음과 같이 실행시킬 수 있는 장점은 존재한다.

./gradlew :api:acceptance-test:test

 

하지만 이렇게 작성하게 되면 빌드 경로에 테스트 결과물(ex. 문서)을 넣어줄 수가 없어서 문제가 발생한다.

따라서, 위치를 수정해야만 한다.

Case 1 : API 모듈 하위 새 모듈 추가하기

앞서 언급한 것처럼 API 모듈 아래에 새로운 모듈을 추가하고 거기에 몰아주는 방법이다.

현재 각 API 모듈은 모든 모듈에 대한 의존성을 받고 있다.

gradle의 subProject로 의존성을 맺어주니 모듈 의존성 관리에는 큰 부담이 없다.

 

여기까지만 언뜻 보면 편해 보이지만 확장에 너무 취약해진다.

현재 API(최상위 계층)에 대한 인수 테스트만 진행하고 있기 때문에, 나중에 도메인 혹은 애플리케이션 계층을 테스트해야 할 때 문제가 발생한다.

프레젠테이션 계층은 하위 계층들을 바라보고 있는데, 테스트용 객체들이 프레젠테이션 계층에 존재하게 되면서 하위 계층들이 (비록 테스트 의존성일지라도) 역으로 의존하게 된다.

Case 2 : Fixture를 각 모듈에 부여하기 (ex. User Fixture → User module)

현재 모든 Fixture는 Api 모듈에 존재하고, companion object(kotlin ❌)인 Fixtures도 같이 존재한다.

API 모듈에 있던 각 도메인의 fixture를 각 도메인 모듈에다 위치시킨다.

 

각 모듈에 퍼져있는 Fixture들은 오히려 테스트 패키지의 응집도를 떨어트리고 관리하기 어렵게 만들 것 같다.

게다가 도메인 모듈이 하나도 아니고 여럿에 depth도 있기 때문에 좋지 않은 생각 같다.

또한, 도메인 모듈에 현재 애플리케이션 계층과 도메인 계층이 존재하고 있는데, 도메인 모듈 별로 fixture를 분리해버린다면 각 도메인끼리 테스트하면서 의존성이 순환할 것이다.

Case 3 : Common 모듈에 테스트 의존성 몰아주기

기존 common 모듈은 지원 모듈로 말 그대로 지원을 목적으로 하는 독립적인 기능이 없는 모듈이다.

이 개념이 테스트를 돕는 클래스들이 모여있기 딱 적합한 위치라고 판단해서 여기에 testFixtures로 몰아 넣었다.

그래서 이 방법은 Fixture들도 common 모듈에 모아두는 방법이다.

 

현재 common 모듈에는 전역적으로 설정되어야 하는 설정(async 설정 등)이나 공용 response 등에 대한 정보를 가지고 있다.

만약 도메인 모듈에서 이 모듈을 의존하고 있지 않는다면 문제가 되지 않으나 그렇지 않다.

따라서, 앞서 언급한 것처럼 비록 테스트 의존성이어도 역으로 의존성이 발생하므로 좋지 않은 방법 같다.

Case 4 : 퍼사드를 깨고, 각 Fixture에게 persist도 위임하기

이름 그대로 Fixture에게 persist까지 위임하고, 퍼사드도 깨버린다.

 

퍼사드(Fixtures)는 분명한 편의성을 제공한다.

빈으로 등록해서 어느 곳에서도 편하게 호출할 수 있고, 다양한 저장 객체(repository)를 호출할 필요를 줄여준다.

 

근데 이 Fixtures도 결국 인터페이스이다. (Interface로 선언되어야만 인터페이스인 것은 아니다.)

현재는 너무 많은 public method를 가지고 있기 때문에 사실상 ISP(인터페이스 분리 원칙)를 깨고 있다고도 볼 수 있다.

예를 들자면, 사용자에 관련 테스트를 하고 있는데 실수로라도 사용자 외에 다른 도메인의 fixture를 만들어낼 수도 있다는 것이다. (물~론 그런 일은 거의 없겠지만)

즉, 주요 관심사 외의 것을 알 수도 있다는 것이다.

 

하지만 이런 문제들은 애플리케이션이 돌아가는데 직접적인 영향을 미치지 않는다. 테스트 코드이기 때문이다.

또한, 혹시라도 JPA가 아니라 다른 DB 접근 기술을 사용하더라도 지금 구조가 영향도 덜 받는다. (물~론 그런 일은 거의 없겠지만 222)


이런 다양한 고민을 해보면서 내린 결론은 다음과 같다.

  • 모듈은 추가하지 않는다.
    1. 지금도 모듈이 충분히 많다.
    2. 특정 모듈의 하위 모듈로 새롭게 만들려면 기존에 세워둔 모듈 규칙을 따라야 한다. 이로 인해서 제약이 발생할 수 있다. (ex. API module)
    3. 아예 새로운 모듈을 만들자니 새로운 규칙을 추가해야 한다. 물론 깔끔하게 의존성을 관리할 순 있겠지만 새로운 규칙을 도입하는 게 더 리스크가 크다.
  • common 모듈에 임시로 위임한다.
    1. 새로운 모듈을 추가하지 않기로 선택했기 때문에 남은 선택지는 ‘모든 의존성을 받는 API 모듈에 위치하기’ 혹은 ‘기존의 성질을 가지고 있는 common 모듈 사용하기’ 둘 중 하나이다.
    2. 어느 모듈을 선택하더라도 테스트 의존성이 순환하므로 그나마 범위가 작은 common 모듈을 선택했다.

댓글