본문 바로가기

Programing/Framework

Kotlin DSL Gradle: 멀티 모듈로 변경하기

spring initializr 에서 프로젝트를 만들면 단일 모듈 기반의 프로젝트를 생성한다.

처음에는 이 구조가 편하지만 단점도 있다.

바로 도메인과 구현 기술의 코드가 섞이게 된다는 것이다.

물론 언어에서는 패키지나 네임스페이스 등의 모듈을 분리할 수 있는 구조를 제공한다.

 

하지만 이것은 구조화적인 것으로 의존성에 대해 직접적인 통제를 할 수 없다.

헥사고날 아키텍처라고 불리는 '포트와 어댑터'라는 구조가 있기는 하지만 나는 페리페리크 안티 패턴(Périphérique anti-pattern)을 더 선호한다. 파리의 Boulevard Périphérique 에서 따온 메타포이다. 사실 A86이나 La Francilienne 와 같은 더 많은 외곽순환 도로가 경계(boundary)를 나누고 있다.

왜냐면 단순하기 때문이다. 도메인에 대한 것, 비즈니스에 대한 것은 안으로 묶고 참조는 밖에서 안으로만 하는 구조를 하면 도메인에 기술 요소가 붙는 것을 막을 수 있기 때문이다.

Domain은 Infrastructure를 모른다!

 

IntelliJ IDEA, Kotlin, Groovy 기준으로 기록해본다.

참고로 starter.spring.io 에서 뼈대를 만들었고 일부 코드가 있다고 가정한다.

- Project: Gradle Project

- Language: Kotlin (이 옵션을 생성하면 Gradle 이 Kotlin DSL로 생성한다. build.gradle 파일 대신 build.gradle.kt 파일이 생김)

 

기존 프로젝트 이름은 xxx-api 였다.

xxx-api 를 xxx-service 로 바꾸고, 내부에 xxx-core와 xxx-api 로 모듈을 구성하고 싶다. xxx-api는 xxx-core에 의존하게 설정한다.

 

New Module - api

단일 모듈로 되어 있는 프로젝트를 열고, File > Module... 을 선택한다.

시행착오를 겪으면서 배운 것인데, 일단 Kotlin DSL로 만들었기에 Kotlin DSL build script에 체크를 하고

디폴트로 체크되어 있는 Java는 체크 해제를 하고, Kotlin/JVM 으로 선택한다.

다음은 New Module 창

Name: 부분에 새로운 모듈 이름을 입력한다.

xxx-api 를 먼저 옮기고 xxx-core를 나중에 만들어서 분리할 생각이다.

 

이러고 나면 gradle 이 자동으로 재로딩을 하는데 경고에 에러에 프로젝트가 문제가 있다고 난리다.

당황하지 않고 프로젝트 구조를 바꾸어주어야 한다.

src 디렉토리 옮기기

프로젝트 바로 아래에 있는 src 디렉토리를 방금 만든 곳으로 이동을 한다.

mv 명령을 써도 되고 git으로 소스코드를 관리한다면 git mv 명령으로 옮긴다.

git mv src xxx-api

자식에 있는 build.gradle.kts 배너 우측에 Load Script Configurations 라고 뜨지만 이걸 누른다고 해결되지는 않는다.

Load Script Configurations

최상위 build.gradle.kts 수정

plugins

이것 저것 테스트를 해보니 모듈에서 새로운 플러그인 정의는 못하고 최상위 build.gradle.kts 에서 정의한 것에 대한 사용은 가능했다.

최상의 플러그인들을 false로 적용한다.

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
	id("org.springframework.boot") version "2.5.0" apply false
	id("io.spring.dependency-management") version "1.0.11.RELEASE" apply false
	kotlin("jvm") version "1.4.32" apply false
	kotlin("plugin.spring") version "1.4.32" apply false
	groovy
}

뒤에 apply false 만 붙여주면 된다.

변경 전(왼쪽)과 후 (오른쪽)

나중에 안 것이지만 groovy 플러그인에는 apply false를 붙이면 에러가 발생했다!

allprojects 블록 추가

하위 모듈에 공통으로 적용할 값들을 설정한다.

group, version, tasks.withType, 등이 있다.

group은 같이 가져가고 version 은 필요에 따라 배포 단위별로 관리하는 것이 좋다. (마틴 밥이 외치지 않는가?!)

다만 현재는 배포 단위가 1개라 같이 가져가는 것으로 설정했다.

java.sourceCompatibility = JavaVersion.VERSION_11

allprojects {
	group = "com.tistory.namocom"
	version = "0.0.3-SNAPSHOT"

	tasks.withType<KotlinCompile> {
		kotlinOptions {
			freeCompilerArgs = listOf("-Xjsr305=strict")
			jvmTarget = "11"
		}
	}

	tasks.withType<Test> {
		useJUnitPlatform()
	}
}

나중에 알았지만 java.sourceCompatibility = JavaVersion.VERSION_11 부분이 allprojects 안에 있으면 동작을 하지 않았다.

 

subprojects 블록 추가

하위 모듈들에 대한 공통적인 설정을 준다.

리포지토리와 스프링 의존성 관리에 대해 해준다.

subprojects {
    repositories {
        mavenCentral()
    }
}

모듈에 있는 build.gradle.kt 의 아래 부분은 없어져도 된다.

repositories {
    mavenCentral()
}

dependencies 이동

새로 만든 모듈로 이동을 한다.

만약 gradle.properties 에 있는 값이 있다면 같이 이동 혹은 복사를 해주어야 한다.

 

이 상태가 되어도 아직 빨갛게 보였다.

 

의외로 groovy 플러그인의 false 적용에 문제가 있었나보다.

 ./gradlew task
Starting a Gradle Daemon, 1 incompatible and 7 stopped Daemons could not be reused, use --status for details

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/namo/git/xxx-api/build.gradle.kts' line: 9

* What went wrong:
Error resolving plugin [id: 'org.gradle.groovy', apply: false]
> Plugin 'org.gradle.groovy' is a core Gradle plugin, which is already on the classpath. Requesting it with the 'apply false' option is a no-op.

 

New Module - core

api 모듈처럼 새로운 모듈을 만든다.

plugins 의 버전이 붙어있는 부분은 지운다.

kotlin("jvm") version "1.5.10"

kotlin("jvm")

아래 부분은 지운다.

group = "com.tistory.namocom"
version = "0.0.3-SNAPSHOT"

repositories {
    mavenCentral()
}

 

의존성을 추가한다.

의존을 할 build.gradle.kt 에 implmentation 을 추가한다.

dependencies {
    implementation(project(":xxx-core"))

이후 core 부분의 코드를 옮긴다.

나는 모듈을 만드는 작업전에 package를 core로 분리해 놓았다.

 

buildJar 부분은 false로 바꾼다. (core는 부트 프로젝트가 아니라 N/A)

 

참고 사이트:

https://kotlindays.com/2019/12/06/multi-module-spring-boot-in-kotlin-dsl/index.html

 

How to Create a Multi-Module Spring Boot Project using Gradle’s Kotlin DSL

An example of using the Gradle Kotlin DSL for a multi-module Spring project

kotlindays.com