Kotlin DSL, Gradle 빌드 기본 언어 채택… 왜 Kotlin DSL일까?

안녕하세요.
저는 IMQA 개발팀 SDK 파트에서 Android SDK를 개발하는 김성윤 연구원입니다.

최근 구글이 Android의 새로운 빌드 언어로 Kotlin DSL을 채택했습니다. 그래서 이번 글을 통해 구글이 채택한 Kotlin DSL이 무엇인지, 어떤 장점이 있는지 공유하고자 합니다.

Kotlin DSL란?

“Thanks to the collaborative effort between JetBrains, Google and Gradle, the Kotlin DSL reached the next level of maturity and is now an even more efficient and user-friendly tool for developers to use in their projects.” ~ The Gradle team

“JetBrains, Google 및 Gradle 간의 협업 덕분에 Kotlin DSL은 한 단계 더 발전했고 이제 개발자들이 프로젝트에 사용할 수 있는 훨씬 더 효율적이고 사용자 친화적인 도구로 거듭났습니다.” ~ Gradle 팀

Kotlin DSL을 알아보기에 앞서 DSL은 무엇일까요? DSL은 도메인 특정 언어(Domain Specific Language)로 특정 도메인에 국한해 사용됩니다.

예를 들어 단팥빵을 만들기 위해 단팥빵 레시피를 보며 빵을 만든다고 했을 때, 이 단팥빵 레시피로 크림빵을 만들 수 있을까요? 이 단팥빵 레시피는 오로지 단팥빵을 만들기 위한 레시피이므로 다른 빵은 만들 수 없습니다.

즉, 이 단팥빵 레시피는 특정 도메인(단팥빵을 만들기 위함)에 대한 언어로 되어 있고, 해당 도메인(단팥빵을 만들기 위함)에서만 의미가 있습니다. 정리하자면 단팥빵을 만들기 위한 레시피는 DSL이고 해당 DSL을 따라 단팥빵만 만들 수 있습니다.

이처럼 특정 도메인에 대한 목적으로 만들어진 언어를 DSL이라고 할 수 있습니다. 또한 DSL의 반대 개념으로는 일반 목적 언어(General Purpose Language)가 있습니다. GPL은 다양한 문제 및 도메인을 다룰 수 있는 범용적인 언어이며 다양한 종류의 소프트웨어 개발에 사용됩니다. (C, C++, Java, Python, Ruby, JavaScript, Kotlin 등이 GPL입니다.)

DSL과 GPL 차이

DSL GPL
목적 특정 도메인 또는 문제 영역 해결 다양한 문제와 도메인을 다룸
표현력 특정 도메인에 특화된 표현력 일반적인 프로그래밍 표현력
범용성 한정된 범위 내에서 사용 다양한 분야에서 사용
확장성 도메인에 특화된 기능 확장 가능 일반적인 기능 확장 가능
문법 독립적인 문법 사용 표준적인 문법 사용
도구 지원 도구 및 라이브러리 제한 양한 도구 및 라이브러리 지원
학습 곡선 도메인 전문성 필요 일반적인 프로그래밍 학습 곡선
가독성 도메인에 특화된 가독성 일반적인 가독성
개발자 역량 도메인 지식이 필요함 범용 프로그래밍 역량 필요

그렇다면 Kotlin DSL은 무엇일까요? 말 그대로 Kotlin DSL은 Kotlin으로 작성된 도메인 특화 언어(DSL)입니다.  Kotlin DSL은 Gradle, Android 등 여러 영역에서 사용되며 정적 타입 검사, 람다 함수, 확장 함수 등과 같은 Kotlin 언어의 장점을 살려 직관적인 DSL을 구축할 수 있게 해줍니다.

그럼, 이제 Groovy DSL과 Kotlin DSL의 예시 코드를 통해 차이를 확인해 볼까요? 아래는 안드로이드 앱 개발을 하게 되면 무조건 보게 되는 Groovy DSL(build.gradle)입니다.

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.myapp"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    // 추가적인 설정
    // ...
}

