코틀린 클린코드 가이드: 읽기 좋은 코드 작성법

코틀린 클린코드
코틀린 클린코드

코틀린은 문법이 간결해서 처음 접하면 “짧게 쓰는 코드”가 곧 좋은 코드처럼 느껴질 때가 많습니다. 하지만 실무에서는 조금 다릅니다. 코드가 짧은지보다 더 중요한 것은, 다른 개발자가 빠르게 이해할 수 있는지, 수정할 때 부작용이 적은지, 테스트하기 쉬운지입니다.

특히 코틀린은 null safety, data class, sealed class, extension function, scope function, coroutines처럼 표현력을 높여주는 기능이 많아서, 잘 쓰면 아주 읽기 좋은 코드가 되지만 잘못 쓰면 오히려 의도가 흐려지기 쉽습니다.

코틀린 클린코드는 짧은 코드가 아니라, 의도가 빠르게 읽히고 수정 비용이 낮은 코드입니다.


이 글은 코틀린 클린코드 시리즈의 허브 페이지입니다. 시리즈 전체 방향을 먼저 정리하고, 어떤 순서로 읽으면 좋은지, 각 글에서 무엇을 배우게 되는지 한눈에 볼 수 있도록 구성했습니다. 코틀린을 막 공부한 분부터, 자바 습관을 코틀린으로 옮겨오고 있는 분, 실무 코드 리뷰 품질을 끌어올리고 싶은 분까지 모두를 대상으로 작성했습니다.

왜 코틀린 클린코드를 따로 다뤄야 할까요?

클린코드 자체는 특정 언어에만 적용되는 개념이 아닙니다. 하지만 코틀린으로 클린코드를 이야기할 때는, 다른 언어의 원칙을 그대로 가져오는 것만으로는 부족합니다. 코틀린은 언어 차원에서 의도를 더 분명하게 드러낼 수 있는 기능을 많이 제공하기 때문입니다.

예를 들어 코틀린에서는 null 처리를 타입 시스템으로 더 명확하게 표현할 수 있고, data class와 sealed class로 모델의 의미를 분리할 수 있으며, extension function과 scope function으로 코드의 표현 방식을 바꿀 수 있습니다. 또한 코루틴을 통해 비동기 로직도 비교적 순차적인 형태로 읽히게 만들 수 있습니다.

문제는 여기서부터입니다. 코틀린 문법을 “많이 쓰는 것”과 “잘 쓰는 것”은 다릅니다. scope function을 남발하거나, !!를 쉽게 사용하거나, 확장 함수를 무분별하게 추가하거나, 자바 스타일 클래스를 그대로 옮겨오면 코틀린답지도 않고 읽기 쉬운 코드도 되지 않습니다. 결국 코틀린 클린코드는 문법의 화려함보다 의도의 전달력을 우선하는 태도에서 시작합니다.

이 시리즈에서 다루는 핵심 원칙

1. 이름이 코드의 절반입니다

좋은 변수명, 함수명, 클래스명은 주석보다 강력합니다. 이름만 봐도 역할이 보이면, 코드를 읽는 속도와 유지보수 품질이 함께 올라갑니다.

2. 함수는 짧기보다 선명해야 합니다

무조건 짧은 함수가 좋은 것은 아닙니다. 다만 하나의 함수 안에 여러 관심사가 섞이면 읽는 사람이 문맥을 놓치기 쉽습니다. 이 시리즈에서는 “함수를 어디서 끊어야 하는지”를 코틀린 예제로 설명합니다.

3. null은 코드 안쪽이 아니라 경계에서 정리해야 합니다

실무에서 복잡해지는 코드는 대부분 nullable 값이 여기저기 퍼지면서 생깁니다. 가능한 한 입력 경계에서 null을 정리하고, 그 이후에는 non-null 모델로 흘러가게 만드는 것이 훨씬 읽기 쉽습니다.

4. 코틀린다운 문법은 목적이 분명할 때만 사용해야 합니다

let, run, apply, also, 확장 함수, 고차 함수는 모두 강력합니다. 하지만 강력한 도구일수록 언제 쓰지 말아야 하는지 기준이 더 중요합니다.

5. 상태와 부수효과가 적을수록 테스트하기 쉬워집니다

클린코드는 결국 테스트 가능성과 연결됩니다. 상태를 줄이고 책임을 분리하면, 코드 리뷰가 쉬워지고 버그가 줄어들며 리팩터링 부담도 낮아집니다.

6. 코틀린의 장점은 “짧게”가 아니라 “명확하게”에 있습니다

