Kotlin

[Kotlin IN ACTION] 1. 코틀린이란 무엇이며, 왜 필요한가? - (1) 코틀린 맛보기 & (2) 코틀린의 주요 특성

suoop 2024. 5. 27. 15:38

드미트리 제메로프, 스베트라나 이사코바, 『Kotlin IN ACTION』, 에이콘, 2017.

 

해당 포스팅은 위 책을 학습하기 위한 용도로 쓰여진 글입니다.

 

 


<1장에서 다루는 내용>
- 코틀린 기본 기능 데모
- 코틀린 언어의 주요 특성
- 코틀린을 활용한 안드로이드와 서버 개발
- 코틀린이 다른 언어보다 더 나은 점
- 코틀린으로 코드를 작성하고 실행하는 방법

 

💡 코틀린이란 무엇인가?

코틀린은 자바 플랫폼에서 돌아가는 새로운 프로그래밍 언어다.

코틀린은 간결하고 실용적이며, 자바 코드와의 상호운용성을 중시한다. 현재 자바가 사용 중인 곳이라면 거의 대부분 코틀린을 활용할 수 있다. 대표적으로 서버 개발, 안드로이드 앱 개발 등의 분야에서 코틀린을 쓸 수 있다.

코틀린은 기존 자바 라이브러리나 프레임워크와 함께 잘 작동하며, 성능도 자바와 같은 수준이다. 1장에서는 코틀린의 주요 특성을 자세히 살펴본다. 

 

☝️ 1.1 코틀린 맛보기

코틀린의 특징을 보여줄 수 있는 작은 예제로 시작해보자. 이 예제에서는 Person이라는 클래스를 정의하고, 그 클래스를 사용해 사람을 모아둔 컬렉션을 만들고, 가장 나이가 많은 사람을 찾아 결과를 출력한다.

코드는 아주 짧지만 그 안에서 여러 가지 흥미진진한 코틀린 언어의 특성을 발견할 수 있을 것이다. 

 

http://try.kotl.in 에 접속하면 이 예제를 가장 쉽고 빠르게 실행해볼 수 있다. 예제를 프로그램 입력 창에 쳐 넣고 실행 버튼을 클릭하면 코드가 실행된다.

 

Kotlin Playground: Edit, Run, Share Kotlin Code Online

 

play.kotlinlang.org

 

// 리스트 1.1 코틀린의 첫 인상

data class Person(val name: String, // <- '데이터' 클래스
				  val age: Int ?= null) // <- 널이 될 수 있는 타입(Int?)과 파라미터 디폴트 값
            
fun main(args:Array<String>) { // <- 최상위 함수
	val persons = listOf(Person("영희"),
    					 Person("철수", age = 29)) // <- 이름 붙은 파라미터
                         
    val oldest = persons.maxBy { it.age ?: 0 } // <- 람다 식과 엘비스 연산자
    println("나이가 가장 많은 사람: $oldest") // <- 문자열 템플릿
}

// 결과: 나이가 가장 많은 사람: Person(name=철수, age=29) // <- toString 자동 생성

 

name과 age라는 프로퍼티가 들어간 간단한 데이터 클래스를 정의한다.

age 프로퍼티의 디폴트 값은(따로 지정하지 않은 경우) null이다. 

사람 리스트를 만들면서 영희의 나이를 지정하지 않았기 때문에 null이 대신 쓰인다. 

리스트에서 가장 나이가 많은 사람을 찾기 위해 maxBy 함수를 사용한다. maxBy 함수에 전달한 람다 식은 파라미터를 하나 받는다. it이라는 이름을 사용하면 (별도의 파라미터 이름을 정의하지 않아도) 람다 식의 유일한 인자를 사용할 수 있다. 

 

엘비스 연산자라고 부르는 ?: 는 age가 null인 경우 0을 반환하고, 그렇지 않은 경우 age의 값을 반환한다.

영희의 나이를 지정하지는 않았지만 엘비스 연산자가 null을 0으로 변환해주기 때문에 철수가 가장 나이가 많은 사람으로 선정될 수 있다.

 

 

 

💫 1.2 코틀린의 주요 특성

코틀린의 핵심 특성을 좀 더 자세히 알아보자. 먼저 코틀린을 통해 어떤 종류의 애플리케이션을 만들 수 있는지 살펴보자.

 

 

