많은 개발자들이 개발 언어로 Kotlin을 사용하고 있습니다. 본 글에서 Kotlin 이란 어떤 언어이며, 어떤 장점이 있어 많은 개발자들이 사용하는지 알아보겠습니다.
Kotlin은 JetBrains 사에서 2011년 처음 공개된 후 2016년 정식 출시된 오픈소스 프로그래밍 언어입니다. JVM 기반의 언어이며, Java와 유사하지만 훨씬 더 간결한 문법과 다양한 기능을 제공합니다. Java와 100% 호환이 가능한데 이는 Java 기반 프로그램이 모두 Kotlin으로 개발이 가능하다는 의미가 됩니다. 어떻게 100% 호환이 가능한 걸까요? 이를 알아보기 위해 JVM에서 Kotlin 언어가 어떻게 빌드 되는지 보겠습니다.
Kotlin은 JVM 상에서 동작하기 때문에 빌드 되는 과정이 Java와 유사합니다.
이를 그림으로 표현하면 다음과 같습니다.
Kotlin 컴파일러와 Java 컴파일러 모두 Java 바이트코드인 class 파일로 변환하게 됩니다. 이는 Kotlin이 컴파일 되어 생성된 바이트 코드를 디컴파일 해 Java 코드를 확인할 수도 있다는 의미가 되는데요. 실제로 안드로이드 스튜디오와 같은 IDE에선 Kotlin으로 작성된 코드를 디컴파일 해 Java 코드로 보여주는 기능을 제공합니다.
Kotlin은 빌드 되면서 Kotlin 컴파일러를 거쳐 Java 바이트코드를 생성하고, JVM을 통해 기계어로 변환 되는 것을 알 수 있었습니다. Kotlin 컴파일러가 Java 바이트 코드를 생성하기 때문에 다시 Java로 디컴파일이 가능하며, Java와 100% 호환되는 것을 알 수 있습니다.
Kotlin 공식 홈페이지에서 코틀린을 다음과 같이 이야기하고 있습니다.
왜 이렇게 이야기하는 것일까요? Java는 처음 발표된 지 무려 20년이 지난 오래된 언어입니다. 처음 공개된 이후부터 지금까지 사용하면서 많은 문제점들이 발견되었고, 이를 수정하고 개선된 신버전들이 계속 출시되어 어느새 17 버전까지 나오게 되었습니다. Kotlin은 Java 언어가 처음 설계되었을 때부터 가진 많은 문제점들을 고려해서 언어를 설계했고 개발자가 더 쉽고 편리하게 작성할 수 있게 설계되었습니다. 그럼 Kotlin이 어떤 특징과 장점이 있는지 한 번 살펴보겠습니다.
정적 타입의 언어
타입 추론
간결한 언어
//Kotlin
data class Person(val name: String, val age: Int)
//Java
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
public String toString() {
return "Person" + "name = " + name + "age = " + age;
}
}
Java를 이용할 경우 불필요하게 추가되던 boilerplate code들이 Kotlin의 data class를 사용하니 훨씬 간결하고 편리하게 작성되는 것을 볼 수 있습니다. 이처럼 Kotlin은 동일한 코드도 더 간결하게 작성할 수 있게 도와줍니다.Null safe 언어
코루틴
Kotlin은 비동기 처리와 효과적인 동시성 작업을 위해 코루틴이라는 아주 강력한 기능을 제공합니다. api 호출, db connect와 같은 I/O 작업은 비동기로 수행되는데요. 기존에는 비동기 처리를 위해 Callback을 사용하거나 RxJava와 같은 외부 플러그인을 이용해 비동기 로직을 처리했습니다.
Callback을 사용할 경우 콜백 지옥이라고 할 정도로 코드의 depth가 깊어지고 RxJava를 사용할 경우 직관적이지 않은 코드와 불필요한 Stream 작업이 발생됩니다.
코루틴을 사용할 경우 순차적인 코드 작성이 가능해 가독성을 높일 뿐만 아니라, 스레드를 더 효율적으로 사용해 성능도 좋아질 수 있습니다. 간단하게 코루틴으로 코드를 작성할 경우 Callback과 비교해 코드가 얼마나 가독성이 좋아지는지 보겠습니다.
callback을 사용하는 경우 api 호출 성공과 실패에 대한 callback 메서드를 전달해야 합니다. 그리고 api 응답을 성공적으로 수신 한 경우 다른 api를 호출하면서 다시 성공과 실패에 대한 callback을 전달하게 되는데요. 이 과정에서 코드 depth가 깊어지면서 가독성이 상당히 안 좋아지는 것을 볼 수 있습니다.
fun upload() { //callback
loading.postValue(true)
api.prepareUpload().enqueue(object : Callback<PrepareUploadResponse>{
override fun onResponse(call: Call<PrepareUploadResponse>, response: Response<PrepareUploadResponse>) {
if (response.isSuccessful) {
val path = response.body()
api.upload(path).enqueue(
object : Callback<UploadResponse>{
override fun onResponse(call: Call<UploadResponse>, response: Response<UploadResponse>) {
if (response.isSuccessful) {
loading.postValue(false)
successToast.postValue(true)
}
}
override fun onFailure(call: Call<PrepareUploadResponse>, t: Throwable) {
loading.postValue(false)
Log.d("")
}
}
)
}
}
override fun onFailure(call: Call<PrepareUploadResponse>, t: Throwable) {
loading.postValue(false)
Log.d("")
}
})
}
fun upload() { //coroutines
try {
val path = api.prepareUpload()
val response = api.upload(path)
loding.postValue(false)
successToast.postValue(true)
} catch (e: Exception) {
loading.postValue(false)
Log.d("")
}
}
이에 반해 코루틴으로 작성된 코드를 살펴보면 순차적인 코드 작성이 가능해 훨씬 가독성이 좋은 것을 알 수 있습니다.(물론 위 코드 그대로 동작하진 않습니다. 순차적인 코드 작성이 가능한 점을 나타내기 위한 예시일 뿐입니다.) 단순히 가독성을 높여줄 뿐 아니라 코루틴은 suspend 함수를 이용해 thread를 더 효율적으로 사용할 수 있습니다. 코루틴의 동작에 대해 더 알아보고 싶다면 아래 링크를 확인해 보세요.
추가로 Kotlin 공식 홈페이지에 가보면 함수형 프로그래밍 지원, 객체 지향 프로그래밍 지원, 멀티 플랫폼 지원 등 본 글에서 설명하지 않은 Kotlin이 제공하는 다양한 기능들을 확인해 볼 수 있습니다.
Kotlin을 사용하는 이유에 대해서 알아보기 위해 Kotlin이 어떻게 빌드되고 특징과 장점은 어떤 것들이 있는지 알아보았습니다. Java언어와의 100% 상호운용성, 간결한 언어, Null Safe 등 Kotlin을 사용하게 될 경우 얻을 수 있는 많은 이점들이 있는것을 알 수 있었는데요. 이러한 장점들 덕분에 60% 이상의 안드로이드 개발자들이 Kotlin 언어를 사용하고 있습니다. 또한 안드로이드 코드 스니펫도 Kotlin으로 먼저 작성되고 안드로이드 스튜디오 내부에서 Java to Kotlin 변환을 지원해 주고 있습니다. 아직 Kotlin을 접해본 적 없다면, Kotlin에 대해서 한 번 공부해 보는 게 어떨까요?