운 좋게도 회사에서 Kotlin을 도입한 지 1년여가 되었습니다.
지난 1년 간을 되돌아 보며 Kotlin을 사용해 본 경험을 함께 나눠 볼까 합니다.
카카오헤어샵의 Backend 시스템은 Java 90%, Python 5%, Node.js 5%의 비중으로 구축되어 있습니다. 그중에서 주요 비즈니스는 Java로 되어 있습니다. 그래서 새로운 언어를 선택함에 있어서 JVM 위에서 동작하는 언어를 택하는 것이 호환성 측면에서 유리하다고 판단했습니다.
JVM 위에서 동작하는 언어는 Kotlin, Scala, Groovy, Clojure가 있는데 아래 3가지 이유로 Kotlin을 선택했습니다.
Kotlin은 정적 타입 언어입니다. 그렇기 때문에 컴파일 타임에 변수의 타입을 체크할 수 있습니다. 동적 타입 언어에서 발생할 수 있는 런타임 오류를 어느 정도 예방할 수 있습니다. 또 Kotlin은 NullPointException을 컴파일 단계에서 예방할 수 있습니다.
Kotlin은 Learning curve가 완만합니다. 자바 개발자라면 1주일이면 기본적인 문법을 익힐 수 있습니다. 그리고 Jetbrain 사에서 만든 언어이기 때문에 Intellij IDEA에서 강력한 성능을 발휘합니다. 간단한 예로 Java 소스 코드를 Kotln 파일에 ‘붙여 넣기’ 하면 IDEA가 자동으로 Kotlin으로 변환해줍니다.
Kotlin은 간결한 언어입니다. 얼마나 간단한 지 아래 소스를 통해 확인해 보시죠.
data class Person(val name: String)
위 Kotlin 클래스를 Java로 개발하면 아래와 같습니다.
public class Person {
private String name;
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
// toString()
// eqauls()
// hashCode()
}
책 중에 Kotlin in Action을 추천합니다. 내용도 알차고 번역도 딱히 흠잡을 곳이 없습니다.
Jetbrain이 공식 제공하는 KOANS는 온라인으로 Kotlin을 실습할 수 있는 유용한 사이트입니다. 특히 순서대로 문제를 풀어가다 보면 Syntax과 Idioms에 대해서 자연스럽게 이해할 수 있습니다.
Java는 int, long 같은 Primitive Type이 있고 Integer, Long과 같은 Wrapper Type도 있습니다. 그렇다보니 개발자의 성향에 따라 2가지가 혼재될 수 있습니다. 문제는 Wrapper Type의 경우 NullPointException(NPE)이 발생할 소지가 있다는 것입니다.
Long num = null;
int i = num.intValue();
위 소스 코드는 Compile Error가 나지 않고 Runtime 예외가 발생합니다. 그렇게 때문에 곤욕스러운 경험을 하게 될 수도 있습니다.
반면에 Kotlin은 오로지 Wrapper Type만 사용할 수 있습니다. 그래서 초기값이 Null 이기 때문에 발생하는 Runtime 예외를 피할 수 있습니다.
개인적으로 생각하는 Kotlin의 가장 큰 장점은 Null이 될 수 있는 타입이 있다는 것입니다. 아래 Kotlin 소스 코드를 보시겠습니다.
val x: String? = null
var y: String
변수 x는 Null이 될 수 있는 타입입니다. 그리고 변수 y는 Null 될 수 없는 타입니다. 이렇게 타입을 정의하게 되면 이후에 작성하는 소스 코드의 형태가 달라지게 됩니다.
문자열의 길이를 출력하는 예제를 보시겠습니다.
print(x?.length)
print(y.length)
x는 ?. 연산자를 쓰고 y는 . 연산자를 씁니다. 그렇지 않으면 Compile Error가 납니다.
Compile 단계에서 NPE를 잡아주기 때문에 Runtime에 NPE가 발생할 가능성이 매우 줄어들게 됩니다.
Kotlin은 현장에서 사용하는 관용 표현(Idioms)들이 언어 자체에 내재화 되어 있습니다.
“상속을 위한 설계와 문서를 갖추지 않았다면 상속을 금지하라.”라는 조슈아 블로크의 조언에 따라 클래스와 메쏘드는 기존적으로 public final 입니다.
// Java
public final class Person{ }
// Kotlin
class Person
상속을 허용하려면 open 변경자를 붙여야 합니다.
그리고 일반적으로 많이 사용하게 되는 Singleton 객체의 경우 object 키워드로 쉽게 정의할 수 있습니다.
object Payroll
또 equals, hashCode, toString 등의 메쏘드를 한방에 구현해주는 data 키워드도 있습니다.
data class Person(val name: String, val age: Int)
객체 생성도 더 이상 new 키워드를 사용하지 않습니다.
val peter = Person("peter")
Java에서 유용하게 쓰이는 lambda가 Kotlin에서는 좀 더 심플해졌습니다.
아래 3개의 라인이 모두 동일한 기능을 수행합니다.
people.maxBy(Person::age)
people.maxBy { p -> p.age }
people.maxBy { it.age }
Java의 유용한 라이브러리인 Lombok https://projectlombok.org/ 을 Kotlin에서 사용할 수 없습니다. 특히 @Builder를 사용할 수 없는 것이 뼈 아픕니다.
대신 Kotlin은 생성자에 이름 있는 인자가 있어서 @Builder를 대신할 수 있습니다.
Person(name = "Peter", age = 16)
저는 새로운 언어나 플랫폼에 보수적인 편입니다. 개발 업무의 특성상 새로운 프로젝트보다 유지보수에 투입하는 시간이 많기 때문에 그렇습니다. 또 누군가의 주도로 새로운 것을 시도했는데 그 사람이 퇴사하게 되어 시스템이 방치되는 것을 본 경험이 있기 때문에 그럴지도 모르겠습니다.하지만 새로운 것을 시도하지 않으면 도태된다는 것을 잘 알고 있습니다.
그래서 이번에 Kotlin을 도입하면서는 몇 가지 노력을 함께 하려고 합니다.
옆 개발자도 Kotlin 하자고 설득해서 내가 퇴사해도 이 시스템이 유지 보수될 수 있도록 합니다.
Kotlin 세미나 및 스터디를 매월 1회 이상 진행해서 개발자들의 관심을 유도합니다.
혹시 Kotlin 도입에 망설이는 분이 계시다면 겁 먹지 마시고 도전하시길 바랍니다.