본문 바로가기

안드로이드 Android

안드로이드 개발 (37) Kotlin In Action 정리 - 1

 

현업에서 일을 하다보면, Back To The Basic 을 통하여 디버깅 추적 및 안전한 코드 작성 능력을 강화 할 수 있다는 것을 알게 됩니다. 이 글은 J brains 에서 일하는  Dmitry Jemerov, Kotlin 개발팀의 일원인 Svetlana lsakova 이 두명이 집필한 책인 Kotlin In Action 내용을 정리한 내용 입니다. 

 

더보기

Drimitry jemerov 는 대표적으로 최초의 Kotlin ByteCode Generator를 만들었다.

Svetlana Isakova는 대표적으로 Kotlin Compiler의 Type Inference 과 Overload resolution 부분을 개발 하였다. 

 

최근에 Effective Kotlin 과 Kotlin In Action을 다시 정독하기 시작했습니다. 예전에 이미 읽었던 책이지만, 바쁜 현업 생활에 기본기가 떨어지지 않을까 걱정하는 생각 때문에 이번엔 블로그에 글을 남겨 Basic과 best Pratice를 나의 생각에 뿌리 깊게 박히길 원하는 마음으로 적었습니다. 

 

 

Intro) 탄생 비화

 

kotlin 의 시작..!

 

Kotlin 의 탄생 비화는 Java 를 쓰는 J Brain 팀이 다른 팀에서 C# 를 이용하여 모던한 방식으로 개발 하는 것을 보며 부러워하게 됬던 점에서 시작하였습니다. 그래서 Java 팀은 대체할만한 언어를 찾거나 대안을 찾아내려는 노력을 하면서 다음과 같은 해결점을 고려하였습니다.

  1.  기존 Java팀이 쓰던 Java 라이브러리나 프레임워크를 호환이 가능해야함 그렇지 않으면 처음부터 만들거나 유지보수 해야하는 불상사가 발생  
  2.  1번을 해결하기 위해 Java와 상호 호환성을 할 수 있는 언어가 없음
  3.  모던한 방식 

그렇게 J Brain은 자바와 상호호환성이 좋고 모던함을 갖추고 J Brain 팀의 실무 경험을 토대로 실용적인 언어를 새롭게 만들기로 결정합니다.

 

더보기

Kotlin은 코틀린 개발 팀이 대부분 살고 있는 러시아의 상트페테르부르크 근처에 있는 섬이름을 따서 만든 이름입니다. Java나 Ceylon 같이 언어 기원의 전통을 따른 것인데, 고향에 가까운 섬의 이름을 따왔습니다.

 

1장 - Kotlin이 무엇이고, 왜 써야하는가?

 

위 에서 설명했다시피 Java 보다 더 모던한 방식이 필요하면서 동시에 Java로 만든 라이브러리,SDK, 프레임 워크를 이용할 수 있는 언어가 필요하였고 이 두가지 요구 충족을 목표로 하여 만들어진 것이 Koltin 입니다.

 

아래는 Kotlin 코드 맛보기 입니다. 

 

fun main() {
    val persons = listOf(
        Person("영희"),
        Person("철수", 29)
    )
    
    val oldPerson = persons.maxBy { it.age?:0 }
    println("나이가 가장 많은 사람: $oldPerson")
}

data class Person(val name: String, val age: Int? = null)


Kotlin은 다음과 같은 특성들이 생깁니다.

 

1) 사용 가능 플랫폼

- 자바가 실행되는 모든 곳에서 사용이 가능합니다. 대표적으로 Spring , Android 등등이 있습니다. 

- 코틀린은 자바뿐만 아니라 더 다양한 곳에서 사용이 가능합니다. 

ex) 인텔의 멀티OS 엔진을 통한 IOS디바이스에서 실행, 자바스크립트에서 사용 등등..

 

2) 정적 타입 지정 언어 

- 정적 언어가 가지는 안정성을 그대로 가져간다.

- 정적 언어지만 동시에 타입 추론이 가능하기 때문에 간결한 코드 작성이 가능해진다.

*Loner 생각: 하지만 타입 추론을 잘못 사용하면 상위 타입과 매칭이 안되는 경우도 있으며, 당장 타입을 알지 못해 직접 확인해야하는 비용이 발생 합니다. 이는 effective 코틀린에서 언급되는 내용이기도 합니다.* 

- 함수 타입을 지원한다. 예제 코드를 보면 다음과 같다. 

#코틀린에서 잘만 실행 된다.

*Loner 생각: Kotlin의 모든 함수는 기본적으로 Unit이라는 Type을 반환 합니다. 사실 실무에서 아래 예제처럼 쓰는 경우는 거의 없고 람다를 주로 쓰겠지만.. Unit Type 의 특징을 예시로 듭니다.* 

 