1.2.1 대상 플랫폼: 서버, 안드로이드 등 자바가 실행되는 모든 곳

코틀린의 주목적은 현재 자바가 사용되고 있는 모든 용도에 적합하면서도 더 간결하고 생산적이며 안전한 대체 언어를 제공하는 것이다.

자바는 아주 유명하며, 스마트카드로부터 구글, 트위터, 링크드인 등 세계적인 규모의 인터넷 기업이 활용 중인 큰 데이터 센터에 이르기까지 다양한 환경에서 사용되고 있다. 그런 환경 중 대다수는 코틀린을 도입하면 더 적은 코드로 더 편하게 프로그래머의 목표를 달성할 수 있을 것이다.

 

코틀린을 활용할 수 있는 가장 일반적인 영역은 다음과 같다.

  • 서버상의 코드(특히 웹 애플리케이션의 백엔드)
  • 안드로이드 디바이스에서 실행되는 모바일 애플리케이션

하지만 코틀린은 다른 환경에서도 잘 작동한다. 

예를 들어 인텔의 멀티OS 엔진을 사용하면 코틀린을 iOS 디바이스에서 실행할 수 있다. 데스크탑 애플리케이션을 작성하고 싶다면 코틀린과 토네이도FX, 자바FX 등을 함께 사용할 수 있다.

 

자바뿐 아니라 자바스크립트로도 코틀린을 컴파일할 수 있다. 따라서 코틀린 코드를 브라우저나 노드에서 실행할 수 있다. 코틀린 1.1부터는 자바스크립트를 공식적으로 지원한다. 다만 이 책에서는 자바와 관련된 부분을 집중적으로 설명한다.

