Kode ditulis sekali tetapi dibaca ratusan kali. Setiap developer yang membaca kode kita — termasuk diri kita sendiri tiga bulan ke depan — perlu memahami dengan cepat apa yang kode lakukan dan mengapa. Clean code bukan sekadar “kode rapi”; ia adalah kode yang dirancang untuk dibaca manusia terlebih dahulu, baru kemudian kompilator. Pada chapter ini kita akan membahas empat pilar clean code: penamaan bermakna, fungsi kecil, single responsibility, dan komentar yang menjelaskan mengapa. Kode demo akan membandingkan versi buruk dan versi clean untuk topik yang sama.
Empat Pilar Clean Code #
- Meaningful names: nama variabel, fungsi, dan class harus mengungkapkan maksud.
- Small functions: fungsi idealnya 5-15 baris, paling banyak satu level indentasi per logical block.
- Single responsibility: setiap class dan fungsi melakukan satu hal.
- Comments explain why: komentar menjelaskan keputusan, bukan mengulang kode.
Kode Sebelum dan Sesudah #
Program berikut membandingkan kode buruk (nama ambigu, fungsi panjang, komentar what) dengan versi clean (nama jelas, fungsi kecil, komentar why).
// Demo clean code: meaningful names, small functions, single responsibility, comments explain why.
// === SEBELUM: nama buruk, fungsi panjang, komentar what ===
class Repo {
fun p(items: List<Map<String, Any>>): Double {
var t = 0.0
for (i in items) {
val p = i["price"] as Double
val q = i["qty"] as Int
t += p * q // hitung total
}
return t // kembalikan total
}
}
// === SETELAH: clean code ===
data class ItemKeranjang(val harga: Double, val jumlah: Int)
class KeranjangBelanja {
fun hitungTotal(items: List<ItemKeranjang>): Double {
return items.sumOf { it.harga * it.jumlah }
}
}
// === Single Responsibility: pisahkan perhitungan dari formatting ===
class PeringkasStruk {
fun ringkas(items: List<ItemKeranjang>, total: Double): String {
val daftarItem = items.joinToString("\n") { "- ${it.jumlah}x @ Rp${it.harga}" }
return "$daftarItem\nTotal: Rp$total"
}
}
// === Comments explain why, not what ===
class DiskonTahunan {
// Diskon dinaikkan dari 5% menjadi 10% pada 2026 untuk kompetisi dengan platform lain
// (lihat tiket PROJ-1234 untuk detail keputusan bisnis)
fun persentaseDiskon(tahun: Int): Double = if (tahun >= 2026) 0.10 else 0.05
}
fun main() {
println("=== Demo Clean Code ===")
// Versi sebelum
val repoLama = Repo()
val dataLama = listOf(
mapOf("price" to 15000.0, "qty" to 2),
mapOf("price" to 5000.0, "qty" to 3)
)
println("Versi sebelum (buruk): ${repoLama.p(dataLama)}")
println()
// Versi sesudah
val items = listOf(
ItemKeranjang(15000.0, 2),
ItemKeranjang(5000.0, 3)
)
val keranjang = KeranjangBelanja()
val total = keranjang.hitungTotal(items)
println("Versi sesudah (clean):")
println(PeringkasStruk().ringkas(items, total))
println()
val diskon = DiskonTahunan()
println("Diskon 2025: ${diskon.persentaseDiskon(2025)}")
println("Diskon 2026: ${diskon.persentaseDiskon(2026)}")
}Output yang Dihasilkan:
=== Demo Clean Code ===
Versi sebelum (buruk): 45000.0
Versi sesudah (clean):
- 2x @ Rp15000.0
- 3x @ Rp5000.0
Total: Rp45000.0
Diskon 2025: 0.05
Diskon 2026: 0.1Penamaan Bermakna #
Pada versi “sebelum”, Repo.p(items) tidak menjelaskan apa yang dilakukan. Nama p, t, i, q adalah noise. Pada versi “sesudah”, KeranjangBelanja.hitungTotal(items: List<ItemKeranjang>) langsung menjelaskan maksud: class KeranjangBelanja punya method hitungTotal yang menerima list ItemKeranjang. Aturan praktis:
- Pakai kata benda untuk class dan nilai:
Pengguna,KeranjangBelanja. - Pakai kata kerja untuk method:
hitungTotal,simpanPesanan. - Hindari singkatan:
mgrjadimanajer,cfgjadikonfigurasi. - Pakai nama domain:
Pesanan,Pelanggan,Faktur.
Fungsi Kecil #
Fungsi Repo.p melakukan tiga hal: iterasi, perhitungan, dan return. Pada versi clean, KeranjangBelanja.hitungTotal hanya menghitung total; formatting dipisah ke PeringkasStruk.ringkas. Fungsi kecil memiliki beberapa keuntungan:
- Mudah diberi nama yang akurat.
- Mudah di-test secara terpisah.
- Mudah dipahami tanpa scroll.
Single Responsibility #
Class Repo menggabungkan logika bisnis (menghitung total) dan struktur data (Map<String, Any>). Pada versi clean, ItemKeranjang adalah data class terpisah, KeranjangBelanja hanya menghitung, PeringkasStruk hanya memformat. Bila requirement berubah (mis. format struk ke HTML), hanya PeringkasStruk yang berubah.
Komentar: Why, Not What #
Komentar // hitung total di versi buruk tidak menambah informasi — kode sudah menjelaskan. Komentar yang bermakna adalah yang menjelaskan mengapa sesuatu dilakukan, mis. “Diskon dinaikkan ke 10% untuk kompetisi”. Komentar semacam ini menyimpan konteks bisnis yang tidak ada di kode.
Referensi Lanjutan #
- Kotlin coding conventions — konvensi penulisan Kotlin untuk nama function, struktur class, dan pemformatan yang mendukung clean code
Penutup #
Clean code adalah keterampilan yang berkembang dengan latihan dan review. Empat pilar — penamaan bermakna, fungsi kecil, single responsibility, dan komentar yang menjelaskan mengapa — adalah fondasi yang akan kita gunakan di seluruh chapter arsitektur berikutnya. Pada chapter berikutnya kita akan memperluas ke prinsip SOLID yang lebih formal.