Step 12 of 13
Kotlin naming and style conventions, Detekt static analysis, ktlint formatting, CI integration
Coding conventions ของ Kotlin และ static analysis ด้วย Detekt และ ktlint
Follow these conventions to write Kotlin that other developers expect to read.
// Classes and interfaces: PascalCase
class UserRepository { }
interface Readable { }
// Functions and variables: camelCase
fun calculateTotal() { }
val userName = "Alice"
// Constants: SCREAMING_SNAKE_CASE or camelCase
const val MAX_RETRIES = 3
const val defaultPort = 8080
// Packages: lowercase, no underscores
package com.example.userservice
// Good — read-only, safe
val users = listOf("Alice", "Bob")
// Avoid unless you need to change it
var count = 0
// Good — clean one-liner
fun isAdult(age: Int): Boolean = age >= 18
// Fine for longer functions
fun process(data: String): String {
val cleaned = data.trim()
val upper = cleaned.uppercase()
return upper
}
// Good — auto-generates equals, hashCode, toString, copy
data class Product(val id: Int, val name: String, val price: Double)
// Avoid — manual boilerplate when a data class works
class Product(val id: Int, val name: String, val price: Double) {
override fun equals(other: Any?): Boolean { /* ... */ }
override fun hashCode(): Int { /* ... */ }
}
// Configure with apply
val server = Server().apply {
host = "localhost"
port = 8080
timeout = 30
}
// Null-safe transformation with let
val email: String? = getEmail()
val domain = email?.let { it.substringAfter("@") }
Detekt finds code smells, style violations, and potential bugs.
Add to your build.gradle.kts:
plugins {
kotlin("jvm") version "2.4.10"
id("io.gitlab.arturbosch.detekt") version "1.23.8"
}
repositories {
mavenCentral()
}
./gradlew detekt
Detekt checks your code and prints issues:
src/main/kotlin/UserService.kt:15:1
ComplexMethod [Complexity: 12] — method doEverything is too complex
Create config/detekt.yml to customize rules:
complexity:
LongMethod:
threshold: 60 # max lines per function (default: 60)
LongParameterList:
functionThreshold: 6 # max params per function (default: 6)
ComplexCondition:
threshold: 4 # max conditions in one if (default: 4)
style:
MaxLineLength:
maxLineLength: 120 # max characters per line
WildcardImport:
active: true # ban import com.example.*
Run with the config:
./gradlew detekt --config config/detekt.yml
| Rule | What it catches |
|---|---|
ComplexMethod | Functions with too many branches |
LongParameterList | Functions with too many parameters |
LargeClass | Classes with too many lines |
WildcardImport | import x.* instead of specific imports |
MagicNumber | Unnamed numeric literals |
ReturnCount | Too many return statements |
SwallowedException | Empty catch blocks |
@Suppress("MagicNumber")
fun calculateFibonacci(n: Int): Int {
if (n <= 1) return n // MagicNumber suppressed
return calculateFibonacci(n - 1) + calculateFibonacci(n - 2)
}
Detekt finds code smells. ktlint checks formatting (spacing, indentation, imports). Use both together:
plugins {
id("org.jlleitschuh.gradle.ktlint") version "12.3.0"
}
Auto-format your code:
./gradlew ktlintFormat
Add detekt to your CI pipeline (GitHub Actions, GitLab CI) to catch issues before merge:
# .github/workflows/ci.yml
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- run: ./gradlew detekt test
The build fails if Detekt finds issues or tests fail.
Apply these to your code:
val unless mutation is neededconst val or named parametersimport x.*)./gradlew detekt with zero issues./gradlew ktlintFormat to auto-fix style