Skip to main content
simplified northern lights aurora visualizationNur Arif

Clean Code Bukan Soal Rapi, Ini Buktinya dari Lapangan

Agustus 2026

Saya selalu curiga kalau ada tim yang bilang kodenya sudah “clean code” hanya karena sudah diformat rapi oleh Prettier. Rapi dan bersih itu dua hal yang berbeda. Kode bisa terlihat rapi tapi tetap menjadi mimpi buruk bagi orang lain yang harus membacanya enam bulan kemudian. Masalahnya bukan estetika. Masalahnya adalah: bisakah developer lain—yang bukan penulis aslinya—membaca, memahami, dan mengubah kode itu tanpa harus bertanya ke Slack setiap lima menit? Kalau jawabannya tidak, sebagus apa pun indentasinya, kode itu belum clean code. Artikel ini bukan daftar checklist generik. Ini kumpulan prinsip yang sudah teruji lintas bahasa pemrograman, lintas tim, dan lintas dekade, disusun ulang dengan konteks nyata supaya masuk akal dipraktikkan, bukan sekadar dihafal.

Musuh yang Sebenarnya: Kode yang Butuh Penerjemah

Setiap tulisan yang bagus punya musuh. Musuh saya di sini adalah kode yang butuh “penerjemah”—biasanya penulis aslinya sendiri—untuk bisa dipahami tim. Begitu penulis itu resign atau pindah proyek, kode itu berubah jadi kotak hitam yang ditakuti semua orang.

Saya pernah menangani modul billing yang ditulis satu orang senior selama tiga tahun. Variabelnya bernama d, flag2, tmpData. Tidak ada komentar, tidak ada penjelasan kenapa ada percabangan aneh di baris 340. Butuh dua minggu penuh hanya untuk berani mengubah satu baris tanpa memicu bug produksi.

Itulah kenapa aturan paling dasar dari clean code sebenarnya sederhana: ikuti konvensi standar, jaga kesederhanaan, dan selalu tinggalkan kode lebih bersih daripada saat kamu menemukannya—prinsip yang biasa disebut “boy scout rule”. Kalau kamu menyentuh sebuah fungsi untuk menambah fitur, rapikan sedikit di sekitarnya sebelum pergi.

Satu lagi yang sering dilupakan: kalau ada bug, jangan hanya tempel patch di gejalanya. Cari akar masalahnya. Patch tanpa investigasi akar masalah hanya menunda ledakan berikutnya.

Nama Variabel Itu Dokumentasi Gratis

Coba bayangkan kamu diminta memahami fungsi tanpa membaca isinya, hanya dari namanya dan nama variabel di dalamnya. Kalau itu mustahil, penamaan kamu bermasalah.

Beberapa aturan penamaan yang paling sering dilanggar justru yang paling murah untuk diperbaiki:

AturanContoh BurukContoh Baik
Deskriptif dan jelasdelapsedDays
Bisa diucapkangenymdhmsgenerationTimestamp
Bisa dicariangka 86400 tersebar di kodekonstanta SECONDS_PER_DAY
Tanpa embel-embel tipestrName, iCountname, count

Poin soal angka ajaib (magic number) ini kelihatan sepele, tapi dampaknya besar. Saya pernah debugging sistem cache selama setengah hari hanya karena angka 3600 muncul di lima tempat berbeda dengan makna yang ternyata berbeda-beda—satu untuk TTL cache, satu untuk timeout request. Kalau semua diberi nama konstanta sejak awal, bug itu tidak akan pernah lahir.

Coba terapkan aturan ini di satu file lama kamu minggu ini, lalu lihat sendiri berapa banyak “aha, ternyata variabel ini maksudnya begini” yang muncul.

Fungsi Kecil Bukan Obsesi, Tapi Kebutuhan

Ada anggapan keliru bahwa memecah fungsi jadi kecil-kecil itu berlebihan, hanya menambah lompatan saat membaca kode. Kenyataannya kebalikannya: fungsi besar memaksa otak menyimpan terlalu banyak konteks sekaligus, dan itu yang membuat bug bersembunyi.

