/ KOTLIN, LINT, KTLINT, CODE STYLE

코틀린 코드 스타일, 고민하지마! - ktlint

코드를 작성하다 보면, 원했건 원치 않았던 간에 하나의 코딩 스타일을 사용하게 됩니다.

팀으로 일하는 경우, 코딩 스타일이 통일되지 않으면 작성한 사람에 따라 전반적인 구현 방식이 달라지는 경우가 많습니다. 따라서 보통 팀에서 사용하는 규칙을 정하고 그에 따라 코드를 작성하는 경우가 일반적입니다.

코딩 스타일을 정의한 문서를 작성한 후 이에 따라 작성하도록 유도하기도 하지만, 이러한 규칙들을 매번 사람이 확인하는 것은 거의 불가능에 가깝습니다. 때문에, checkstyle과 같은 정적 분석 도구를 사용하여 규칙 준수 여부를 확인합니다.

하지만, checkstyle 툴은 자바 코드에서만 사용할 수 있기에 코틀린으로 작성한 코드 스타일을 검사할 수 없습니다.

ktlint - Kotlin linter

ktlint는 코틀린을 위한 정적 분석 도구로, 코틀린으로 작성한 코드의 스타일 검사와, 형식에 맞지 않는 부분을 수정하는 기능을 제공합니다.

현재 글을 쓰는 시점을 기준으로 약 한 달 전에 공개된 도구로, 코틀린이 신생 언어라는게 확실히 느껴집니다. :)

ktlint는 코드 스타일을 검사한다는 측면에서 checkstyle과 유사하지만, 사용자가 직접 코드 스타일을 정의하지 않고 하나의 규칙을 일괄 적용합니다.

적용되는 규칙은 코틀린 공식 가이드 문서에 있는 Coding conventions를 따르며, 설정 파일 없이 일관된 규칙을 적용한다는 점에서 Go 언어를 위한 포매팅 툴인 gofmt와 유사합니다.

현재 적용되어 있는 규칙은 다음과 같습니다.

  • 인덴트로 공백(Space) 4개 사용
  • 세미콜론(;) 사용 금지 (단, 한 줄에 여러 문장을 적는 경우 제외)
  • 와일드카드(예: import foo.*)를 사용한 import 및 사용하지 않는 import 문 금지
  • 연속된 빈 줄 금지
  • 문장의 끝 부분에 빈 공간(whitespace) 금지 (예: space, tab)
  • 키워드, 콤마(,), 콜론(:), 중괄호({, }) 등 사이에 공백 확보

안드로이드 프로젝트에 적용하기

ktlint를 안드로이드 프로젝트에 적용해봅시다. 스타일을 검사하는 태스크(ktlint)와 스타일에 맞게 자동으로 코드를 수정하는 태스크(ktlintFormat) 두 개를 추가합니다.

여러 모듈로 구성된 프로젝트에 모두 추가되도록 하기 위해, 프로젝트 루트에 있는 빌드스크립트(build.gradle)를 다음과 같이 구성합니다.

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ...
}

allprojects {
    ...
}

// -- 다음 부분 추가 --
subprojects {
    configurations {
        ktlint
    }

    dependencies {
        ktlint 'com.github.shyiko:ktlint:0.2.0'
    }

    // 스타일을 검사하는 태스크
    task ktlint(type: JavaExec) {
        main = 'com.github.shyiko.ktlint.Main'
        classpath = configurations.ktlint
        args 'src/**/*.kt'
    }

    // 스타일을 검사하고 맞지 않는 부분을 수정해주는 태스크
    task ktlintFormat(type: JavaExec) {
        main = 'com.github.shyiko.ktlint.Main'
        classpath = configurations.ktlint
        args '-F', 'src/**/*.kt'
    }

    // 'check' 태스크가 실행될 때 'ktlint' 태스크가 함께 수행되도록 합니다.
    afterEvaluate { project ->
        check.dependsOn ktlint
    }
}
// -- 추가 끝 --

task clean(type: Delete) {
    delete rootProject.buildDir
}

검사 수행하기 (ktlint)