fun main() {
    test2(test1())
}
fun test1(){
    println("asd")
}

fun test2(test1:Unit){
    test1
}

#자바에서는 오류난다. (비교가 이상하지만.. void는 타입이 아니기 때문 )

*Loner 생각: 당연히 Unit이 없어서 사용불가 하다.*

 

 

3) 객체지향 + 함수형의 장점을 가진다.

- Kotlin은 객체지향과 함수형을 가지는 멀티 패러다임 언어다.

- 함수형을 간단히 설명하자면.. (1) 일급 시민인 함수를 변수로 취급하거나 다른 함수로 인자로 보낼 수도 있다.

(2) 불변성을 가진다. 코드 작성시 불변인 상태를 사용해서 많은 이점을 가져간다. (3) 사이드 이펙트가 없다. 사이드 이펙트는 함수 내부에서 함수 외부의 상태 값을 건드는 일인데, Pure Function 이라는 개념으로 함수 외부 객체의 값을 변경하지 않는다.

*Loner 생각: Kotlin은 상황에 따라 가변 객체를 사용할 수 있어서 매우 활용성이 좋으나 기본 권장으로 객체가 불변상태인것이 디버깅 할때 마음 편하고, 안정적이긴 합니다.  * 

- 함수형의 장점을 이용하여 선언형 프로그래밍 방식이 가능 하다. 

- Kotlin은 람다와 공식지원 라이브러리가 함수형으로 코드 작성 할 수 있도록 도와준다.

- 함수형의 특징을 가지기 때문에 고차함수 활용이 가능하다.

- data class의 copy로 불변 객체 활용을 도와준다.

- Kotlin은 객체지향, 함수형 프로그래밍의 장점을 상황에 따라 자유롭게 활용할 수 있다

*Loner 생각: 실무에서 가능하면 선언형 프로그래밍 방식과 안정성을 위해 불변성 응용과 사이드 이펙트와 람다를 활용하려는 경우가 많은것 같고,  큰 설계 그림에서 객체지향적인 설계 위주로 생각하게 되는 것 같습니다. 물론 상황에 따라 가변 변수나 명령형 방식을 쓰는게 좋은 경우가 간혹 있습니다.* 

 

4) 안드로이드 프로그래밍

- 코틀린 언어의 특성과 안드로이드 프레임워크의 특별한 컴파일러 플로그인 지원을 조합하면 생산성을 더 높일 수 있다.

- 안드로이드의 Jetpack Compose가 Kotlin Api를 이용한 대표적인 좋은 사례이다. 

*Loner 생각: 책에서 Anko를 예시를 들지만, Anko는 이제 사용되지 않는 라이브러리 임으로 정리에서 제외하였습니다."

- Kotlin의 Null 방지 시스템은 컴파일 단계에서 Null PointerException 방지가 가능하므로 앱 도중에 중지되는 일을 많이 방지 할 수 있다. 

-Koltin으로 작성한 앱은 Java와 작성된 앱과 비교했을때 성능이 차이가 없다. 용량은 Kotlin 런타임 시스템의 용량이 작기 때문에 조금만 차이가 있을 뿐이다. 또한 코틀린 표준 라이브러리 함수는 인자로 받은 람다를 Inlining 하기 때문에 새로운 객체가 만들어지지 않아서 GC 이 늘어나 프로그램이 자주 Colding 되는일이 없다.

 

5) 코틀린의 철학

- Koltin은 Java와 호환성을 초점으로 맞추면서 실용적이고 간결하고 안전한 언어를 목표로 만들어졌다.

- 실용성

Kotlin은 연구를 목적을 위한 언어가 아니며, 실제 문제 해결을 위한 언어라서 기존에 검증된 해법과 기능을 효율적으로 활용 할 수 있도록 한다. 또한 Kotlin은 특정 프로그래밍만 강조하는 것이 아니므로 내가 익숙한 프로그래밍 기법으로 바로 코딩할 수 있다. 뿐만 아니라 Kotlin은 인텔리J의 IDE 지원을 강력하게 받을 수 있어서 인텔리J사용시 매우 편한 개발환경을 만들어준다.

 

#IDE 지원예시 

 

 

 

- 간결성