dependencies {
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    // 다른 종속성 추가
    // ...
}

위에 작성한 Groovy DSL을 Kotlin DSL로 변경하면 어떻게 될까요?

android {
    compileSdkVersion(30)
    buildToolsVersion("30.0.3")

    defaultConfig {
        applicationId = "com.example.myapp"
        minSdkVersion(21)
        targetSdkVersion(30)
        versionCode = 1
        versionName = "1.0"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }

    // 추가적인 설정
    // ...
}

dependencies {
    implementation("androidx.appcompat:appcompat:1.3.0")
    implementation("com.google.android.material:material:1.4.0")
    // 다른 종속성 추가
    // ...
}

안드로이드를 예로 들어 Kotlin DSL에 대해 보여드렸는데요. Kotlin DSL는 안드로이드 개발뿐만 아니라 Android 개발, Gradle 빌드, 웹 개발, 테스트와 같은 다양한 도메인에서 활용될 수 있습니다.

왜 Kotlin DSL인가?

다른 DSL을 사용해도 괜찮을 것 같은데.. 왜 굳이 Kotlin DSL을 사용할까요? 꼭 Kotlin DSL을 사용해야 하는 것은 아닙니다. 하지만 Kotlin DSL은 다른 DSL의 비해서 특정 도메인이나 작업에 대해 보다 표현력이 뛰어나고 유연한 코드를 작성할 수 있도록 도와주는 도구입니다.

그럼, Kotlin DSL을 사용했을 때, 어떤 효과를 볼 수 있는지 Kotlin DSL의 장단점에 대해 간단히 살펴볼까요?

Kotlin DSL 장점

  • 간결하고 가독성이 높은 코드
    Kotlin은 간결하고 표현력이 뛰어난 프로그래밍 언어입니다. Kotlin DSL을 사용하면 이러한 Kotlin의 장점을 살려 더욱 간결하고 가독성이 높은 코드를 작성할 수 있게 해줍니다.
  • 타입 안전성
    Kotlin은 정적 타입 언어이므로 컴파일 시점에서 오류를 잡을 수 있습니다. Kotlin DSL을 사용하면 컴파일러의 검사를 통해 더욱 안정적인 코드를 작성할 수 있습니다.
  • IDE 지원
    Kotlin은 안드로이드 스튜디오를 비롯한 다양한 IDE에서 지원을 하고 있습니다. Kotlin DSL을 사용하면 IDE에서 DSL의 구문 강조 표시, 자동 완성, 코드 내비게이션 등의 기능을 활용할 수 있으며, 개발 생산성을 향상할 수 있습니다.
  • 유연성과 확장성
    Kotlin은 객체 지향 프로그래밍과 함수형 프로그래밍을 모두 지원하므로, Kotlin DSL을 작성할 때 유연하고 확장 가능한 구조를 구성할 수 있습니다. 이를 통해 DSL을 확장하거나 커스터마이징하는 데 용이하며, 도메인의 요구사항에 맞게 코드를 구성할 수 있습니다.
  • Kotlin의 기능 활용
    Kotlin은 람다식, 확장 함수, Null 안전성 등 다양한 특징과 기능을 제공합니다. Kotlin DSL을 사용하면 이러한 기능을 활용하여 DSL를 보다 효율적으로 작성할 수 있습니다.

말은 Kotlin DSL의 장점이라고 했지만, 대략적인 장점들은 다 Kotlin 언어에 대한 장점입니다. 그럼 어떤 단점이 있을까요?

