본문 바로가기
프로그래밍 놀이터/Kotlin, Coroutine

[Kotlin] 장점, 단점, 그리고 아쉬운 점 이야기

by 돼지왕 왕돼지 2018. 1. 15.
반응형

 [Kotlin] 장점, 단점, 그리고 아쉬운 점 이야기


https://medium.com/keepsafe-engineering/lessons-from-converting-an-app-to-100-kotlin-68984a05dcb6

https://medium.com/keepsafe-engineering/kotlin-the-good-the-bad-and-the-ugly-bf5f09b87e6f


@jvmfield, @Jvmstatic, Android, any, associate, by lazy, CLOSE, closed by default, code line, collection, conversion, default argument, default getter, default value, delegate, delegates, dex method count limit, dex method limit, entry, functional collection extensions, Get, getter, instance, java doc, java to kotlin 변환, jointostring, Kotlin, kotlin lib, kotlin method count, kotlin runtime, kotlin 단점, kotlin 아쉬운 점, kotlin 장점, LAMBDA, lambda param, lateinit, Lazy, Member, method count, minify, name space, named argument, nonnull, notnull, object, onCreate, optimize, pair list, private property, proguard, property, qualifier, required property accessor syntax, sam conversion, Set, Setter, single argument method, Singleton, static field, static modifier, suppress, top level function, top level property, Ugly, Unit, unit return, unit.instance, UsePropertyAccessSyntax, view initialize, [Kotlin] 장점, 가독성, 그리고 아쉬운 점 이야기, 단점, 아쉬운 점, 자동 변환, 장점, 코드 가독성, 편리


-

위 링크의 글을 쓴 필자는 마켓에 출시된 Java 로 되어 있는 앱을 Kotlin 으로 전환했다.

많은 사람들이 Kotlin lib 때문에 dex method limit 이 걸릴 것을 걱정하지만,

실제 converting 후 proguard 적용시 method count 는 10% 줄어들고, code line 은 30% 줄어들었다.

( 5491 to 4987 & 12,371 to 8,564 )


돼지왕왕돼지 주 : proguard 적용 전에는 확실히 dex method limit 에 부딪힐수도 있겠다….




잘 다뤄지지 않는 장점


Java to Kotlin 자동 변환

    perfect 하게 되진 않지만 그래도 초심자에게는 충분한 idea 를 준다.

    그리고 기존 코드를 converting 할 시에는 (받아쓰기같은 느낌의) 불필요한 코딩도 많이 줄일 수 있다.



lateinit, Delegates.notNull and lazy

    lateinit 덕에 android 의 onCreate 에서 view initialize 하는 경우, member 변수를 nullable 로 두지 않아도 된다.

    lateinit 을 delegate 에 사용하는 경우에는 Delegates.notNull<Int>() 를 사용하면 된다.


    lateinit 은 구조상 lazy init 이라면, 실제 lazy init 에서는 by lazy 함수를 사용할 수 있다.



Functional collection extensions

    any, joinToString, associate 등을 사용하면 정말 많은 불필요한 코드를 줄일 수 있다.

    ( any 는 entry 가 있는지 여부, associate 는 collection 값을 기준으로 pair list 를 생성 )



Named and default function arguments

    불필요한 overloading 정의를 막아준다.




잘 다뤄지지 않은 단점


No namespace

    Kotlin 은 top level function, property 를 지원한다.

    매우 편리하지만 헛갈릴 수 있다. ( 예 : 여러 파일에서 동명의 top level 함수 정의 )

    Kotlin 내부에서 qualifier 없이 바로 쓸 수 있기 때문이다.


    이에 대한 해결책은 사용시 qualifier 를 사용하는 방법인데 코드 가독성이 나뻐진다.

    다른 방법은 top-level 대신 object 를 사용해서 singleton 으로 만드는 것이다. 이는 Java 에서 부를 때 INSTANCE 가 붙어 또한 ugly 하다. 이를 피하려면 @JvmStatic 으로 선언해야 하는데 이 또한 ugly 하다.



No static modifier

    static 이 없어짐으로 인해서 Java 에서 호출할 때 쓸데없이 코드가 길어지고 가독성이 떨어질 수 있다.

    기본적으로 무조건 getter 접근하게 되어서 예를 들어 View class 의 VISIBLE const 를 접근하려면 View.Companion.getVISIBLE() 로 접근하거나, @JvmField 를 주어 View.VISIBLE 로 접근해야 한다. 여튼 기대보다 번잡스럽다.

    


Java to Kotlin 자동 변환

    장점이기도 하지만, 약 80% 정도만 제대로 작동한다.

    Javadoc 은 가끔 완전 이상하게 노출되기도 한다. 특히 line wrap 이 있을 때.

    static field 는 companion object 로 바뀌는데 기존 호출부를 다 고쳐야 한다. ( @JvmField, @JvmStatic 을 붙여주면 괜찮지만.. )



Required property accessor syntax

    get 을 property 이름으로 갖고 있다면 lint 관련해서 문제가 되며, 이를 해결하기 위해서는 @Suppress(“UsePropertyAccessSyntax”) 를 싸줘야 한다.



Method count

    line 수는 확실히 줄어들 것이다.

    그러나 프로젝트에 따라 method count 는 늘어날 수 있다. 그래서 dex method count limit 에 도달할 수 있다.

    method 가 늘어나는 이유는 여러가지가 있다.

    우선 쉽게 생각할 수 있는 것은 Kotlin runtime 에 추가된 함수들

    두번째는 property 의 등장으로 그들에 대한 자동 생성되는 get, set function 들

    ( private property with default getter & setter case 에는 실제 getter, setter 를 만들지 않는다 )

    

    getter, setter 에 의해 method count limit 에 도달할 상황이면 @JvmField 를 적용하는 것도 한 방법이다.





아쉬운 점 ( Ugly 한 점 )


SAM conversion 과 lambda 의 Unit return

    SAM interface 를 param 으로 받는 Java 함수가 있을 때는 큰 문제가 없다. Lambda 를 써주면 된다.

    그러나 반대로 SAM interface 를 param 으로 받는 Kotlin 함수가 있을 때는 쉽지 않다..

    fun registerCallback(r: View.OnClickListener)

    registerCallback(View.OnClickListener { /* do something */ })


    저렇게 안 하려면 함수 정의를 다르게 해야 한다.

    그럼 Kotlin 에서는 OK 지만.. Java 에서는 Unit 을 return 해줘야 한다..

    /* Kotlin */

    fun registerCallback(r: () -> Unit)

    

    /* Java */

    registerCallback( () -> {

        /* do something */

        return Unit.INSTANCE;

    })


    결론적으로 Kotlin 에서 만드는 lib 은 Kotlin 과 Java 모두를 만족시키는 interface 로 만드는 것이 힘들 수 있다는 것.

    그것에 대한 해결책으로 SAM param 과 lambda param 받는 overloading 을 해줘야 할 수 있다.



Closed by default

    이 부분은 크게 공감가지 않아 정리하지 않음.





반응형

댓글