HSQLDB 종속성 제거로 의존성 관리 개선
목차
HSQLDB가 빌드 파일에 남아 있다는 걸 인지한 건 의존성 트리를 한번 훑어보다가였다. 실제로 코드에서 직접 참조하는 곳이 있나 찾아봤는데 없었다. 이미 오래전에 다른 걸로 갈아탔거나, 아니면 처음부터 명시적으로 추가한 게 아니라 어느 라이브러리의 전이 의존성으로 딸려 들어온 뒤 그냥 남아 있던 케이스. 어느 쪽이든 지금 기준으로는 필요 없는 상태였다.
HSQLDB를 빼야 하는 이유
임베디드 Java DB 시장에서 HSQLDB는 오랫동안 H2와 함께 양대 선택지였다. 테스트 환경에서 실 DB 대신 인메모리 DB를 쓰는 패턴이 굳어지던 시기에 많이 퍼졌는데, 지금 기준으로는 H2가 사실상 표준에 가깝다. Spring Boot도 spring-boot-starter-test에 H2를 먼저 권장하는 구조고, JPA 관련 자동 설정 상당수도 H2 기준으로 동작한다. HSQLDB를 굳이 쓸 이유가 없는 상황에서 그게 classpath에 올라가 있으면 몇 가지 문제가 따라온다.
- 빌드 시간 소폭 증가 - 쓰지 않는 jar가 다운로드·캐시 대상에 포함됨
- 버전 충돌 리스크 - 다른 의존성이 HSQLDB를 전이로 당기는 버전이 다를 때 conflict 발생 가능
- 보안 취약점 노출면 확대 - 사용하지 않는 라이브러리라도 취약점 스캔에 걸리면 대응 비용이 생김
- 가독성 저하 -
build.gradle이나pom.xml읽는 사람이 "이거 왜 있지?" 하고 멈추게 됨
특히 세 번째가 생각보다 실질적인 비용이다. CVE 하나 나왔을 때 "우린 실제로 안 쓰는데요"가 통하는 맥락도 있지만, 자동화된 보안 게이트가 버전 기준으로 막아버리는 환경이면 쓰든 안 쓰든 대응해야 한다. 안 쓰는 라이브러리 하나 때문에 릴리즈 파이프라인이 막히는 건 꽤 허무한 상황이다.
제거 작업
수정 파일은 1개였다. 의존성 선언 파일에서 HSQLDB 항목을 지우고, 테스트가 H2로 정상 동작하는지 확인하는 게 전부. 실제로 HSQLDB를 참조하는 코드가 없었으니 런타임 동작 변경은 없었고, 테스트 통과 여부만 체크하면 됐다.
// 제거 전
dependencies {
testRuntimeOnly 'org.hsqldb:hsqldb:2.7.2'
testRuntimeOnly 'com.h2database:h2'
}
// 제거 후 - H2만 남김
dependencies {
testRuntimeOnly 'com.h2database:h2'
}
명시적으로 선언돼 있던 케이스라 이렇게 한 줄 지우는 게 전부였다. 만약 전이 의존성으로 여러 군데서 당겨지고 있었다면 exclude로 강제로 빼야 하는데, 그 경우엔 어디서 오는지 역추적하는 과정이 추가된다.
# 전이 의존성으로 딸려 들어오는 경우 의존성 트리 확인
./gradlew dependencies --configuration testRuntimeClasspath | grep hsqldb
이렇게 근원 의존성을 파악한 뒤, 해당 라이브러리 버전을 올리면 자연스럽게 빠지는 경우도 있고, 계속 당기면 configurations.all { exclude ... } 로 강제 제외해야 하는 경우도 있다. 근원 의존성 버전 업그레이드로 해결되면 그쪽이 더 깔끔하다.
의존성 관리를 어떻게 가져갈 건가
이번 작업은 단순한 한 줄 삭제였지만, 그 계기로 의존성 관리 전반을 다시 생각하게 됐다. 잘 정비된 의존성 목록이 주는 이점은 꽤 실질적이다.
| 상황 | 미정비 상태 | 정비된 상태 |
|---|---|---|
| 보안 패치 대응 | 쓰는 건지 몰라서 일단 올려야 함 | 영향 범위 즉시 파악 가능 |
| 신규 팀원 온보딩 | "이 의존성 왜 있어요?" 반복 질문 | 의도가 명확해서 설명 비용 낮음 |
| 버전 업그레이드 | 불필요한 것까지 전부 추적 | 실제 쓰는 것만 관리 |
| 빌드 속도 저하 추적 | 원인 파악이 어려움 | 최적화 여지 파악 용이 |
자동화 측면에서 Dependabot이나 Renovate 같은 툴을 붙여두면 버전 업데이트 PR을 자동으로 올려준다. 이게 설정해두면 잊어버릴 수 있는 게 아니라, 쏟아지는 PR을 얼마나 효율적으로 처리할 것인가가 오히려 과제가 된다. 전략 없이 켜두면 PR 폭탄이 되니 그룹핑이나 auto-merge 조건을 잘 설계해야 한다. patch 업데이트는 테스트 통과 시 자동 머지, minor는 리뷰 후 머지, major는 별도 태스크로 분리하는 식으로 계층을 두는 게 현실적이다.
의존성 업데이트를 오래 미뤄두면 나중에 한꺼번에 올려야 하는데, 그때는 breaking change가 복수로 겹쳐서 원인 파악이 어려워진다. 어떤 라이브러리 때문에 테스트가 터진 건지 bisect 하는 시간이 오히려 더 걸리는 상황. 이번 작업을 계기로 정기 점검 루틴을 만들기로 했다. 스프린트마다 의존성 트리 훑기, 분기마다 ./gradlew dependencyUpdates로 버전 gap 확인, 연 1회 이상 실제로 쓰는지 여부까지 재검토. 완벽하게 할 순 없지만 루틴이 있는 것과 없는 것의 차이는 1~2년 뒤에 드러난다.
이번 변경은 파일 하나에 한 줄 삭제였다. 실제 작업 시간은 10분도 안 걸렸는데, 그게 "별거 아니다"가 아니라 잘 관리된 환경이 이 정도 변경을 10분짜리로 유지해줬다는 의미로 읽힌다. 엉켜 있는 상태였으면 영향 범위 파악에 오히려 더 걸렸을 거다. 인프라나 환경 정비에 투자하는 시간은 복리처럼 돌아온다는 말이 진짜인 게, 쌓일수록 단순한 작업이 단순하게 유지된다.
댓글 0
첫 댓글 달아줘.