Kotlin DSL 단점

  • 학습 곡선
    Kotlin DSL은 Kotlin 언어의 특성과 문법을 이해해야 합니다. 따라서 Kotlin 언어에 익숙하지 않은 개발자들에게는 학습 곡선이 존재할 수 있습니다.
  • 생산성 저하
    Kotlin DSL은 표현력이 높고 강력한 기능을 제공하지만, 초기 구현 및 설정에는 추가적인 작업이 필요할 수 있습니다. 기존의 설정 방식이나 프레임워크에 익숙한 개발자들에게는 처음에는 생산성 저하가 있을 수 있습니다.
  • 제한된 확장성
    Kotlin DSL은 Kotlin 언어의 기능과 제한적인 범위 내에서 확장이 가능합니다. 하지만 특정한 요구사항이나 도메인에 따라 확장이 어려울 수도 있습니다. 이는 Kotlin 언어의 한계이거나 DSL 설계의 한계로 인해 발생할 수 있습니다.

Kotlin DSL은 이런 장∙단점을 가졌지만, 모든 프로젝트에 Kotlin DSL을 사용할 수는 없습니다. Kotlin DSL을 사용할지의 대한 여부는 프로젝트의 특정 상황과 요구 사항에 따라 결정이 되어야 합니다.

Kotlin DSL vs Groovy DSL

Kotlin DSL과 Groovy는 둘 다 강력한 도구로서 DSL을 구축하는 데 사용될 수 있습니다. 각각의 언어는 다음과 같은 차이가 있습니다. 다음은 Kotlin DSL과 Groovy DSL의 차이를 비교한 표입니다.

Kotlin DSL Groovy DSL
언어 Kotlin 언어 사용 Groovy 언어 사용
문법 정적 타입, 람다식, 확장 함수 등의 Kotlin 문법 동적 타입, 클로저, 메소드 체인 등의 Groovy 문법
타입 안정성 정적 타입으로 타입 안전성 보장 동적 타입으로 타입 안전성 제한적
확장성 Kotlin 언어의 기능을 활용한 확장성 Groovy 언어의 기능을 활용한 확장성
가독성 Kotlin 표현력을 활용한 가독성 Groovy 표현력을 활용한 가독성
IDE 지원 안드로이드 스튜디오 등 Kotlin IDE에서 지원 IntelliJ IDEA 등 Groovy IDE에서 지원
도구 및 라이브러리 Kotlin과 Gradle 통합 지원 Groovy와 Gradle 통합 지원
사용 범위 주로 안드로이드 및 Kotlin 기반 프로젝트 다양한 프로젝트 및 스크립트에 사용 가능
학습 곡선 Kotlin 언어에 익숙해야 함 Groovy 언어에 익숙해야 함

위의 표에서 볼 수 있듯이, Kotlin DSL과 Groovy DSL은 언어적인 차이와 기능적인 차이를 가지고 있습니다. Kotlin DSL은 Kotlin 언어를 사용하여 정적 타입과 풍부한 문법 기능을 활용하며, 안드로이드 개발 및 Kotlin 기반 프로젝트에 주로 사용됩니다.

Groovy DSL은 Groovy 언어를 사용하여 동적 타입과 클로저, 메소드 체인 등의 기능을 활용하며, 다양한 프로젝트 및 스크립트에 활용됩니다. 선택은 프로젝트의 요구사항과 개발자의 선호도에 따라 달라집니다.

Groovy DSL로 작성된 IMQA 설정을 Kotlin DSL 바꿔보자

IMQA로 Android 앱 성능 모니터링을 하기 위해선 build.gradle에 특정 설정을 진행해 주어야 합니다. 현재는 docs 사이트에 Groovy DSL 설정으로만 가이드가 되어 있는데요. 그럼, 이 설정을 Kotlin DSL로 변경해 볼까요?

Groovy DSL 로 작성된 IMQA 설정

dependencies {
    // dependencies 추가
       implementation 'io.imqa:imqa-core:2.27.1'
       implementation 'io.imqa:imqa-mpm-client:2.27.6'
       implementation 'io.imqa:imqa-crash-client:2.27.1'
    } 
} 

