ArchUnit을 사용하여 공통 개발 컨벤션을 검증하자

SightStudio

·

2024. 11. 5. 06:31

개발자로서 회사생활을 하다 보니 팀원들과 개발 컨벤션을 정의하고 합의된 컨벤션을 유지할 수 있도록 노력하고 있습니다. 
 하지만 노력만으론 부족합니다. 팀원들 간에 합의가 되었다고 해도 사람은 언제나 실수할 수 있습니다.

 

실수로 컨벤션을 어긴 코드를 작성할 가능성이 있으며, 이는 코드리뷰에서 반드시 발견될 수밖에 없습니다.
그러나 코드리뷰 과정에서 이미 합의된 컨벤션까지 확인하는 것은 팀원 간의 커뮤니케이션 비용을 증가시킵니다.

 

이런 상황이 반복되다보니 자연스레 테스트코드를 통해

팀의 아키텍처와 코딩 컨벤션을 코드로 문서화하는 방법을 찾게 되었습니다.
 
해결책을 찾다가 ArchUnit을 찾게 되었고 위의 문제를 해결해보고자 합니다.
예시코드는 "여기"에서 확인 할 수 있습니다.
 
 

 

ArchUnit이란

 
ArchUnit은 자바에서 아키텍처를 테스트하고 검증할 수 있는 오픈소스 라이브러리입니다. 
ArchUnit을 통해 코드베이스의 구조적 일관성을 유지할 수 있고, 리팩터링이나 신규 기능 추가 시
이미 합의된 아키텍처에 대한 위반을 CI에서 탐지할 수 있습니다. 
 
 

이렇게 말이죠!

 

환경 설정

 

검사할 클래스 로딩하기

 
ArchUnit은 ClassFileImporter를 통해 검사할 클래스, 패키지들을 임포팅 할 수 있습니다.
이를 통해 아키텍처 검사의 범위를 제어할 수 있습니다. 
 

 

검증 예제

 
자 이제 제가 실무에서 사용하는 형태의 몇 가지 개발 컨벤션들을 검증해 보도록 하겠습니다.
 

컨트롤러에서 DTO 상속 금지

 
필드 재사용을 위한 DTO 상속은 프로젝트 유지보수에 제일 문제가 되던 부분이었습니다.
한번 상속을 하기 시작하는 순간 이게 사용하는 필드인지 아닌지 확인하기 어려워 유지보수 비용이 높아졌습니다.

Root Object를 제외하고는 상속을 금지시켜 봅시다.

아래처럼 ArchCondition을 정의해서 룰에 추가해 주면 CI 환경에서 자동적으로 검증할 수 있습니다.
 

경험상 이부분이 Map을 리턴하는것보다 유지보수 비용이 높았습니다.

 

테스트코드를 실행해 보면 다음과 같이 상속된 클래스를 리턴하는 것을 탐지해서 에러를 발생시키는 것을 확인할 수 있습니다.

 

어느 엔드포인트에서 리턴하는지도 확인 할 수 있다.

 

JPA Entity는 클래스명이  반드시 Entity로 끝나야 한다.

 
도메인 레이어와 영속성 레이어를 분리해서 개발하다 보면 JPA 엔티티의 클래스명과 도메인 클래스명이 겹쳐서
항상 이름 짓는데 골치 아픕니다. 심지어 이름을 잘못 지어서 도메인 레이어에 엔티티가 올라오기도 합니다. 
이럴 때 JPA 엔티티에 Suffix를 주면 구분하기 훨씬 쉬워집니다.
 

이렇게 하다보면 DTO 클래스 뒤에 dto를 안붙여도 됩니다!

 

JPA Entity에서 @Transient 사용금지

 
@Transient 애너테이션은 DB 테이블과 연관되지 않은 필드들을 엔티티에 선언할 때 사용됩니다.
즉 어디에선가 setter나 생성자를 통해 값이 할당되어야 하는데요.
이 부분도 프로젝트가 커지다 보면 예측하기 어럽고 실수하기 쉬워서 싫어하는 패턴입니다.
 

필자는 이것도 정말 싫어한다.

 

프로젝트 폴더구조 검증

 
다음과 같이 JPA 엔티티들은 각 도메인 패키지의 모델 패키지 안에 넣도록 강제시킬 수 있습니다.
 

의도된 위치에 있는 ActorEntity는 에러로 검출되지 않았다.

 

아키텍처 검증

 

Serivce에서 직접적으로 Repository를 호출하지 말고 해당 도메인에 대응하는 퍼사드 클래스를 하나 만들어 이를 참조하도록 합니다. 이렇게 인프라스트럭처 레이어에 대한 명시적인 계층을 만들 수 있습니다.
 

서비스레이어는 인프라매니저를 통해서만 접근

 

해당 구조에 대한 검증

 
위의 아치유닛 테스트를 통해 아래처럼 서비스레이어가 직접적으로 JpaRepository를 참조하는 것을 방지할 수 있습니다.
 

Repository 직접참조시 테스트에서 검증

기타

 

JUnit 5 지원

아래와 같은 의존성을 추가함으로써 JUnit 5에서 ArchUnit을 사용할 때 추가적인 기능을 사용할 수 있습니다.
다만 사진처럼 하는 경우, 클래스를 캐싱할 순 있지만 메서드 단위로 실행할 수 없다는 단점이 있습니다.

ArchUnit으로 검사하는 데 걸리는 시간을 판단하고 선택하면 될듯합니다.

 

dependencies {
    testImplementation 'com.tngtech.archunit:archunit-junit5:1.3.0'
}

 
 

 
 

마치며 

 
ArchUnit을 통해 우리들의 코딩스타일을 테스트코드로 문서화할 수 있다는 점은 정말 매력적입니다.
예시로든 코딩컨벤션을 맞추기 위해서는 동료 개발자들이 직접 체크해줘야 하는 문제점이 있는데요.
문서화하고 CI 환경에서 실패하게 한다면, 새로오는 인원들도 동료들에게 물어보지 않아도 됩니다!
컨벤션이 바뀌면 논의한 후에 테스트코드를 수정하면 됩니다.
 
이렇게 팀원들의 시간을 절약한다면, 그 시간들을 더 가치 있는 곳에 투자할 수 있습니다. 
짧은 글이지만 봐주셔서 감사합니다!
 

Reference

 
- https://www.archunit.org/userguide/html/000_Index.html