[kt cloud TECH UP] 완벽한 모듈 격리: Gradle api vs implementation
2026. 2. 6.본 포스팅은 치열하게 진행 중인 kt cloud TECH UP 실무 통합 프로젝트의 일환으로 진행된 마라톤 티켓팅 플랫폼 구축기의 이어지는 기록입니다.)
1. 분리된 모듈 사이에서 피어난 고민
우리는 1편에서 비대했던 하나의 거대한 main 서비스를 common, auth, main으로 분리하는 데 성공했습니다. 하지만 코드가 물리적으로 나뉘었음에도 불구하고, 의존성 관리라는 큰 숙제가 우리 팀을 기다리고 있었습니다.
이 과정에서 우리 백엔드 팀이 직면했던 가장 치열한 논의 주제는 바로 빌드 도구인 Gradle 환경에서 외부 의존성을 정의할 때 api를 사용할 것인가, implementation을 사용할 것인가 였습니다.
2. 의존성의 전이(Transitive Dependency): 달콤한 유혹 api
common (공통) 모듈은 사실상 다른 모든 모듈이 참조하는 가장 근간이 되는 모듈입니다. 자연스럽게 common 모듈은 내부적으로 Spring Security 구조나 JWT 처리를 위한 다양한 라이브러리(jjwt 등)를 필요로 합니다.
이때 common 모듈의 build.gradle에서 의존성을 api 키워드로 선언하면 아주 간편한 이점이 생깁니다.
common 모듈을 가져다 쓰는(의존하는) 상위의 main이나 auth 모듈에서, 별도로 jjwt 같은 의존성을 추가하지 않아도 common을 통해 해당 의존성이 그대로 투과되어(전이되어) 사용 가능해진다는 점입니다.
- 장점:
build.gradle파일들이 단순해지고, 중복된 라이브러리 선언을 획기적으로 줄일 수 있습니다.
3. 왜 우리 팀은 불친절한 implementation을 강제했을까?
그럼에도 불구하고 우리 팀의 결론은 단호했습니다. **"어떤 모듈이 어떤 라이브러리를 쓰는지 한눈에 직관적으로 파악해야 한다!"**는 아키텍처 원칙을 바탕으로 implementation의 사용을 규칙으로 세웠습니다. 그 이유는 크게 두 가지입니다.
3.1. 모듈 결합도의 상승 방지
api는 의도치 않은 '사이드 이펙트'를 동반합니다.
common 모듈 개발자가 자신이 필요해서 추가한 라이브러리가, 자신도 모르게 수많은 상위 모듈로 흩뿌려져 사용될 수 있습니다. 훗날 common 모듈에서 그 라이브러리를 제거하거나 버전을 바꾸려 할 때 수많은 곳에서 의도치 않은 에러와 격돌하게 됩니다. 이는 결국 common과 main을 나누어 결합도를 끊어내고자 했던 우리의 MSA 분리 취지와 정면으로 충돌했습니다.
3.2. 캡슐화(Encapsulation) 원칙 보장
가장 본질적인 이유는 캡슐화의 붕괴였습니다. implementation 키워드는 **"이 라이브러리는 현재 이 모듈 내부의 구현에서만 사용할 것이며, 나를 소환하는 상위 모듈에게 이 라이브러리의 존재를 숨기겠다"**라는 캡슐화의 철학을 선언하는 기능입니다.
main 모듈은 common이 제공하는 잘 포장된 '메소드 인터페이스'만 이용하면 되지, common이 내부에서 무슨 JWT 라이브러리로 그것을 구현했는지까지 알 (혹은 사용할) 필요가 없습니다.
4. 의존성의 경계가 명확해질 때 다가온 안전
설령 상위 모듈과 개발자가 dependencies를 한 번 더 번거롭게 중복해서 써야 한다고 하더라도, 우리는 철저하게 캡슐화를 보호했습니다.
그 결과, 나중에 인증 구현부가 통째로 바뀌더라도 비즈니스 도메인(main)은 빌드 의존성에 타격을 받지 않는 단단한 방어벽을 얻을 수 있었습니다. 이러한 명확한 의존성의 분리는 훗날 우리가 API Gateway를 도입하여 인증의 책임을 완전히 바깥으로 도려낼 때, 극적인 추진력을 제공하게 됩니다.
➡️ (다음 포스팅에서 계속)