io.imqa.IMQAPlugin imqaPlugin = new io.imqa.IMQAPlugin()
imqaPlugin.init(project)
new io.imqa.injector.GJavacAction(project.name).setConfiguration(project)
android.applicationVariants.all { variant ->
    variant.javaCompile.doLast { task ->
        new io.imqa.injector.CompileAction(
                io.imqa.injector.util.BuildOption.BUILD_LOCATION_TYPE.javacClasses,
                project.name,
                io.imqa.injector.GJavacAction.convertBuildType(variant.getBuildType()),
                io.imqa.injector.GJavacAction.makeFlavor(variant.getBuildType().name,
                        variant)
        ).execute(task)
    }
}

Kotlin DSL로 변경한 IMQA 설정

dependencies {
    // dependencies 추가
    implementation("io.imqa:imqa-core:2.27.1")
    implementation("io.imqa:imqa-mpm-client:2.27.6")
    implementation("io.imqa:imqa-crash-client:2.27.1")
}

val imqaPlugin = io.imqa.IMQAPlugin()
imqaPlugin.init(project)

android.applicationVariants.all { variant ->
    variant.javaCompile.doLast { task ->
        val compileAction = io.imqa.injector.CompileAction(
            io.imqa.injector.util.BuildOption.BUILD_LOCATION_TYPE.javacClasses,
            project.name,
            io.imqa.injector.GJavacAction.convertBuildType(variant.buildType),
            io.imqa.injector.GJavacAction.makeFlavor(variant.buildType.name, variant)
        )
        compileAction.execute(task)
    }
}

드라마틱하게 변경된 부분은 없지만(설정의 양이 줄지는 않아요..ㅠㅠ) 문법을 통해 좀 더 간결한 코드를 작성할 수 있습니다. 무엇보다 Kotlin DSL을 사용하면 오타나 잘못된 메서드 호출을 컴파일 단계에서 확인할 수 있습니다. 이는 코드의 안정성을 향상시키고 런타임 오류를 줄여줍니다.

Groovy DSL로 작성된 build.gradle에서 applications를 참조하려 했을 때 이런 식으로 작성하면 마치 문제없는 것처럼 경고를 보여주지 않지만, 빌드를 진행하게 되면 아래와 같이 오류가 발생하게 됩니다.

하지만 Kotlin DSL에서는 이런 식으로 잘못된 참조를 하게 될 경우 바로 빨간색 경고로 코드가 잘못됐다는 것을 알려줍니다.

정말 간단한 예제로 보여드렸지만, 이런한 컴파일 타임 검사 기능은 Android 앱 개발에 있어서 중요하다고 생각이 드는데요. 오타나 참조 오류로 인해 빌드를 다시 해야 하는 상황을 Kotlin DSL을 적용하여 해결할 수 있습니다. (Android 앱 개발자에게 빌드 시간은 정말..)

기존 Gradle 빌드를 Groovy에서 Kotlin DSL로 마이그레이션 할 수 있게 마이그레이션 가이드 문서도 친절하게 설명되어 있으니 한 번 읽어 보시는 것도 좋을 것 같습니다.

마치며

저도 아직은 Kotlin DSL을 많이 접해보지 않았지만, 이번 글을 작성하면서 IMQA SDK에 작성된 groovy DSL 코드를 Kotlin DSL로 마이그레이션 하여 간결하고 가독성이 높은 코드로 리펙토링하고 싶은 생각이 바로 들었습니다.

구글에서 이 Kotlin DSL을 Android 앱용 Gradle 빌드 파일의 기본 스크립트로 사용하겠다고 밝힌 시점에서, 변화가 빠른 Android 생태계를 따라가기 위해서라도 저는 지금부터라도 적극적으로 Kotlin DSL을 활용할 수 있도록 노력해야 할 것 같습니다!

그럼, 이번 포스팅이 Android App 개발자분들께 도움이 됐길 바라며, 이만 물러가겠습니다.
감사합니다.


IMQA와 관련하여 궁금하신 사항은 언제든 아래 연락처로 문의해 주시면 상세히 안내해 드리겠습니다. 이미지를 클릭하시면 1:1 채팅 창으로 이동합니다.

  • 02-6395-7730
  • support@imqa.io