ksp는 출시한 지 몇 년 된 것으로 알고 있었는데 라이브러리를 사용하고 있는 내가 kapt와 ksp에 대한 차이를 명확하게 모르고 있다는 것을 인지하고, 그것에 대해 알아보기 위해 공부를 해야겠다고 느꼈다.
따라서,
kapt와 ksp에 대해 알아보고,
사용하고 있는 라이브러리를 마이그레이션 하는 방법,
그리고 어떠한 차이가 있는지에 대해 알아보고자 한다.
우선 kapt가 무엇인지 알아보자.
kapt란,
Kotlin Annotation Processing Tool의 약자로 자바의 어노테이션 프로세서를 코틀린에서 사용할 수 있게 해주는 도구라고 한다.
kapt는 자바에서 사용되는 어노테이션 프로세서를 코틀린에서 사용할 수 있게 해 준다는데, 이게 무슨 말인가 싶을 것이다.
간단하게 생각하면@Entity와같이 작성한 어노테이션을 코틀린에서 사용할 수 있게 만들어준다는 것인데
// Room - kapt
@Entity
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "name") val name: String
)
Room에서 이렇게 선언된 어노테이션들이 kapt를 통해 적용되는 것이다.
이렇게 선언된 것들이 실제 처리 될 때는 다음과 같은 순서를 통해 진행된다.
- Java Stub 생성
- Java 어노테이션 프로세서 실행
- 자바 코드 생성
- 코틀린 코드로 변환
즉, 자바로 만들어진 코드를 코틀린으로 변환하는 과정에 추가적인 프로세스가 필요하게 되며, 이러한 작업을 해준다는 것이다.
이러한 JAVA로 만들어진 어노테이션을 코틀린으로 사용하기 위한 것이 kapt라는 것이라고 간단하게 개념을 알게 되었으니
다음으로 ksp에 대해 알아보도록 하자.
ksp란,
Kotlin Symbol Processing의 약자로, 코틀린 전용 어노테이션 프로세서다.
KSP는 코틀린 전용이기 때문에 kapt와 다르게 자바 리플렉션 대신 코틀린 컴파일러 플러그인을 직접 사용한다.
ksp로 사용하면 무엇이 다른가 한번 간단한 예제를 확인해 보도록 하자.
// Room - ksp
@Entity
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "name") val name: String
)
차이가 있을 것이라고 생각했는데, 완전히 동일한 코드로 보인다.
하지만, 이름에서 알 수 있다시피 코틀린 전용 어노테이션이기 때문에 실행되는 순서에서 차이가 있다.
- 코틀린으로 어노테이션 처리
- 코드 생성
아주 간단하게 처리가 된다.
kapt와 ksp의 가장 큰 차이점은 역시 기본적으로 사용되는 언어가 자바와 코틀린이기 때문에 발생하는 것으로 보인다.
둘 다 동일한 어노테이션을 처리하기 위한 것이지만, 현재 코틀린을 사용하여 개발을 하고 있기 때문에 자바로 되어있는 코드들을 코틀린으로 컨버팅 하는 과정이 추가되어야 하기 때문에 발생하는 차이로 보인다.
그렇다면 나중에 나온, 코틀린 기반의 ksp가 kapt에 비해서 상당히 좋아 보이는데,
kapt와 ksp에 대해 현재 장단점을 한번 확인해 보자.
Kapt의 장점.
- 안정성
- 많은 라이브러리 지원
- 자바 코드와의 호환성
Kapt의 단점.
- ksp에 비해 느린 처리 속도
- 많은 메모리 사용
- 복잡한 처리 과정
Ksp의 장점.
- Kapt에 비해 빠른 처리 속도
- 낮은 메모리
- 코틀린 특화
Ksp의 단점.
- ksp로 마이그레이션 된 라이브러리가 비교적 많지 않음.
- 일부 복잡한 타입 정보의 손실이 일어남.
위의 내용은 직접 확인했다기보다는 검색을 통해 알게 된 사실들이다.
하지만 여기서 Kapt의 장단점은 Java이기 때문에 발생하는 것들이었고, ksp 또한 Kotlin이기 때문에 생기는 장단점이라고 보인다.
이러한 장단점 중, 디테일한 부분은 둘째치고 필자가 가장 중요하게 생각하는 부분은 피부로 느낄 수 있는 처리 속도의 차이가 가장 중요하다고 생각이 되었다.
그에 따라, 현재 사용 중인 kapt를 ksp로 마이그레이션 한 후 빌드 타임과 메모리의 차이를 비교해 보도록 하겠다.
그러기 위해서는 우선 사용 중인 kapt를 ksp로 변경을 해야 한다.
필자가 예제를 만들 때 항상 사용하는 프로젝트에서 Room을 사용하는 부분에 kapt를 사용하고 있었기 때문에 이것을 간단하게 ksp로 마이그레이션 해보겠다.
우선 현재 필자가 예제 프로젝트에서 사용하고 있는 kotlin 버전은 1.9.0 이기 때문에, 이것과 맞는 버전의 KSP를 찾아서 적용한다.
versions.gradle로 버전을 별도로 관리하고 있기 때문에, 해당 부분에 코드를 추가해 주도록 한다.
다음으로는 프로젝트 레벨의 gradle에 ksp에 대한 플러그인을 설정해 주도록 한다.
buildscript {
apply from: 'version.gradle'
dependencies {
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$ksp_version"
}
}
우선 이렇게 설정한 다음, Android Studio에서 Invalidate Caches / Restart를 실행하여 캐시를 날린 후 재 실행하도록 한다.
해당 작업을 안 해도 상관은 없지만 필자는 빌드하는데 오류가 발생했었고, Invalidate Caches / Restart를 실행한 후 리빌딩을 수행하니 정상적으로 빌드가 되었다.
빌드가 정상적으로 되었다면,
kapt로 선언된 부분을 ksp로 변경해주기만 하면 된다.
필자는 현재 core-dependencies.gradle 파일로 room 라이브러리를 빼내어 관리하고 있지만, 일반적인 Module에서 사용하는 경우가 많을 것이라고 생각하고 data module의 gradle에 room library를 추가하고 변경해 보도록 하겠다.
기본적으로 kapt를 사용하고 있었다면
apply {
plugin('com.android.application')
plugin('org.jetbrains.kotlin.android')
plugin('kotlin-kapt')
plugin('kotlin-parcelize')
from('../version.gradle')
from('../config.gradle')
from('../core-dependencies.gradle')
}
이것과 같이 kotlin-kapt plugin을 추가해서 사용하고 있었을 것이다.
하지만 이제는 ksp를 사용해야 하므로,
plugin('com.google.devtools.ksp')
해당 플러그인을 추가해 주도록 한다.
필자는 room 밖에 사용하고 있지 않았고 room은 kapt를 ksp로 마이그레이션 되었기 때문에 kapt 플러그인은 제거했다.
그 후, kapt로 선언된 부분을 ksp로 변경해 주도록 하자.
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version"
이렇게 선언되어 있는 부분을
implementation("androidx.room:room-runtime:$room_version")
implementation("androidx.room:room-ktx:$room_version")
ksp("androidx.room:room-compiler:$room_version")
이와 같이 변경해 주도록 한다.
물론, 괄호는 없애고 원래 사용하는 것처럼 사용해도 상관없다.
아주 간단하게 kapt라고 선언된 부분을 ksp로 변경하기만 하면 된다.
이렇게 수정한 후, 빌드를 했을 때 문제가 생긴다면 아까와 같이 캐시를 날리고 재시작을 해주면 정상적으로 빌드가 될 것이다.
아주 간단하게 kapt를 ksp로 변경해 보았는데, kapt를 사용하는 모든 라이브러리를 ksp로 변경해서는 안된다.
당연하다시피 라이브러리 자체에서 kapt에서 ksp로 마이그레이션을 진행한 후, ksp를 지원하는 경우에만 이와 같이 사용할 수 있기 때문에 kapt를 ksp로 전환하고 싶다면 해당 라이브러리를 제공하는 github에 들어가서 제공 여부를 확인해 보는 것이 좋을 것이다.
자 이렇게 변경을 해보았으니, 빌드 시간이나 메모리 사용량에 대하여 차이를 비교해 보도록 하자.
필자는 빌드 시간을 찍어보거나, 프로파일러 등을 사용하여 시간이나 메모리를 확인해보려고 했으나 명령어를 통해서 이러한 사용량을 확인할 수 있었고, 지금 한창 사용하고 있는 Cursor IDE를 사용하여 이를 측정해 보도록 하였다.
그 결과는 다음과 같다.
빌드 시간의 경우
이렇게 명령어와 예측 시간의 차이를 알려주었고,
실제로 수행해 본 결과
이와 같이 빌드 시간의 차이를 알려주었다.
clean 명령어를 한 후에 빌드하는 시간이기 때문에, 실제로 사용하면서 빌드하는 시간과는 큰 차이가 있다는 부분을 고려해야 한다.
kapt를 사용하는 부분이 room 하나밖에 없었는데, 그것 하나 사용하는 것 때문에 빌드 시간이 1분이 넘게 차이가 나는 것을 직접 확인할 수 있었다.
그리고 결과는, 보통 kapt와 ksp의 속도 차이를 찾아보았을 때 ksp가 약 2배 정도 빠르다.라는 것을 볼 수 있었는데, 정말로 그에 가깝게 ksp가 빠른 것을 확인할 수 있었다.
다음으로 메모리와 같은 경우에는
다음과 같은 명령어를 통하여 분석을 진행하였고,
이러한 결과를 보여주었다.
메모리는 얼마나 효율적으로 사용이 되는지 알 수 없었는데, 결과를 보니 전반적으로 ksp가 약 30% 정도 효율적으로 메모리를 사용한다는 것을 알 수 있었다.
이렇게 정말 간단하게, kapt, ksp에 대해 알아보고 변경하는 방법에 대하여 작성해 보았다.
kapt를 ksp로 바꾸고, gradle 설정만 조금 변경해 주는 아주 간단한 작업이지만 이렇게 까지 효율적인 부분에서 차이가 클 것이라고는 생각하지 못했다.
필자가 샘플로 사용했던 프로젝트는 kapt를 하나밖에 사용하고 있지 않고, 샘플만 작성해 둔 아주 가벼운 프로젝트였음에도 불구하고 많은 효율의 차이를 볼 수 있었는데,
실제 프로젝트에서 적용한다면 얼마나 큰 차이를 보일지 정말 기대가 되는 부분이다.
시간이 된다면, 회사에서 사용 중인 라이브러리 중 ksp를 지원하는 것이 있다면 마이그레이션을 진행해 보고 속도 차이를 체감해보고 싶다.
또한,
cursor IDE를 최근에 이것저것 만져보면서 사용하고 있는데, 사용하면 사용할수록 정말 대단한 녀석이라고 생각이 든다.
직접 뭔가 찾아보고 설정하고 확인해야 하는, 귀찮고 단순한 작업들을 프롬프트 몇 줄이면 뚝딱 만들어주는 게 정말 편하고, 개발에 큰 도움을 줄 수 있는 도구라고 생각한다.
메모리 사용량, 빌드 속도 차이를 직접 확인하려고 했으면 얼마나 또 많은 부분을 찾아보고 테스트해봤어야 했을지.. 상상만 해도 끔찍하다.
Gradle밖에 변경하지 않았지만,
해당 게시글에 사용한 예제는 Github에 올려두었다.
https://github.com/HeeGyeong/ComposeSample
'Android > Gradle' 카테고리의 다른 글
[Android] toml 파일을 사용하여 Gradle을 개선해보자. (3) | 2024.12.16 |
---|---|
[Gradle] Implementation vs Api (0) | 2022.06.02 |
[Gradle] 빌드 변형 구성을 사용하여 하나의 앱을 나눠보자. (0) | 2022.05.26 |
[Gradle] Gradle 7.2 버전 대응하기. (0) | 2022.05.20 |
[Android] 공통된 Gradle Code를 빼내어 관리해보자. (0) | 2022.04.22 |