gradle에서 편하게 의존성 버전 관리하기

komment·2024년 12월 6일
13

2024 개발 일지

목록 보기
7/7
post-thumbnail

포스팅과 관련된 코드는 케이크크 서버 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 버전을 사용하면 당연히 문제가 발생한다.

  아직 직접적으로 문제가 발생하진 않았지만, 버전 관리를 보다 용이하기 위해 리팩토링을 진행하기로 했다.

해결

1. dependencyResolutionManagement 블록

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는 뭘까?

2. 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" }

3. 의존성 추가

  위에서 우리는 버전 카탈로그를 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)

  다음과 같이 추가해주면 다음과 같이 동일한 버전이 빌드된다.

profile
안녕하세요. 서버 개발자 komment 입니다.

0개의 댓글