Fungsi yang sehat punya empat ciri yang saling terkait:

  1. Kecil—idealnya bisa dibaca tanpa scroll.
  2. Melakukan satu hal saja—kalau namanya butuh kata “dan” untuk dijelaskan, pecah jadi dua fungsi.
  3. Argumennya sedikit—lebih dari tiga parameter biasanya tanda fungsi itu melakukan terlalu banyak hal.
  4. Tanpa flag argument—parameter boolean seperti isEdit yang mengubah perilaku fungsi secara drastis sebaiknya dipecah jadi dua fungsi terpisah, bukan satu fungsi dengan percabangan di dalamnya.

Saya pernah menulis fungsi saveUser(user, bool sendEmail) yang kelihatannya efisien. Enam bulan kemudian, ada kebutuhan baru: kirim email tapi dengan template berbeda untuk user korporat. Karena logikanya sudah bercampur lewat flag, saya harus menambah flag kedua, lalu ketiga. Fungsi itu akhirnya jadi rawa logika if-else yang tidak bisa ditest per skenario.

Kalau kamu pernah menemukan diri sendiri menambah parameter boolean ke fungsi yang sudah ada, itu sinyal untuk berhenti dan memecahnya sekarang, bukan nanti.

Komentar yang Berguna vs Komentar yang Bohong

Saya tidak pernah percaya dengan orang yang bilang “kode saya self-explanatory, tidak butuh komentar sama sekali.” Itu ekstrem yang sama bahayanya dengan kode penuh komentar berlebihan.

Yang benar ada di tengah. Komentar seharusnya menjelaskan intent—kenapa sebuah keputusan diambil, bukan apa yang dilakukan baris kode itu, karena baris kode itu sendiri sudah cukup jelas kalau ditulis benar. Komentar juga berguna sebagai peringatan konsekuensi, misalnya “jangan ubah urutan ini, race condition kalau dibalik.”

