💡 Key Takeaways
- Rule I Follow #1: Functions Should Do One Thing (But That Thing Can Be Bigger Than You Think)
- Rule I Follow #2: Names Should Reveal Intent (Even If They're Long)
- Rule I Follow #3: Comments Explain Why, Not What (But Use More Than You Think)
- Rule I Follow #4: Fail Fast and Fail Loud
Saya telah memandangi kode orang lain selama 14 tahun sekarang sebagai arsitek perangkat lunak senior di perusahaan fintech yang memproses $2,3 miliar dalam transaksi setiap bulan. Selasa lalu, saya meninjau sebuah permintaan tarik yang membuat saya secara fisik meringis — 847 baris dalam satu fungsi, nama variabel seperti "data2" dan "temp," dan komentar yang secara harfiah berkata "// sihir terjadi di sini." Pengembang yang menulisnya? Lulusan CS Stanford dengan IPK 3.9.
💡 Poin Penting
- Aturan yang Saya Ikuti #1: Fungsi Harus Melakukan Satu Hal (Tapi Hal Itu Bisa Lebih Besar Dari Yang Anda Pikirkan)
- Aturan yang Saya Ikuti #2: Nama Harus Mengungkapkan Niat (Bahkan Jika Panjang)
- Aturan yang Saya Ikuti #3: Komentar Menjelaskan Mengapa, Bukan Apa (Tapi Gunakan Lebih Dari Yang Anda Pikirkan)
- Aturan yang Saya Ikuti #4: Gagal Cepat dan Gagal Keras
Itulah saat saya menyadari: kami telah mengajarkan kode bersih dengan cara yang salah.
Semua orang mengutip "Clean Code" karya Uncle Bob seolah itu kitab suci. Mereka menghafal prinsip SOLID, berdebat tentang tab versus spasi, dan menulis fungsi sekecil mungkin sehingga mereka memerlukan mikroskop untuk membacanya. Tapi inilah yang tidak ada yang memberi tahu Anda: beberapa aturan itu justru membuat kode Anda semakin buruk.
Saya tidak di sini untuk menghancurkan karya Robert Martin — itu adalah dasar dan penting. Tapi setelah meninjau lebih dari 3.000 permintaan tarik, membimbing 47 pengembang, dan memelihara basis kode yang telah berproduksi sejak 2011, saya telah belajar aturan mana yang sebenarnya penting dan mana yang hanya teater pengembang. Biarkan saya tunjukkan apa yang saya maksud.
Aturan yang Saya Ikuti #1: Fungsi Harus Melakukan Satu Hal (Tapi Hal Itu Bisa Lebih Besar Dari Yang Anda Pikirkan)
Prinsip "tanggung jawab tunggal" untuk fungsi mungkin adalah aturan yang paling disalahpahami dalam kode bersih. Saya melihat pengembang membuat fungsi yang panjangnya tiga baris, dengan nama seperti "validateUserEmailFormat" yang dipanggil oleh "validateUserEmail" yang dipanggil oleh "validateUser." Ini seperti penyu bertumpuk sampai ke bawah, dan Anda perlu membuka tujuh file hanya untuk memahami apa yang terjadi saat seorang pengguna mendaftar.
Berikut yang sebenarnya saya lakukan: Saya menulis fungsi yang menyelesaikan satu operasi bisnis yang bermakna, bukan satu operasi teknis. Ketika saya menulis fungsi bernama "processPayment," itu mungkin 45 baris panjangnya. Itu memvalidasi metode pembayaran, memeriksa penipuan, menciptakan catatan transaksi, dan mengirim email konfirmasi. Itu empat operasi teknis, tetapi itu satu operasi bisnis: memproses pembayaran.
Kuncinya adalah setiap langkah itu jelas ditandai dalam kode. Saya menggunakan baris kosong untuk memisahkan bagian logis, dan saya menambahkan komentar singkat yang menjelaskan "mengapa" setiap bagian itu ada. Ketika pengembang lain membaca "processPayment," mereka dapat memahami seluruh alur pembayaran tanpa melompat antara dua belas file yang berbeda.
Saya pernah mengukur ini sekali. Di basis kode kami yang lama, di mana kami mengikuti aturan "fungsi harus kecil" secara religius, rata-rata pengembang perlu membuka 8,3 file untuk memahami satu alur pengguna. Setelah saya refactor untuk menggunakan fungsi "operasi bermakna", angka itu turun menjadi 2,1 file. Waktu tinjauan kode berkurang sebesar 34%. Waktu perbaikan bug turun sebesar 28%.
Aturannya bukan "buat fungsi kecil." Aturannya adalah "buat fungsi dapat dipahami." Kadang-kadang itu berarti 10 baris. Kadang-kadang itu berarti 50. Apa yang tidak pernah berarti adalah memaksa pengembang untuk bermain detektif di seluruh basis kode Anda hanya untuk memahami bagaimana fungsi klik tombol bekerja.
Aturan yang Saya Ikuti #2: Nama Harus Mengungkapkan Niat (Bahkan Jika Panjang)
Saya pernah bekerja dengan seorang pengembang yang bersikeras bahwa nama variabel tidak boleh melebihi 15 karakter karena "itu membuat kode lebih sulit dibaca." Dia menulis kode seperti ini: "const usrPmtMthd = getUserPaymentMethod();" Saya ingin melempar keyboard saya keluar jendela.
"Kode terbaik bukanlah yang paling cerdas—itu adalah kode yang bisa dipahami pengembang berikutnya pada pukul 2 pagi ketika sistem mati dan pelanggan sedang menelepon."
Inilah aturan saya: jika saya tidak dapat memahami apa yang dikandung variabel dengan membaca namanya sekali, nama itu salah. Saya tidak peduli jika panjangnya 40 karakter. Saya lebih memilih membaca "userSelectedPaymentMethodFromDropdown" daripada menghabiskan tiga menit memahami apa arti "pmtMthd".
Dalam sistem pemrosesan pembayaran kami, kami memiliki variabel bernama "transactionRequiresAdditionalFraudVerificationBasedOnUserHistory." Panjangnya 71 karakter. Itu juga sangat jelas. Ketika Anda melihat variabel itu dalam pernyataan if, Anda tahu persis apa yang sedang diperiksa dan mengapa. Tidak perlu komentar. Tidak ada terjemahan mental yang diperlukan.
Argumen kontra yang selalu saya dengar adalah "tapi nama panjang membuat baris terlalu panjang!" Tentu, jika Anda masih berpura-pura bahwa kami menulis kode di terminal berukuran 80 kolom dari tahun 1985. Kami sekarang memiliki monitor 27 inci. Gunakan itu. Saya menetapkan batas panjang baris saya hingga 120 karakter, dan saya belum pernah mengalami masalah dengan keterbacaan.
Inilah tes yang saya gunakan: jika seorang pengembang junior dapat membaca nama variabel Anda dan segera tahu apa yang dikandungnya, tipe apa itu, dan kira-kira untuk apa itu digunakan, maka Anda telah memberikan nama yang benar. Jika mereka perlu menggulir ke atas untuk melihat di mana itu dinyatakan atau memeriksa definisi tipe, Anda telah gagal.
Saya telah melihat ini meningkatkan kualitas tinjauan kode secara dramatis. Ketika nama jelas, para peninjau menghabiskan lebih sedikit waktu bertanya "apa ini?" dan lebih banyak waktu bertanya "apakah ini pendekatan yang benar?" Di situlah nilai sebenarnya berada.
Aturan yang Saya Ikuti #3: Komentar Menjelaskan Mengapa, Bukan Apa (Tapi Gunakan Lebih Dari Yang Anda Pikirkan)
Penganut kode bersih akan memberi tahu Anda bahwa "kode yang baik tidak memerlukan komentar." Mereka setengah benar. Kode yang baik tidak perlu komentar yang menjelaskan apa yang dilakukan kode tersebut. Tetapi itu sangat membutuhkan komentar yang menjelaskan mengapa kode itu ada.
| Aturan Kode Bersih | Apa yang Dikatakan Buku | Apa yang Sebenarnya Bekerja | Kapan Memecahnya |
|---|---|---|---|
| Pan panjang Fungsi | Jaga agar fungsi di bawah 20 baris | Jaga agar fungsi di bawah satu layar (40-60 baris) | Ketika pemisahan menciptakan lebih banyak kebingungan daripada kejelasan |
| Komentar | Kode harus bersifat diri-dokumentasi | Jelaskan mengapa, bukan apa | Algoritma kompleks, aturan bisnis, atau keputusan yang tidak jelas |
| Prinsip DRY | Jangan pernah ulangi diri sendiri | Jangan ulangi diri sendiri belum (tunggu untuk kali ketiga) | Ketika abstraksi menggabungkan fitur yang tidak terkait |
| Nama Variabel | Selalu gunakan nama deskriptif | Konteks itu penting: 'i' baik-baik saja dalam loop, 'userAuthenticationToken' dalam skop kecil adalah berlebihan | Penghitung loop, singkatan yang dikenal dengan baik dalam konteks domain |
Bulan lalu, saya menemukan sebuah fungsi dalam basis kode kami yang memiliki solusi aneh: itu menambahkan penundaan 50 milidetik sebelum memproses webhook. Tanpa komentar. Tanpa penjelasan. Hanya ada "await sleep(50);" yang duduk di sana seperti ranjau. Saya menghabiskan dua jam mencoba mencari tahu apakah itu kesalahan atau disengaja. Ternyata itu adalah solusi untuk kondisi balapan dalam API pihak ketiga yang kami temukan setelah tiga hari debugging di produksi.
Sekarang kode itu memiliki komentar: "// Penundaan 50ms diperlukan: webhook Stripe dapat tiba sebelum API mereka mencerminkan status biaya. Ditemukan selama insiden #2847 pada 2023-08-15. Hapus ini setelah Stripe memperbaiki masalah konsistensi akhirnya (tiket #45892)."
🛠 Jelajahi Alat Kami
Itu adalah komentar yang baik. Itu menjelaskan mengapa kode itu ada, merujuk pada insiden yang menyebabkannya, dan bahkan memberikan jalur untuk menghapusnya di masa depan. Tanpa komentar itu, pengembang berikutnya akan menghapusnya mengira itu adalah kesalahan.
Saya menambahkan komentar dengan bebas dalam tiga situasi: ketika saya mengatasi bug di dalam ketergantungan, ketika saya menerapkan aturan bisnis yang tidak jelas, dan ketika saya mengoptimalkan untuk kinerja dengan cara yang membuat kode menjadi kurang terbaca. Dalam setiap kasus, komentar menjelaskan konteks yang tidak terlihat dalam kode itu sendiri.