윤준서의 블로그

코틀린을 사용하는 이유?

"코틀린을 사용하는 이유가 무엇이냐?"라는 질문을 받았을 때, 나는 제대로 된 답을 하지 못했다. 물론 내가 코틀린으로 안드로이드 개발을 시작하면서 편했던 것도 있었지만, 그 자리에서 그 이유를 명확하게 설명하지 못했던 것이다.

돌아오는 길에 나는 왜 자바 대신 코틀린을 선택했는지, 그리고 그 선택이 어떻게 나의 개발 경험을 변화시켰는지 깊이 생각해보게 되었다 ✍🏻

안드로이드 개발과의 첫 만남

나는 안드로이드 개발을 시작할 때부터 코틀린을 선택했다. 처음에는 그저 최신 트렌드를 따라가는 것처럼 보였을 수 있지만, 이제 돌아보니 그 선택이 나에게 큰 도움이 되었다. 중간에 자바로 프로젝트를 진행해본 적이 있는데, 그때는 뭔가 불편함을 느꼈다. 특히 NullPointerException과의 전쟁은 정말 지치게 했다.

이전에는 그저 "코틀린이 더 편하니까"라는 단순한 이유로 사용해왔지만, 이번 기회에 왜 코틀린을 선택했는지, 그리고 그 선택이 어떻게 나의 개발 경험을 변화시켰는지 깊이 생각해보게 되었다.

안드로이드 개발의 어려움

자바의 한계

안드로이드 프레임워크는 추상화보다는 저수준의 API를 제공한다. 이로 인해 보일러플레이트 코드가 많을 수밖에 없는데, 자바의 제한된 표현력이 더해져서 실제로 실행하고 싶은 코드보다 보일러플레이트 코드가 더 많아지는 상황이 발생한다. 자바 8로 넘어오면서 람다와 메소드 레퍼런스를 사용할 수 있게 되었지만, 이것만으로는 안드로이드의 보일러플레이트 문제를 완전히 해결하기에는 부족했다.

// 람다
button.setOnClickListener(view -> doSomething(view));

// 메소드 레퍼런스
button.setOnClickListener(this::doSomething);

보일러플레이트의 늪

XML 레이아웃 파일에서 뷰 레퍼런스를 가져오는 부분이나 SQLite 트랜잭션을 처리하는 부분에서 보일러플레이트 코드가 많이 발생한다.

progressBar = (ProgressBar) findViewById(R.id.progress_bar);
textView = (TextView) findViewById(R.id.textView);
webView = (WebView) findViewById(R.id.web_view);
db.beginTransaction();
try {
    db.delete("users", "family_name = ?", arrayOf("AB")); // 실행시키고 싶은 코드
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}

이런 보일러플레이트 코드가 안드로이드 프로젝트 전반에 걸쳐 있어서 소스코드의 양이 많아지고, 유지보수 시 어려움이 생긴다.

NullPointerException과의 전쟁

NPE에 대한 기본 대처 방법은 다음과 같다:

if(foobar != null) {
    // foobar is not null
}
try {
    foobar.doSomething()
} catch(NullPointerException e) {
    // Null Exception
}

이후 엄청난 if / try 문에 둘러싸이게 된다. Null일 수도 있고 Null이 아닐 수도 있지만, Null 처리를 해주는 것이 안전할 수 있다. 앱이 죽는 것보다는 낫기 때문이다.

코틀린과의 만남

변수 정의의 혁신

// 읽기 가능
val a: Int = 1
// 읽기 가능, 타입 추론
val b = 1
// 읽기 쓰기 가능
var c = 10
// 에러! 초기화 않음
val d:Int
// nullable이지만 생성자에서 반드시 초기화 해야함
val e: Int?
// nullable이지만 에러! 초기화하지 않음
var f:Int?

어떤 값을 가지는지, 값이 바뀔 여지가 있는지에 대해 고민하고 코드를 작성하게 해 NPE를 막는 데 많은 도움을 준다. Null을 가질 수 있는 변수를 올바르게 처리하지 않으면 컴파일러에서 에러를 발생시킨다.

// foobar가 null이 아닌 경우 doSomething() 호출
foobar?.doSomething()

보일러플레이트 개선

button.setOnClickListener { view -> doSomething(view) }
button.setOnClickListener(this::doSomething)

// 파라미터 사용하지 않음
button.setOnClickLisnster { doSomething() }

자바 6버전 이상 호환되기 때문에 SDK에 제한적이지 않다.

Extension Function의 마법

확장 함수(Extension Function)는 이미 존재하는 클래스에 새로운 메소드를 추가할 수 있는 기능이다.

fun Context.toast(message: CharSequence) {
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
context.toast("토스트 토스트 토스트")

View Injection의 편리함

<!-- main.xml -->
<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
// main.xml 기준으로 뷰 인젝션
import kotlinx.android.synthetic.main.main.view.*

// Button
button.setOnClickListener {
    // Do something
}

Java 100% 호환

공식 사이트에서도 100% interoperable with Java and Android라고 한다. 공식 사이트
일반 자바코드를 사용하는 데 있어 뭔가를 통할 필요가 없어 일반 자바 코드를 작성하듯이 사용할 수 있다.

결론

코틀린을 사용하면서 나는 소스 코드를 더 간결하게 표현할 수 있게 되었고, 그로 인해 코드에서 발생할 수 있는 버그를 줄일 수 있었다. 익숙해지면 자바 코드보다 더 나은 가독성을 가진 코드를 생산할 수 있다는 것을 경험했다.

코틀린은 단순한 언어가 아닌, 개발자의 생산성을 높이고 코드의 품질을 개선하는 도구이다. 나의 안드로이드 개발 경험을 더 즐겁고 효율적으로 만들어준 코틀린에 감사하다.

#android #essay #kotlin