한 줄로 줄일 수 있다고 해서 항상 좋은 코드는 아닙니다. 팀원이 3초 안에 이해하지 못하는 축약은, 대부분 미래의 유지보수 비용으로 돌아옵니다.

코틀린 클린코드 예시: before & after

아래 예시는 같은 비즈니스 규칙을 서로 다른 방식으로 표현한 코드입니다. 핵심은 “더 짧은 코드”가 아니라 “더 읽기 쉬운 코드”가 무엇인지 보는 데 있습니다.

before

fun calc(u: User?, items: List<Item>?): Int {
    if (u == null || items == null) return 0

    var sum = 0
    for (i in items) {
        if (i.price != null && i.count != null) {
            sum += i.price!! * i.count!!
        }
    }

    return if (u.grade == "VIP") sum * 9 / 10 else sum
}

after

data class Customer(
    val isVip: Boolean,
)

data class OrderItem(
    val price: Int,
    val quantity: Int,
)

fun calculateOrderTotal(
    customer: Customer,
    items: List<OrderItem>,
): Int {
    val subtotal = items.sumOf { item -> item.price * item.quantity }
    return if (customer.isVip) subtotal * 90 / 100 else subtotal
}

두 코드의 차이는 분명합니다. calc보다 calculateOrderTotal이 의도를 더 잘 드러내고, uitems보다 customerOrderItem이 도메인을 더 정확하게 표현합니다. 또한 nullable 값을 함수 내부에서 계속 방어하기보다, 애초에 non-null 모델로 정리해서 들어오게 만들면 로직이 훨씬 단순해집니다.

이 시리즈에서는 이런 차이를 이름, 함수 분리, null 처리, 모델링, 코루틴, 리팩터링 관점으로 하나씩 풀어갈 예정입니다.

코틀린 클린코드 시리즈 전체 구성

  1. 코틀린 클린코드란 무엇인가: 실무에서 읽기 좋은 코드의 기준
    클린코드의 기본 개념을 코틀린 관점에서 다시 정리합니다. “짧은 코드”와 “읽기 좋은 코드”의 차이를 가장 먼저 잡는 글입니다.

  2. 코틀린 네이밍 컨벤션: 변수·함수·클래스 이름을 잘 짓는 법
    이름만 봐도 역할이 떠오르는 코드가 왜 중요한지, Boolean 네이밍과 컬렉션 네이밍은 어떻게 해야 하는지 실전 예제로 설명합니다.

  3. 코틀린 함수 설계: 짧고 읽기 쉬운 함수 만드는 방법
    함수 길이, 매개변수 개수, early return, expression body, named argument를 언제 써야 읽기 좋아지는지 다룹니다.

  4. 코틀린 null safety: !! 없이 안전한 코드 작성하기
    safe call, Elvis operator, requireNotNull, nullable 설계를 통해 null 때문에 복잡해지는 코드를 어떻게 줄일지 정리합니다.

  5. data class와 sealed class: 코틀린 모델링을 더 명확하게 만드는 법
    DTO, 상태 표현, 결과 타입, when 분기까지 포함해 도메인 모델을 더 분명하게 만드는 방법을 다룹니다

  6. extension function과 scope function: 코틀린다운 문법을 읽기 좋게 쓰는 법
    let, run, apply, also를 언제 써야 하고 언제 피해야 하는지 기준을 세워드립니다.

  7. 코틀린 컬렉션과 람다 클린코드: map, filter를 읽기 쉽게 쓰는 기준
    체이닝이 길어질 때 어디서 끊어야 하는지, 중간 변수는 언제 도입해야 하는지, 가독성과 표현력의 균형을 설명합니다.

  8. 코틀린 예외 처리: require, check, Result로 실패를 다루는 법
    예외를 던질지, 검증으로 막을지, 결과 타입으로 표현할지 기준이 없을 때 코드가 왜 흐려지는지 실무 예제로 보여드립니다.

  9. 테스트하기 좋은 코틀린 클래스 설계: 상태와 책임을 나누는 기준
    의존성 주입, 상태 최소화, side effect 분리, 작은 클래스 설계를 통해 테스트 가능성과 유지보수성을 함께 높이는 방법을 다룹니다.

  10. 코틀린 코루틴 클린코드: suspend와 structured concurrency 실전 원칙
    비동기 로직을 빠르게 짜는 방법이 아니라, 오래 읽히는 방식으로 작성하는 기준에 집중합니다.

  11. 코틀린과 자바를 함께 쓸 때 클린코드가 깨지는 이유
    플랫폼 타입, 자바 스타일 설계 습관, getter/setter 중심 사고방식이 코틀린 코드 가독성을 어떻게 떨어뜨리는지 설명합니다.

  12. 코틀린 리팩터링 실전: before & after로 배우는 코드 개선
    시리즈 전체 내용을 실제 before & after 예제로 압축 정리하는 마무리 글입니다. 실무에서 바로 써먹을 수 있는 리팩터링 감각을 키우는 데 초점을 둡니다.