다음과 같이 스타일이 엉망(?)인 코드를 작성해봅시다.

[Calendar.kt]

import java.util.*

class Calculator {

         fun add(a: Int, b: Int) : Int{
        return a + b;
    }



    fun sub(a: Int,b:Int) : Int=a-b
}

터미널에서 ./gradlew ktlint를 수행하면 다음과 같이 검사 결과와 문제가 있는 부분이 표시됩니다.

$ ./gradlew ktlint
:app:ktlint
.../Calculator.kt:3:1: Unused import
.../Calculator.kt:7:1: Unexpected indentation (9)
.../Calculator.kt:7:39: Missing spacing before "{"
.../Calculator.kt:9:1: Needless blank line(s)
.../Calculator.kt:10:21: Unnecessary semicolon
.../Calculator.kt:13:20: Missing spacing after ","
.../Calculator.kt:13:22: Missing spacing after ":"
.../Calculator.kt:13:32: Missing spacing around "="
.../Calculator.kt:13:34: Missing spacing around "-"
:app:ktlint FAILED

check 태스크가 실행되는 경우 ktlint 태스크가 함께 실행되도록 설정하였으므로, ./gradlew check 명령을 수행하거나 일반적인 빌드 명령(./gradlew build)을 수행할 때에도 위 태스크가 함께 수행됩니다.

스타일에 맞게 자동 수정하기 (ktlintFormat)

./gradlew ktlintFormat 을 수행하면 스타일에 맞지 않는 부분을 자동으로 수정합니다. 단, 일부 자동으로 수정하지 않은 부분에 대해선 경고 메시지를 표시합니다.

$ ./gradlew ktlintFormat
:app:ktlintFormat
.../Calculator.kt:3:18: Wildcard import
.../Calculator.kt:7:1: Unexpected indentation (9)

BUILD SUCCESSFUL

포매터가 수정한 코드는 다음과 같습니다.

[Calculator.kt]

package com.androidhuman.example.ktlintsample

import java.util.*

class Calculator {

         fun add(a: Int, b: Int) : Int {
        return a + b
    }

    fun sub(a: Int, b: Int) : Int = a - b
}

경고로 표시된 부분을 제외한 다른 항목의 스타일 오류가 수정되었습니다. (단, 수정되지 않는 항목이 버그 때문인지는 아직 확인 불가)

업데이트: 2016/09/07

검사 유형에 따라 자동 수정 지원 여부가 다릅니다.

검사 유형에 따라 ktlintFormat을 사용한 자동 수정 지원 여부가 다릅니다. 검사 유형별 자동 수정 지원 여부는 다음과 같습니다.

이름 검사 항목 자동 수정 지원
IndentationRule 인덴트 X
NoConsecutiveBlankLinesRule 연속된 개행 O
NoMultipleSpacesRule 연속된 공백 문자 O
NoSemicolonsRule 세미콜론 사용 O
NoUnusedImportsRule 미사용 import 문 존재 O
NoWildcardImportsRule 와일드 카드 import 문 (import foo.*) 사용 X
SpacingAfterCommaRule 콤마(,) 뒤 공백 존재 O
SpacingAfterKeywordRule 키워드 뒤 공백 존재 O
SpacingAroundColonRule 콜론(:) 앞뒤로 공백 존재 O
SpacingAroundCurlyRule 중괄호({}) 앞뒤로 공백 존재 O
SpacingAroundOperatorsRule 연산자 앞뒤로 공백 존재 O

사용자 정의 규칙 지원

0.2.0 버전으로 업데이트 되면서 사용자 정의 규칙을 사용할 수 있게 되었습니다.

사용자 정의 규칙이 필요하신 분들은 관련 문서를 참고하시면 됩니다.

예제 코드

이 프로젝트에서 사용한 예제 코드는 다음 저장소에서 확인할 수 있습니다.

kunny

커니

안드로이드와 오픈소스, 코틀린(Kotlin)에 관심이 많습니다. 한국 GDG 안드로이드 운영자 및 GDE 안드로이드로 활동했으며, 현재 구글에서 애드몹 기술 지원을 담당하고 있습니다.

Read More