여기서 간결하다는 말은 작성된 코드를 읽을때 의도가 쉽게 파악되기 쉬운 구문 구조를 제공하고, 그 의도를 달성하는 방법을 이해할때 방해가 될 수 있는 부가적인 코드가 적다는 뜻이다.
그래서 Kotlin은 게터,세터,생성자 파라미터 등등.. 부가적인 코드작성 비용이 발생하는 부분들은 최대한 간소화 되었으며, Collection<T> 관련 함수와 같이 공식 라이브러리 함수를 통하여 핵심 로직만 코드 작성 할 수 있는 구문 구조를 만들 수 있다.
*Loner 생각: 소스코드를 가능한 짦게 만드는 것과는 다른 내용입니다. 그래서 Kolin은 연산자 오버로딩은 지원하지만, 연산자 자체를 커스텀할 수 있는 기능을 제공하지 않습니다. 예시로 test{ 1+1/2} 를 더 짦게 만들고자.. test{ (1)2 } 이런식으로 커스텀 하는 예제가 있을 것 같네요"

 

-안전성

프로그램에서 발생할 수 있는 오류중에서 프로그램 설계가 원천적으로 방지하려는 노력을 뜻합니다. 기본적으로 JVM위 에서 돌아가므로 메모리 안정성과 버퍼 오버 플로우를 방지할 수 있고, 문법 및 구조 적으로는 안전한 작성 방식을 유도합니다.

대표적인 예시로 객체를 다른 타입으로 cast하기 위해 반드시 if(value is String) 을 사용하거나, Null 방지 및 컨트롤 시스템으로 충분한 안전성을 가질 수 있습니다.

*Loner 생각: 더 나아가서 공격적 프로그래밍을 하기에도 좋은 것들이 있습니다. 또한  runCatching을 통한 getOrNull, getOrDefault  등등 활용할게 많습니다."

 

- 상호 운용성 

프로젝트 내에 Java와 Kotlin으로 작성된 클래스가 각각 있을때 서로 의존해도 아무런 호환문제가 없다. 별도의 처리해야될 문제가 없으므로 쉽게 사용할 수 있다. 

*Loner 생각:  Kotlin에서 Java의 플랫폼 타입을 쓸때 주의할 점으로 Java가 Nullable 처리를 따로 하지 않는다면 문제가 생길 수 있습니다. "

 

- Kotlin 빌드 과정

.kt 파일 생성 -> Koltin Complier에서 컴파일링 시작 -> .class 로 변환 -> .jar 파일 생성 -> Application (with. Kotlin Runtime 에 의존)

 

2장 - 코틀린 기초

 

2장에서 다루는 내용은 다음과 같다.

2장은 기본적인 내용은 어느정도 스킵하고 복습할만하다고 생각 되는 부분만 적었습니다.

더보기

- 함수, 변수, 클래스, enum, 프로퍼티 선언하는 방법

- 제어 구조

- 스마트 캐스트 

- 예외 던지기와 예외 잡기 

 

- when, if, try  조건문 대부분 Expression 으로 되어있어서 값을 return할 수 있다. (Java는 Statement라서 반대)

*Loner 생각:  상황에 따라 코드가 간결해질 수 있고, Side effect를 방지할 수 있도록 도움 줄 수 있습니다."

//조건문을 통해서 값을 return 한다.
fun main() {
    val result = when (0) {
        1 -> "1"
        2 -> "2"
        else -> "0"
    }
    println(result)
}

 

- 반면 대입문은 Java에서는 Expression 이나, Kotlin에서는 Statement 로 되어 있어서 대입식과 비교식을 잘못 바꿔 써서 버그가 생기는 경우가 드물다.

 

- koltin에서 if문의 3항 연산자를 지원하지 않는 이유는 expression라서 따로 지원하지 않는다.  

( kotlin의 if( a>b) b else a 이 a>b ? a:b 처럼 작동 한다.)

 

- 긴 함수의 return문이 여럿 들어있는 경우를 생각(어떤 값을 return하는지 모두 명시하기 위해) 해서 식이 본문인 함수의 반환 타입만 생략이 가능하다.

 

- val은 value에서 따왔고, var는 variable에서 따온 축약어이다. 

 

-한글을 사용한 String 의 경우 상황에따라 unresolved reference 오류가 일어 날 수 있다. 그래서 한글은 ${} 써야하는 경우가 종종 있다.

 

- 기본 이름 규칙에 따라 is로 시작하는 변수명의 property 는 기본적으로 getter, setter 도 is로 시작하는 이름이 된다.

 

- Kotlin 에서 Smart Casting은 is 로 이루어지는데, 컴파일러에서 캐스팅을 해준다. 

- map collection을 Iteration 해서 쓸 수 있다.

- 범위 비교는 in, !in 을 사용할 수 있다.

- Kotlin은 unchecked와 check Exception을 구분하지 않는다.

 

이상 Kotlin In Action 1장 정리 였습니다.  앞으로도 Back to the Basic을 외치며 탄탄해지도록 노력해야겠네요.