추천 읽기 순서

시리즈는 처음부터 순서대로 읽어도 좋지만, 현재 수준에 따라 아래 순서로 읽으면 더 효율적입니다.

코틀린 입문을 막 끝낸 분

  • 1편: 코틀린 클린코드란 무엇인가
  • 2편: 네이밍 컨벤션
  • 3편: 함수 설계
  • 4편: null safety

실무 코드가 점점 복잡해지고 있는 분

  • 5편: data class와 sealed class
  • 6편: extension function과 scope function
  • 7편: 컬렉션과 람다
  • 8편: 예외 처리

리팩터링과 코드 리뷰 품질을 높이고 싶은 분

  • 9편: 테스트하기 좋은 클래스 설계
  • 10편: 코루틴 클린코드
  • 11편: 자바와 함께 쓸 때의 함정
  • 12편: 리팩터링 실전

이 시리즈를 읽으면 얻게 되는 것

  • 코드를 “돌아가게” 만드는 수준에서 벗어나, 읽히게 만드는 기준을 갖게 됩니다.
  • 리뷰할 때 막연히 “이상하다”가 아니라, 왜 읽기 어려운지 설명할 수 있는 언어가 생깁니다.
  • 코틀린 문법을 많이 쓰는 것이 아니라, 언제 써야 더 명확해지는지 판단하는 감각이 생깁니다.
  • 자바 습관을 그대로 옮긴 코드와 코틀린다운 코드의 차이를 더 분명하게 이해하게 됩니다.
  • 리팩터링 기준이 생겨서, 기능 추가 전에 코드를 어디부터 손봐야 할지 더 빨리 판단할 수 있습니다.

자주 묻는 질문

클린코드는 짧은 코드인가요?

아닙니다. 짧은 코드는 때로 도움이 되지만, 무조건 좋은 코드는 아닙니다. 오히려 지나친 축약 때문에 문맥이 사라지면 읽는 데 더 오래 걸릴 수 있습니다. 클린코드는 “적게 쓰는 코드”보다 “의도가 잘 드러나는 코드”에 가깝습니다.

scope function을 많이 쓰면 더 코틀린다운 코드가 되나요?

반드시 그렇지는 않습니다. let, run, apply, also는 분명 유용하지만, 중첩되기 시작하면 수신 객체가 무엇인지 헷갈리기 쉽습니다. 코틀린다운 코드는 문법을 많이 쓰는 코드가 아니라, 읽는 사람의 인지 부담을 낮추는 코드입니다.

자바에서 넘어온 개발자가 가장 자주 하는 실수는 무엇인가요?

자바 스타일 getter/setter 중심 설계를 그대로 유지하거나, null 방어 코드를 너무 깊게 끌고 들어오거나, 코틀린에서 더 단순하게 표현할 수 있는 모델을 불필요하게 장황하게 만드는 경우가 많습니다. 이 시리즈에서는 그런 지점을 코틀린 관점으로 다시 정리합니다.

코루틴도 클린코드 주제에 포함되나요?

물론입니다. 비동기 코드는 동기 코드보다 문맥이 복잡해지기 쉬우므로, 오히려 더 강한 클린코드 원칙이 필요합니다. 취소 전파, 책임 분리, dispatcher 처리, 흐름 제어 같은 지점은 가독성과 유지보수성에 직접 연결됩니다.

마무리

코틀린 클린코드는 문법을 멋지게 쓰는 기술이 아니라, 팀이 오래 유지할 수 있는 코드를 만드는 습관입니다. 이 시리즈에서는 단순히 “이 문법을 써보세요” 수준을 넘어서, 왜 그 방식이 더 읽기 쉽고, 왜 그 구조가 더 안전하며, 왜 그 설계가 더 오래 가는지를 실전 코드 중심으로 설명드릴 예정입니다.

이 허브 페이지는 시리즈가 발행될 때마다 계속 업데이트하겠습니다. 즐겨찾기해 두시고 필요할 때마다 전체 흐름을 다시 확인해보세요.

함께보면 좋은 글