젯브레인스(JetBrains)는 코틀린 네이티브 백엔드를 개발 중이다(https://github.com/JetBrains/kotlin-native).

 

코틀린이 정한 목표 영역은 상당히 광범위하다. 코틀린은 어느 한 문제 영역만을 해결하거나 오늘날 소프트웨어 개발이 처한 어려움 중 일부만을 다루기 위한 언어가 아니다. 대신 코틀린은 개발 과정에서 수행해야 하는 모든 과업에 있어 폭넓게 생산성을 향상시켜준다. 코틀린은 구체적인 영역의 문제를 해결하거나 특정 프로그래밍 패러다임을 지원하는 여러 라이브러리와 아주 잘 융합된다. 이제 프로그래밍 언어로서 코틀린이 갖는 몇 가지 핵심 특성을 살펴보자.

 

 

1.2.2 정적 타입 지정 언어

자바와 마찬가지로 코틀린도 정적 타입 지정 언어다. 

정적 타입 지정이라는 말은 모든 프로그램 구성 요소의 타입을 컴파일 시점에 알 수 있고 프로그램 안에서 객체의 필드나 메소드를 사용할 때마다 컴파일러가 타입을 검증해준다는 뜻이다.

 

이런 점은 다른 동적 타입 지정 언어와는 다르다. 

JVM에서 그루비(Groovy)나 JRuby가 대표적인 동적 타입 지정 언어다. 동적 타입 지정 언어에서는 타입과 관계없이 모든 값을 변수에 넣을 수 있고, 메소드나 필드 접근에 대한 검증이 실행 시점에 일어나며, 그에 따라 코드가 더 짧아지고 데이터 구조를 더 유연하게 생성하고 사용할 수 있다. 하지만 반대로 이름을 잘못 입력하는 등의 실수도 컴파일 시 걸러내지 못하고 실행 시점에 오류가 발생한다.

 

한편 자바와 달리 코틀린에서는 모든 변수의 타입을 프로그래머가 직접 명시할 필요가 없다. 대부분의 경우 코틀린 컴파일러가 문맥으로부터 변수 타입을 자동으로 유추할 수 있기 때문에 프로그래머는 타입 선언을 생략해도 된다. 

가장 간단한 예는 다음과 같다.

var x = 1

 

여기서는 변수를 정의하면서 정수 값으로 초기화 한다. 코틀린은 이 변수의 타입이 Int 임을 자동으로 알아낸다. 

컴파일러가 문맥을 고려해 변수 타입을 결정하는 이런 기능을 타입 추론이라고 부른다.

 

정적 타입 지정의 장점은 다음과 같다.

  • 성능   실행 시점에 어떤 메소드를 호출할지 알아내는 과정이 필요 없으므로 메소드 호출이 더 빠르다.
  • 신뢰성   컴파일러가 프로그램의 정확성을 검증하기 때문에, 실행 시 프로그램이 오류로 중단될 가능성이 더 적어진다.
  • 유지 보수성   코드에서 다루는 객체가 어떤 타입에 속하는지 알 수 있기 때문에 처음 보는 코드를 다룰 때도 더 쉽다.
  • 도구 지원   정적 타입 지정을 활용하면 더 안전하게 리팩토링할 수 있고, 도구는 더 정확한 코드 완성 기능을 제공할 수 있으며, IDE의 다른 지원 기능도 더 잘 만들 수 있다.

 

코틀린은 타입 추론을 지원하므로 정적 타입 지정 언어에서 프로그래머가 직접 타입을 선언해야 함에 따라 생기는 불편함이 대부분 사라진다. 

코틀린의 타입 시스템을 더 자세히 살펴보면 이미 잘 알고 있는 내용을 많이 발견할 수 있다.

클래스, 인터페이스, 제네릭스는 모두 자바와 비슷하게 작동한다. 따라서 자바에 대해 아는 내용을 코틀린에서도 쉽게 적용할 수 있다.

 

하지만 몇 가지 새로운 점이 있다.

그중 가장 중요한 특성은 코틀린이 널이 될 수 있는 타입(nullable type)을 지원한다는 점이다. 

널이 될 수 있는 타입을 지원함에 따라 컴파일 시점에 널 포인터 예외가 발생할 수 있는지 여부를 검사할 수 있어서 좀 더 프로그램의 신뢰성을 높일 수 있다. 널이 될 수 있는 타입에 대해서는 1장의 뒷 부분에서 간략히 살펴본 후 6장에서 더 자세히 설명한다.

 

코틀린의 타입 시스템에 있는 다른 새로운 내용으로는 함수 타입(function type)에 대한 지원을 들 수 있다. 함수 타입이 무엇인가 알아보기 위해 함수형 프로그래밍이 어떤 개념인지와 코틀린이 함수형 프로그래밍을 어떻게 지원하는지에 대해 먼저 알아보자.

 

 

1.2.3 함수형 프로그래밍과 객체지향 프로그래밍

 

자바 개발자인 독자라면 객체지향 프로그래밍의 핵심 개념을 잘 이해하고 있을 것이다. 하지만 그런 개발자에게도 함수형 프로그래밍은 새로운 개념일 수 있다. 함수형 프로그래밍의 핵심 개념은 다음과 같다.

  • 일급 시민인(first-class) 함수   함수(프로그램의 행동을 나타내는 코드 조각)를 일반 값처럼 다룰 수 있다. 함수를 변수에 저장할 수 있고, 함수를 인자로 다른 함수에 전달할 수 있으며, 함수에서 새로운 함수를 만들어서 반환할 수 있다.
  • 불변성(immutability)   함수형 프로그래밍에서는 일단 만들어지고 나면 내부 상태가 절대로 바뀌지 않는 불변 객체를 사용해 프로그램을 작성한다.
  • 부수 효과(side effect) 없음   함수형 프로그래밍에서는 입력이 같으면 항상 같은 출력을 내놓고 다른 객체의 상태를 변경하지 않으며, 함수 외부나 다른 바깥 환경과 상호작용하지 않는 순수 함수(pure function)를 사용한다.

 

이런 핵심 개념을 사용하는 함수형 스타일로 프로그램을 작성하면 어떤 유익이 있을까?

첫째로 간결성을 들 수 있다.

함수형 코드는 그에 상응하는 명령형 코드에 비해 더 간결하며 우아하다. (순수) 함수를 값처럼 활용할 수 있으면 더 강력한 추상화를 할 수 있고 강력한 추상화를 사용해 코드 중복을 막을 수 있다.

 

비슷한 작업을 수행하는 아주 비슷한 두 개의 코드 조각이 있다고 가정해보자(예를 들어 컬렉션에서 어떤 조건을 만족하는 원소를 찾는 작업을 생각할 수 있다). 하지만 그 두 코드 조각은 일부 세부 사항에서 차이가 난다(예를 들어 만족시켜야 하는 조건이 조금 다르다). 이 로직에서 공통부분을 따로 함수로 뽑아내고 서로 다른 세부 사항을 인자로 전달할 수 있다. 이런 인자는 그 자체가 함수다. 하지만 람다 식(lambda expression)이라 불리는 무명 함수 구문을 사용하면 간결하게 그런 함수를 표현할 수 있다.

fun findAlice() = findPerson { it.name == "Alice" } // <- findPerson에는 사람을 찾는 일반 로직이 들어가 있다.
fun findBob() = findPerson { it.name == "Bob" } // <- 중괄호({}) 사이에 있는 코드 블록은 찾으려는 사람을 식별한다.

 

 

함수형 프로그래밍에서 얻을 수 있는 두 번째 유익은 다중 스레드를 사용해도 안전하다는 사실이다.

다중 스레드 프로그램에서는 적절한 동기화 없이 같은 데이터를 여러 스레드가 변경하는 경우 가장 많은 문제가 생긴다. 불변 데이터 구조를 사용하고 순수 함수를 그 데이터 구조에 적용한다면 다중 스레드 환경에서 같은 데이터를 여러 스레드가 변경할 수 없다. 따라서 복잡한 동기화를 적용하지 않아도 된다.

 

마지막으로 함수형 프로그램은 테스트하기 쉽다. 

부수 효과가 있는 함수는 그 함수를 실행할 때 필요한 전체 환경을 구성하는 준비 코드(setup code)가 따로 필요하지만, 순수 함수는 그런 준비 코드 없이 독립적으로 테스트할 수 있다.

 

일반적으로 말하자면 언어와 관계없이 함수형 스타일을 활용할 수 있다. 물론 자바에서도 함수형 프로그래밍이 가능하다. 그리고 함수형 프로그래밍 스타일을 이루는 여러 요소는 좋은 프로그래밍 스타일이며, 장려할 만하다.

하지만 모든 언어가 함수형 프로그래밍을 편하게 사용하기에 충분한 라이브러리와 문법 지원을 제공하지는 않는다. 예를 들어 자바 8 이전의 자바에는 함수형 프로그래밍을 지원할 수 있는 기능이 거의 없었다.

코틀린은 처음부터 함수형 프로그래밍을 풍부하게 지원해 왔다. 그런 지원은 다음과 같다.

  • 함수 타입을 지원함에 따라 어떤 함수가 다른 함수를 파라미터로 받거나 함수가 새로운 함수를 반환할 수 있다.
  • 람다 식을 지원함에 따라 번거로운 준비 코드를 작성하지 않아도 코드 블록을 쉽게 정의하고 여기저기 전달할 수 있다.
  • 데이터 클래스는 불변적인 값 객체(value object)를 간편하게 만들 수 있는 구문을 제공한다.
  • 코틀린 표준 라이브러리는 객체와 컬렉션을 함수형 스타일로 다룰 수 있는 API를 제공한다.

코틀린은 함수형 스타일로 프로그램을 짤 수 있게 지원하지만 함수형 프로그래밍 스타일을 강제하지는 않는다.

명령형 방식이 더 적합한 경우라면 함수형 프로그래밍으로 번거롭게 코드를 작성할 필요 없이 직접 변경 가능한 데이터와 부수 효과를 활용하는 함수를 사용해도 된다. 당연히 인터페이스와 클래스 계층 구조를 바탕으로 하는 프레임워크도 자바를 사용할 때와 마찬가지로 쉽게 쓸 수 있다. 코틀린으로 코드를 작성할 때는 객체지향과 함수형 접근 방법을 함께 조합해서 문제에 가장 적합한 도구를 사용하면 된다.

 

 

1.2.4 무료 오픈소스

코틀린 언어와 컴파일러, 라이브러리 및 코틀린과 관련된 모든 도구는 모두 오픈소스며, 어떤 목적에든 무료로 사용할 수 있다. 코틀린은 아파치 2 라이선스하에 제공된다.

개발은 깃허브를 통해 이뤄지고 있으며(http://github.com/jetbrains/kotlin), 코틀린 프로그래밍 커뮤니티의 기여에 대해 열려있다. 코틀린 애플리케이션을 개발하고 싶은 경우 인텔리J 아이디어 커뮤니티 에디션, 안드로이드 스튜디오, 이클립스 같은 오픈소스 IDE를 활용할 수 있다.


드미트리 제메로프, 스베트라나 이사코바, 『Kotlin IN ACTION』, 에이콘, 2017, 36~42쪽.