Yang harus dihindari:

  • Komentar yang hanya mengulang apa yang sudah jelas dari kode (// tambah 1 ke count di atas count++).
  • Kode yang di-comment-out “siapa tahu dipakai lagi”. Kalau butuh riwayatnya, itu tugas Git, bukan komentar mati di tengah file.
  • Komentar penutup blok seperti // end of for loop, yang sebenarnya menandakan bloknya terlalu panjang untuk dibaca tanpa penanda.

Aturan sederhananya: kalau kamu merasa perlu menambah komentar untuk menjelaskan kode yang membingungkan, coba dulu tulis ulang kodenya supaya tidak membingungkan. Komentar itu solusi kedua, bukan solusi pertama.

Struktur, Objek, dan Jebakan “Setengah Objek Setengah Data”

Di level yang lebih tinggi dari fungsi individual, ada masalah struktural yang lebih mahal untuk diperbaiki belakangan. Salah satu yang paling sering saya temui di code review: struktur hybrid, yaitu class yang setengah menyembunyikan data lewat method, tapi setengah lagi mengekspos field publik langsung.

Hybrid ini terlihat “praktis” di awal karena cepat ditulis, tapi ujung-ujungnya menyulitkan dua hal sekaligus: sulit ditambah fungsi baru (karena struktur data terekspos ke mana-mana) dan sulit ditambah struktur data baru (karena logikanya sudah menempel ke representasi lama).

Prinsip praktis yang bisa dipegang:

  • Sembunyikan struktur internal. Class seharusnya mengekspos perilaku, bukan field mentahnya.
  • Class kecil dengan sedikit instance variable. Kalau sebuah class butuh lebih dari segenggam variabel untuk dijelaskan, kemungkinan besar dia melakukan terlalu banyak tanggung jawab.
  • Base class jangan pernah tahu soal turunannya. Begitu base class mulai punya if (this instanceof ChildA), arsitektur pewarisan itu sudah bocor dan perlu dirombak.
  • Ikuti Law of Demeter—sebuah objek sebaiknya hanya “bicara” dengan tetangga langsungnya, bukan memanggil rantai panjang seperti a.getB().getC().doSomething(). Rantai panjang seperti ini adalah tanda class kamu tahu terlalu banyak soal internal class lain.

Kalau kamu sedang membangun fitur baru minggu ini, coba cek: apakah ada rantai pemanggilan lebih dari dua titik di kode kamu? Kalau ada, itu titik awal yang bagus untuk direfactor.

Kenali Enam Bau Busuk Sebelum Jadi Bencana

Sebelum bug besar muncul, biasanya ada tanda-tanda kecil yang sudah terlihat lama sebelumnya. Dalam dunia software, tanda-tanda ini disebut “code smell”, dan enam yang paling umum ini layak ditempel di dinding tim:

  • Rigidity—perubahan kecil memicu efek domino ke banyak file lain.
  • Fragility—satu perubahan membuat bagian lain yang tidak berhubungan ikut rusak.
  • Immobility—kode bagus tapi tidak bisa dipindah ke proyek lain karena terlalu menempel ke konteks spesifik.
  • Needless complexity—solusi rumit untuk masalah yang sebenarnya sederhana.
  • Needless repetition—logika yang sama ditulis ulang di banyak tempat, padahal cukup sekali lalu dipanggil ulang.
  • Opacity—kode yang butuh waktu lama untuk sekadar dipahami maksudnya, apalagi diubah.

Enam ini bukan daftar untuk dihafal sekali lalu dilupakan. Enam ini alat diagnosis. Setiap kali code review terasa lama dan berat, coba cocokkan: kode itu kena smell yang mana?

Test yang Sehat Sama Pentingnya dengan Kode Produksi

Satu bagian yang sering diabaikan padahal setara pentingnya: kualitas kode di dalam file test. Test yang buruk memberi rasa aman palsu—hijau di CI, tapi sebenarnya tidak menguji apa-apa yang berarti.

Test yang sehat punya empat sifat: cepat dijalankan, bisa diulang dengan hasil sama, tidak bergantung pada test lain, dan mudah dibaca. Satu kebiasaan kecil yang sangat membantu keterbacaan adalah membatasi satu assertion utama per test—begitu satu test memvalidasi lima hal sekaligus, kegagalannya jadi susah ditelusuri penyebab pastinya.

Coba jalankan satu test suite lama kamu dan hitung berapa banyak test yang punya lebih dari satu assertion tak berhubungan. Kalau jumlahnya banyak, itu bukan salah penulisnya dulu—itu utang teknis yang wajar diperbaiki bertahap, bukan sekaligus.

Kenapa Semua Ini Penting Lebih dari Sekadar “Rapi”

Radikal rasanya bilang bahwa kualitas kode adalah investasi jangka panjang, tapi setelah dipikir ulang, ini sebenarnya akal sehat yang selama ini diabaikan tim yang terburu-buru kejar deadline. Kode yang mudah dipahami itu bukan kemewahan tim besar dengan waktu luang—itu justru yang menyelamatkan tim kecil dengan waktu sempit, karena setiap jam yang dihabiskan menerka maksud kode lama adalah jam yang hilang dari membangun fitur baru.

Saya tidak pernah menyarankan tim untuk berhenti coding lalu menghabiskan satu sprint penuh cuma untuk refactor besar-besaran. Yang lebih realistis: terapkan boy scout rule konsisten, perbaiki penamaan setiap kali menyentuh file lama, dan pecah fungsi besar begitu terasa sulit dibaca ulang. Perubahan kecil yang konsisten jauh lebih tahan lama dibanding proyek “bersih-bersih total” yang biasanya mati di tengah jalan karena prioritas berubah.

Coba pilih satu file yang paling kamu takuti untuk disentuh minggu ini, lalu terapkan tiga aturan dari artikel ini—penamaan jelas, fungsi kecil, dan hilangkan komentar basi. Bagikan hasilnya ke tim kamu, dan lihat sendiri berapa banyak pertanyaan di code review berikutnya yang tidak perlu lagi diajukan.