Style yang konsisten membuat kode lebih mudah dibaca dan mengurangi perdebatan tak perlu dalam code review. Kotlin Coding Conventions dari JetBrains menetapkan standar yang diakui komunitas: indentasi 4 spasi, tanpa semicolon di akhir baris, panjang baris maksimum 120 karakter. ktlint dapat mengautomasi pemeriksaan dan perbaikan style. Pada chapter ini kita akan melihat kode yang konsisten dengan konvensi, lalu membangun simulasi pre-commit hook yang menjalankan ktlint secara otomatis sebelum commit.
Konvensi Utama Kotlin #
Berikut ringkasan konvensi yang penting:
| Aturan | Standar | Catatan |
|---|---|---|
| Indentasi | 4 spasi | Tidak boleh tab |
| Semicolon | Tidak wajib | Disarankan dihapus |
| Max line length | 100-120 karakter | Tergantung .editorconfig |
| Wildcard import | Hindari | Kecuali library khusus seperti Ktor |
| Brace style | Egyptian (kurung buka di akhir baris) | class Foo { bukan class Foo\n{ |
| Trailing comma | Disarankan untuk multi-baris | Memudahkan diff |
Demo Code Formatting #
Program berikut mendemonstrasikan kode yang sudah konsisten dengan konvensi, plus simulasi pre-commit hook yang menjalankan ktlintCheck dan ktlintFormat.
// Demo code formatting: konvensi 4 spasi, no semicolons, max 100/120 chars.
data class Item(val nama: String, val harga: Int)
class Keranjang {
private val isi = mutableListOf<Item>()
fun tambah(item: Item) {
isi.add(item)
}
fun total(): Int = isi.sumOf { it.harga }
fun ringkas(): String {
if (isi.isEmpty()) {
return "Keranjang kosong"
}
return isi.joinToString(separator = ", ") { "${it.nama}=${it.harga}" }
}
}
// Pre-commit hook simulasi: jalankan ktlintFormat sebelum commit
class GitHookSimulator {
private val log = mutableListOf<String>()
fun preCommit(kodeSumber: String): Boolean {
log.add("[hook] pre-commit dijalankan")
val violations = cek(kodeSumber)
if (violations.isEmpty()) {
log.add("[hook] ktlintCheck bersih, izinkan commit")
return true
}
log.add("[hook] ${violations.size} pelanggaran terdeteksi")
log.add("[hook] jalankan ktlintFormat untuk auto-fix")
val dibersihkan = format(kodeSumber)
val masihAda = cek(dibersihkan)
if (masihAda.isNotEmpty()) {
log.add("[hook] masih ada ${masihAda.size} manual violations; tolak commit")
return false
}
log.add("[hook] auto-fix berhasil; izinkan commit")
return true
}
private fun cek(sumber: String): List<String> {
val pelanggaran = mutableListOf<String>()
sumber.lines().forEachIndexed { i, b ->
if (b.endsWith(";")) pelanggaran.add("semicolon di baris ${i + 1}")
if (b.startsWith("\t")) pelanggaran.add("tab di baris ${i + 1}")
if (b.length > 100) pelanggaran.add("panjang baris ${i + 1}: ${b.length}")
}
return pelanggaran
}
private fun format(sumber: String): String =
sumber.lines().joinToString("\n") {
it.replace("\t", " ").trimEnd().removeSuffix(";")
}
fun log() = log.forEach(::println)
}
fun main() {
println("=== Demo Code Formatting ===")
val k = Keranjang()
k.tambah(Item("Buku", 15000))
k.tambah(Item("Pulpen", 5000))
k.tambah(Item("Penggaris", 3000))
println("Isi: ${k.ringkas()}")
println("Total: Rp${k.total()}")
println()
println("=== Simulasi pre-commit hook ===")
val kodeBaik = """
val a = 1
val b = 2
""".trimIndent()
val sim = GitHookSimulator()
println("--- Skenario kode bersih ---")
sim.preCommit(kodeBaik)
sim.log()
println()
println("--- Skenario kode kotor ---")
val sim2 = GitHookSimulator()
val kodeKotor = """
val a = 1;
val b = 2
\tval c = 3
""".trimIndent()
sim2.preCommit(kodeKotor)
sim2.log()
}Output yang Dihasilkan:
=== Demo Code Formatting ===
Isi: Buku=15000, Pulpen=5000, Penggaris=3000
Total: Rp23000
=== Simulasi pre-commit hook ===
--- Skenario kode bersih ---
[hook] pre-commit dijalankan
[hook] ktlintCheck bersih, izinkan commit
--- Skenario kode kotor ---
[hook] pre-commit dijalankan
[hook] 1 pelanggaran terdeteksi
[hook] jalankan ktlintFormat untuk auto-fix
[hook] auto-fix berhasil; izinkan commit.editorconfig #
File .editorconfig di root project memastikan editor (IntelliJ, VS Code, Vim) menggunakan konfigurasi yang sama. Contoh:
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{kt,kts}]
indent_size = 4
max_line_length = 120
ij_kotlin_imports_layout = *Pre-commit Hook #
Pre-commit hook memastikan style check dijalankan sebelum commit diterima. Setup dengan pre-commit framework (Python) atau via skrip shell sederhana di .git/hooks/pre-commit:
#!/bin/sh
echo "[pre-commit] menjalankan ktlintCheck"
./gradlew ktlintCheck
if [ $? -ne 0 ]; then
echo "[pre-commit] ktlint gagal; jalankan './gradlew ktlintFormat' lalu commit ulang"
exit 1
fi
exit 0Format on Save di IntelliJ #
IntelliJ memiliki opsi “Reformat code on save” (Settings > Tools > Actions on Save) yang menjalankan Ctrl+Alt+L otomatis setiap file disimpan. Opsi ini memastikan kode konsisten tanpa langkah manual. Aktifkan juga “Optimize imports on save” untuk membersihkan import yang tidak dipakai.
Referensi Lanjutan #
- ktlint — repository resmi ktlint untuk formatting otomatis kode Kotlin
Penutup #
Code formatting adalah hal yang sepertinya sepele tetapi berdampak besar pada konsistensi tim. Otomatisasi via ktlint dan pre-commit hook menghilangkan perdebatan style dari code review, sehingga reviewer dapat fokus pada masalah substantif: logic, design, dan kebenaran. Pada chapter terakhir section ini kita akan membahas code review practices yang membangun budaya kualitas kolaboratif.