포스팅과 관련된 코드는 케이크크 서버 Github에 저장돼 있습니다.
Spring Boot를 활용하여 개발할 때 보통은 빌드 도구로 gradle을 사용한다. gradle은 많은 장점을 가지고 있고, 그 중 하나가 의존성 추가가 쉽다는 것이다. implementation, api 등을 활용해 한줄만 추가해주면 된다.
dependencies {
// 1
implementation("org.springframework.boot:spring-boot-starter-web")
// 2
implementation("org.springframework.boot:spring-boot-starter-web:3.2.4")
}
1번과 같이 의존성을 추가하거나 2번처럼 버전을 명시하여 추가할 수 있다. 1번의 경우, 가장 최신의 버전이 추가된다. 하지만 멀티모듈 프로젝트를 관리하다보면 문제가 발생할 수 있다. 다음과 같은 경우를 살펴보자.
// core 모듈
testImplementation("com.navercorp.fixturemonkey:fixture-monkey-starter:1.0.23")
// domain 모듈
testImplementation("com.navercorp.fixturemonkey:fixture-monkey-starter:1.1.3")
현재 프로젝트에선 각 모듈 별로 테스트 코드를 작성하고 있고, core 모듈에서는 비즈니스 로직 테스트, domain 모듈에서는 도메인 로직 테스트를 진행한다. 테스트에 필요한 Fixture를 생성할 때는 보일러 플레이트를 줄이고자 Naver에서 공개한 오픈 소스인 fixture-monkey를 활용하고 있다. 하지만 위처럼 각 모듈이 다른 버전의 의존성이 추가돼 있다. 또 (그런 사람은 없겠지만) spring-boot-starter-web은 3.x.x를 사용하고, spring-boot-starter-security는 2.x.x 버전을 사용하면 당연히 문제가 발생한다.
아직 직접적으로 문제가 발생하진 않았지만, 버전 관리를 보다 용이하기 위해 리팩토링을 진행하기로 했다.
public open fun dependencyResolutionManagement(dependencyResolutionConfiguration: org.gradle.api.Action<in org.gradle.api.initialization.resolve.DependencyResolutionManagement>): kotlin.Unit {
/* compiled code */
}
dependencyResolutionManagement 메서드
는 Gradle 초기화 단계에서 의존성 해상도를 관리하기 위해 실행되는 설정 블록이다. dependencyResolutionConfiguration는 Action 인터페이스를 구현하며, Gradle의 DependencyResolutionManagement
객체를 수정하는 데 사용된다.
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("libs.versions.toml"))
}
}
}
dependencyResolutionManagement 메서드를 활용하여 위와 같이 작성할 수 있다. versionCatalogs
는 Gradle 7.0부터 도입된 기능으로, 의존성 관리 및 버전 관리를 체계적으로 수행할 수 있는 도구이다. 해당 코드를 해석하면 다음과 같다.
libs
라는 이름의 버전 카탈로그를 libs.versions.toml
를 기반으로 생성 그렇다면 libs.versions.toml
는 뭘까?
libs.versions.toml
은 Gradle의 버전 카탈로그(version catalog) 파일이다. Gradle 7.0 이상에서 도입된 기능으로, 프로젝트 내 의존성과 버전을 한 곳에서 관리하기 위한 구조를 제공한다. 이를 통해 의존성을 더 명확하고 재사용 가능하게 정의할 수 있다. 그럼 예시를 살펴보자.
[versions]
kotlin = "2.0.10"
...
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
...
[libraries]
kotlin-stdlib-jdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8" }
...
[ ]
는 특정 테이블을 정의하는 섹션이다. 해당 파일은 TOML
(Tom's Obvious, Minimal Language) 방식으로 작성되기에, 리스트를 표현할 때도 활용되지만, 이 경우는 생략하겠다.
이후로는 key-value 형식으로 작성하면 된다. 만약 spring-boot 버전으로 관련 의존성의 버전을 한번에 관리하고 싶다면 다음과 같이 작성하면 된다.
[versions]
spring-boot = "3.2.4"
[libraries]
spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" }
spring-boot-starter-validation = { module = "org.springframework.boot:spring-boot-starter-validation", version.ref = "spring-boot" }
spring-boot-configuration-processor = { module = "org.springframework.boot:spring-boot-configuration-processor", version.ref = "spring-boot" }
spring-boot-starter-aop = { module = "org.springframework.boot:spring-boot-starter-aop", version.ref = "spring-boot" }
spring-boot-starter-batch = { module = "org.springframework.boot:spring-boot-starter-batch", version.ref = "spring-boot" }
위에서 우리는 버전 카탈로그를 libs
라는 이름으로 생성하였다. 의존성을 추가할 때도 libs를 사용하면 된다. 문제 단계에서 fixture-monkey로 예를 들었으니 똑같이 fixture-monkey를 추가해보자.
fixture-monkey-starter = { module = "com.navercorp.fixturemonkey:fixture-monkey-starter", version = "1.1.3" }
1.1.3 버전의 fixture-monkey를 libs.versions.toml에 작성해뒀다.
// core 모듈
testImplementation(libs.fixture.monkey.starter)
// domain 모듈
testImplementation(libs.fixture.monkey.starter)
다음과 같이 추가해주면 다음과 같이 동일한 버전이 빌드된다.