린팅만으로는 부족한 이유: 코드 거버넌스의 본질
소프트웨어 개발에서 코드 품질을 지키는 첫 번째 도구로 오랫동안 린팅(Linting)이 활용되어 왔다. Checkstyle, PMD, SpotBugs 같은 도구들은 Java 백엔드 프로젝트에서 정적 분석의 기본으로 자리잡았다. 하지만 린팅은 본질적으로 문법적 규칙 준수와 패턴 위반 감지에 초점을 맞춘다. 즉, 코드가 어떻게 작성되었는지는 검사할 수 있지만, 그 코드가 왜 그렇게 작성되었는지, 시스템 전체 맥락에서 적절한지는 판단하지 못한다.
린팅이 잡아낼 수 없는 문제들은 실무에서 더 자주, 더 크게 터진다. 트랜잭션 경계를 잘못 설계한 서비스 레이어, 도메인 규칙을 무시한 채 작성된 쿼리 로직, 보안 정책을 우회하는 API 엔드포인트 — 이런 결함은 린터 경고 없이 빌드를 통과한다.
거버넌스는 규칙이 아니라 구조다
진정한 코드 거버넌스는 단순한 스타일 강제가 아니다. 팀이 합의한 아키텍처 원칙, 도메인 경계, 의존성 방향이 코드베이스 전반에 일관되게 반영되도록 보장하는 것이다. 이를 위해 실무에서 활용할 수 있는 접근법은 다음과 같다.
- ArchUnit: 패키지 간 의존성 방향, 레이어드 아키텍처 규칙을 테스트 코드로 명시하고 CI에서 강제할 수 있다.
- ADR(Architecture Decision Records): 결정 근거를 문서화하여 코드 리뷰 기준을 명확히 한다.
- 커스텀 정적 분석 룰: PMD나 SonarQube의 커스텀 룰셋으로 팀 고유의 도메인 규칙 위반을 감지한다.
// ArchUnit 예시: Service가 Controller를 참조하면 테스트 실패
@Test
void servicesShouldNotDependOnControllers() {
noClasses()
.that().resideInAPackage("..service..")
.should().dependOnClassesThat()
.resideInAPackage("..controller..")
.check(importedClasses);
}
이처럼 거버넌스 규칙을 코드로 표현하고 자동 검증하는 것이 핵심이다. 문서나 리뷰 코멘트에만 의존하면 시간이 지날수록 규칙은 형식화된다.
코드 리뷰와 자동화의 역할 분담
린팅과 자동화 도구가 기계적으로 처리할 수 없는 영역은 코드 리뷰가 담당해야 한다. 다만 리뷰어가 스타일 교정에 에너지를 쏟지 않도록, 자동화 가능한 것은 최대한 도구에 위임하는 것이 중요하다.
실무적인 역할 분담은 다음과 같이 구성할 수 있다.
- 린터 + 포매터: 코드 스타일, 네이밍, 미사용 임포트 등 기계적 규칙
- ArchUnit + 커스텀 룰: 아키텍처 원칙, 의존성 방향, 도메인 규칙
- 코드 리뷰: 비즈니스 로직의 적절성, 설계 트레이드오프, 예외 처리 전략
- 통합/E2E 테스트: 런타임에서만 확인 가능한 동작 보장
이 분담 구조가 명확할수록 리뷰 피드백의 질이 높아지고, 팀 전체의 거버넌스 역량이 코드베이스에 누적된다.
정리
- 린팅은 코드 스타일과 패턴을 검사하지만, 아키텍처 원칙과 도메인 규칙 준수는 보장하지 못한다.
- ArchUnit 같은 도구로 거버넌스 규칙을 테스트 코드화하면 CI 단계에서 자동으로 강제할 수 있다.
- 자동화 도구와 코드 리뷰의 역할을 명확히 분리할수록 팀의 거버넌스 수준이 지속적으로 향상된다.