소스 코드를 실제로 실행하지 않고 코드를 분석하는 디버깅 방법을 말한다. 반대로 동적 분석은 소스 코드를 실제로 실행하여 코드를 분석하는 디버깅 방법을 말한다.
BASIS FOR COMPARISON | STATIC TESTING | DYNAMIC TESTING |
---|---|---|
Basic | Does not execute the software | Execution of the software is necessary |
Cost | Low | High |
Statement coverage | 100% | 50% |
Time consumption | Less | More |
Uncovers | Large variety of bugs | Limited types of bugs |
Performed | Before compilation | Only when executables are available |
개발자가 리뷰를 할 수 있는 속도엔 한계가 있다. 일정을 진행하기에 바쁜데 개발된 코드들을 전부 직접 검토한다면 소요되는 시간이 많을 것이다. 이러한 문제를 자동화 도구로 빠르게 해결할 수 있으며, 어디에 문제가 있는지 표시를 해주기 때문에 에러를 빠르게 고칠 수 있다.
개발자가 모든 실행 경로를 직접 확인하기는 힘들 것이다. 하지만 분석 도구는 그러한 심층 분석을 손쉽게 할 수 있다.
코드 리뷰는 사람의 착오가 생길 수가 있다. 분석 도구를 이용하면 정해진 규칙과 기준에 따라 분석을 하기 때문에 착오가 발생하지는 않는다.
애플리케이션 보안을 강화하여 DevOps의 보안을 강화할 수 있다.
Kotlin 언어에 대한 정적 분석 도구로는 대표적으로 Android Lint, Detekt, ktlint의 세가지가 있다.
Java 언어에 대한 정적 분석 도구로 주로 사용되지만, SonarQube에서도 설정을 통해 Kotlin 언어에 대한 정적 분석을 수행할 수 있다.
정적 분석 도구에도 아래와 같이 한계가 존재한다. 이는 팀원과의 코드 리뷰를 통해서 해결해야한다.
본 가이드는 Kotlin DSL로 작성된 Spring Boot + Gradle 프로젝트를 기준으로 한다.
root 디렉토리에 존재하는 build.gradle.kts 에 아래의 종속성을 추가한다.
자세한 설명이 궁금하다면 Run detekt using the Detekt Gradle Plugin | A static code analyzer for Kotlin 를 참고하도록 한다.
plugins {
id("io.gitlab.arturbosch.detekt").version("1.19.0")
}
repositories {
mavenCentral()
// 중요! 정적 분석 이후 report로 출력하기 위해서는 아래의 repository 주소를 추가로 등록해주어야 한다. // 등록해주지 않은 경우 아래에 후술할 detekt 작업이 동작하지 않는다.
// 이슈에 대해 상세한 원인이 궁금하다면 https://github.com/detekt/detekt/issues/3461 를 참고하도록 한다.
maven("https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven")
}
이 때 버전은 Compatibility Table | A static code analyzer for Kotlin 을 참고하여 지정하도록 한다.
위 과정을 완료하고 gradle reload까지 진행하면, 인텔리제이 기준 우측 gradle - Tasks - verification 탭에서 아래 사진과 같이 detekt 작업을 볼 수 있다.
만약 커맨드로 실행하고 싶다면 아래와 같이 터미널에 입력하면 된다(물론 실행권한이 부여되어 있어야 한다).
./gradlew detekt
detekt 작업을 실행했을 때, code style, performance 등등.. 문제의 소지가 발생할 수 있는 지점들이 존재하면 아래 사진과 같이 실패한다.
분석에 대한 결과 리포트는 기본적으로 build/reports/detekt
디렉토리에 존재한다. 확장자의 종류로는 html, txt, xml, sarif 가 있다.
분석 결과로는 콘솔에 출력되는 로그와 분석 결과 리포트로 생성되는 파일이 있다. 기본적으로 지정되는 분석 결과 생성 디렉토리인 build/reports/detekt 의 detekt.html 파일을 열어보면 아래와
같이 나오며, Metrics(측정 기준), Complexity Report(복잡성 보고서), Findings(발견한 취약점의 수) 을 확인할 수 있으며, 이유와 함께 표시해준다.
이때 표시되는 취약점의 원인들에 대해서, 설정 파일을 통해 제한 조건을 지정해줄 수 있다.
설정 항목에 대해 자세한 내용은 detekt의 메뉴중, Rule Sets
를 참고하도록 한다.
detekt 작업은 gradle의 check
task 실행시에 기본적으로 수행되도록 설정되어 있는 검사 작업이다. 하지만 상황에 따라서는 점진적으로 코드 품질을 높이고 싶을 수가 있다. 이럴 경우에 아래
script를 build.gradle.kts에 작성하면 detekt 작업을 gradle이 수행하는 check task 실행시에 실행되지 않도록 비활성화 할 수 있다.
tasks.named("check").configure {
this.setDependsOn(this.dependsOn.filterNot {
it is TaskProvider <*> && it.name == "detekt"
})
}
하지만 만약 비활성화 대신, 약하지만 제한을 건다던지 설정을 해주고 싶다면 설정 파일(yml로 작성되는)에서 빌드시 실패하도록 만들 임계값을 설정해줄 수 있다. 이 외에도 검사 규칙과 같은 여러 가지 것들에 대한
설정들을 직접 지정할 수 있도록 지원하고 있는데, 자세한 내용은 Detekt Configuration File 를 참고하도록 한다.
버전 관리 시스템으로 Git을 사용하고 있다면, Commit 시에 hook을 발생시키도록 하여 검사를 수행할 수 있다. Detekt 에서는 Git Commit 시에 사용자 지정 스크립트를 자동으로 실행하는 방식으로
이를 지원해준다.
아래는 Run detekt using a Git pre-commit hook | A static code analyzer for Kotlin 에서 제공해주는, Git Commit 시에 실행될 스크립트 예제이다.
# !/usr/bin/env bash
echo "Running detekt check..."
OUTPUT="/tmp/detekt-$(date +%s)"
./gradlew detekt > $OUTPUT
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
cat $OUTPUT rm $OUTPUT
echo "***********************************************"
echo " Detekt failed "
echo " Please fix the above issues before committing "
echo "***********************************************"
exit $EXIT_CODE
fi
rm $OUTPUT
가령, 위 스크립트를 복사해서 <<your-repo>>/.git/hooks/pre-commit
디렉토리에 설치하여 사용할 수 있다. 단, 이 스크립트는 실행가능한 파일이어야 하므로 사용 권한의
변경(chmod +x pre-commit
)이 필요하다.
Git Hooks 에 대해서 더 알아보고 싶다면 Git Hooks | Atlassian Git Tutorial 를 참고하도록 한다.
Detekt는 인텔리제이 플러그인도 지원하고 있다.
우선, Preferences → Plugins 에서 Detekt 플러그인을 설치한다.
Preferences → Tools → Detekt 항목에서 플러그인에 대한 설정을 진행할 수 있으며, 원한다면 설정 파일을 직접 지정해줄 수 있다.
각각의 옵션들에 대한 설명은 아래와 같다.