Code Smell adalah tanda permukaan dalam kode yang menandakan potensi masalah dalam desain atau arsitektur aplikasi. Istilah ini diperkenalkan oleh Kent Beck dan dipopulerkan oleh Martin Fowler dalam buku “Refactoring: Improving the Design of Existing Code”. Menurut Martin Fowler, bau kode tidak selalu berarti bug, tetapi hampir selalu menunjukkan perlunya refactoring untuk meningkatkan kemudahan perawatan.
Utama
Code Smell (bau kode) — adalah metafora untuk gejala dalam kode sumber yang dengan probabilitas tinggi menunjukkan masalah yang lebih dalam. Istilah itu sendiri tidak memiliki definisi formal — ini adalah heuristik yang didasarkan pada pengalaman pengembang. Martin Fowler dan Kent Beck pada tahun 1999 untuk pertama kalinya mensistematisasikan 22 bau dalam buku “Refactoring”, dan sebagian besar masih relevan setelah puluhan tahun.
Penting untuk memahami perbedaan antara Code Smell dan bug. Bau bukanlah kesalahan: kode dikompilasi, berfungsi, dan memberikan hasil yang benar. Masalahnya adalah kode semacam itu sulit dibaca, diubah, dan diuji. Seiring waktu, biaya setiap perubahan meningkat, dan kepercayaan pada kebenaran refactoring menurun. Alat analisis statis (SonarQube, Detekt, SwiftLint) mendeteksi banyak bau secara otomatis.
Sifat heuristik Code Smell berarti tidak setiap metode panjang harus dipecah dan tidak setiap kelas besar memerlukan refactoring. Keputusan dibuat oleh pengembang, menilai konteks: frekuensi perubahan, kekritisan modul, rencana pengembangan. Insinyur berpengalaman mencium bau secara intuitif — kode “berbau tidak sedap”, meskipun secara formal semua aturan dipatuhi.
Fowler mengidentifikasi 22 bau yang dibagi menjadi beberapa kategori. Untuk pengembangan mobile, yang paling relevan adalah bau struktural, bau desain berorientasi objek, dan masalah spesifik terkait batasan platform. Mari kita lihat setiap kelompok dengan contoh dari praktik nyata.
Long Method (metode panjang) — bau yang paling umum dalam aplikasi mobile. Layar dengan formulir pendaftaran sering berisi satu metode setupUI sepanjang 200+ baris yang membuat semua View, mengatur konstrain, berlangganan ke acara, dan menangani kesalahan. Solusi: dipecah menjadi metode berdasarkan blok logis — configureEmailField, configurePasswordField, setupConstraints, bindViewModel.
Large Class (kelas besar) — Activity atau ViewController yang bertanggung jawab atas tampilan, navigasi, logika bisnis, dan komunikasi jaringan. Kelas seperti itu melanggar Prinsip Single Responsibility dan berisi puluhan bidang dan metode. Di Android, ini sering berupa Fragment dengan 1000+ baris yang berisi logika dari berbagai layar. Solusi: memisahkan presenter/ViewModel, memindahkan kerja jaringan ke repositori, navigasi ke koordinator.
Duplicate Code (duplikasi kode) — menyalin blok yang sama di berbagai bagian aplikasi. Contoh tipikal: dua layar yang menampilkan kartu produk — di katalog dan favorit. Jika logika tampilan disalin, memperbaiki bug di satu tempat tidak akan memperbaikinya di tempat lain. Solusi: memindahkan logika umum ke komponen yang dapat digunakan kembali atau ekstensi.
Feature Envy (iri pada kelas lain) — metode dari satu kelas secara intensif menggunakan data kelas lain. Di Android, ini terlihat ketika ViewModel langsung mengakses bidang model User alih-alih memanggil metode model. Sinyal: jika metode dapat dipindahkan ke kelas yang datanya digunakan — pindahkan. Switch Statements (rantai kondisi) — konstruksi switch atau rantai if-else yang memeriksa tipe objek. Sebagai gantinya, gunakan polimorfisme atau pola strategy.
Data Class — kelas yang hanya menyimpan data tetapi tidak mengandung perilaku. Data class (di Kotlin) atau struktur (di Swift) bukanlah bau dengan sendirinya. Masalah muncul ketika logika bisnis yang bekerja dengan data ini tersebar di seluruh basis kode alih-alih dienkapsulasi. Refused Bequest — pewaris tidak menggunakan sebagian besar metode induk dan menimpanya dengan implementasi kosong. Tanda pewarisan yang salah: ganti pewarisan dengan komposisi.
God Activity / God Fragment — Activity atau Fragment yang tahu segalanya: tentang siklus hidup, data, navigasi, izin, DI. Ini adalah kelas yang paling mahal untuk dipelihara dalam aplikasi. Solusi: pola arsitektur MVVM, MVI, atau Clean Architecture membagi tanggung jawab. Giant ViewController — analog untuk iOS, di mana UIViewController berisi semua logika layar dan sering melebihi 500 baris.
Hardcoded Resources — string, warna, ukuran, URL API yang disematkan langsung dalam kode. Di Android, ini melanggar penggunaan sistem sumber daya R, di iOS — NSLocalizedString dan Asset Catalog. Perbaikan: pindahkan semua string ke strings.xml atau Localizable.strings, URL ke file konfigurasi, ukuran ke dimens. Leaking Context — menyimpan referensi ke Activity atau ViewController lebih lama dari komponen itu sendiri hidup. Menyebabkan kebocoran memori dan crash. Solusi: referensi lemah, Jetpack Lifecycle, RxSwift DisposeBag.
| Bau | Di mana muncul | Solusi |
|---|---|---|
| Long Method | Android/iOS | Extract Method, pemecahan |
| Large Class | Activity, ViewController | MVVM, VIPER, Clean Arch |
| Duplicate Code | Layar mana pun | Shared Component, DRY |
| Feature Envy | ViewModel, Presenter | Move Method |
| Leaking Context | Android | Komponen sadar siklus hidup |
Code review — cara paling andal untuk mendeteksi bau. Mata manusia melihat konstruksi tidak alami yang dilewatkan oleh penganalisis otomatis. Efektivitas tinjauan kode meningkat ketika tim menggunakan daftar periksa bau umum. Disarankan untuk memeriksa tidak lebih dari 200–400 baris kode dalam satu sesi — setelah ambang ini, perhatian menurun dan bau mulai terlewatkan.
Analisis statis mengotomatiskan pencarian bau struktural. Untuk Android, alat standarnya adalah Detekt (Kotlin) dan Android Lint, untuk iOS — SwiftLint dan SonarQube. Alat-alat ini menemukan metode panjang, kelas besar, duplikasi kode, dan banyak masalah lainnya. Penting untuk mengonfigurasi aturan sesuai proyek — konfigurasi default sering terlalu ketat atau sebaliknya, melewatkan bau kritis.
Metrik kode memberikan kriteria objektif: Cyclomatic Complexity (ambang >10 memerlukan perhatian), Lines of Code per Method (ambang >30), Depth of Inheritance (>3 — alasan untuk berpikir). Alat seperti CodeMetrics (Xcode) dan Gradle Metrics Plugin membuat grafik perubahan metrik dari waktu ke waktu. Jika kompleksitas metode meningkat dari 5 menjadi 15 setelah komit terakhir — ini adalah sinyal untuk refactoring.
// Contoh: metode dengan kompleksitas Cyclomatic = 7 (di atas ambang 5)
fun processOrder(order: Order) {
if (order.status == Status.NEW) { /* 10 baris */ }
else if (order.status == Status.PAID) { /* 15 baris */ }
else if (order.status == Status.SHIPPED) { /* 20 baris */ }
else if (order.status == Status.DELIVERED) { /* 8 baris */ }
else if (order.status == Status.CANCELLED) { /* 5 baris */ }
else { throw IllegalStateException() }
}
// Perbaikan: polimorfisme sebagai pengganti switch
interface OrderHandler {
fun handle(order: Order)
}
Pencarian otomatis bau tidak menggantikan tinjauan kode: penganalisis statis hanya menemukan masalah struktural, tetapi tidak menangkap bau semantik (Feature Envy, Inappropriate Intimacy). Kombinasi alat otomatis dan kontrol manusia memberikan hasil terbaik. Konfigurasikan pipeline CI/CD sehingga build gagal saat melampaui ambang kompleksitas atau panjang metode.
Refactoring — metode utama untuk menghilangkan bau kode. Fowler menjelaskan puluhan teknik refactoring, masing-masing berlaku untuk bau tertentu. Extract Method — untuk metode panjang, Extract Class — untuk kelas besar, Move Method — untuk Feature Envy. Penting untuk melakukan refactoring dalam langkah-langkah kecil, menjaga kode tetap berfungsi setelah setiap perubahan.
Pengujian sebelum refactoring — kondisi wajib. Jika kode tidak tercakup oleh pengujian unit, refactoring berubah menjadi penulisan ulang dengan hasil yang tidak diketahui. Untuk kode legacy tanpa pengujian, gunakan Characterisation Tests — tulis pengujian yang merekam perilaku saat ini, lalu refactor. Pengujian memberikan keyakinan bahwa logika bisnis tidak rusak setelah refactoring.
Bertahap — kunci keberhasilan memperbaiki bau dalam pengembangan mobile. Jangan mencoba menulis ulang God Activity secara keseluruhan. Pisahkan dulu lapisan navigasi, lalu lapisan data, kemudian logika tampilan. Setiap langkah disertai dengan komit dan menjalankan pengujian. Gunakan feature toggle untuk mengaktifkan refactoring untuk sebagian pengguna dan memutar kembali jika ada masalah.
Alat IDE mengotomatiskan banyak teknik refactoring. Android Studio dan IntelliJ IDEA menawarkan refactoring bawaan: Extract Method, Extract Interface, Pull Members Up, Encapsulate Fields. Xcode (mulai dari versi 14) telah meningkatkan dukungan refactoring untuk Swift. Menggunakan refactoring otomatis mengurangi risiko kesalahan dibandingkan dengan menyalin kode secara manual.
Pengembangan mobile menambahkan bau spesifiknya sendiri terkait dengan batasan platform. Di Android, ini adalah kebocoran Context, Cursor yang tidak ditutup, penggunaan Lifecycle yang tidak tepat. Di iOS — retain cycle melalui closure, pekerjaan yang salah dengan Auto Layout, ViewController raksasa. Bau ini tidak hanya memperburuk pemeliharaan, tetapi juga secara langsung memengaruhi kinerja dan stabilitas aplikasi.
Callback Hell — bau khas untuk kode yang bekerja dengan operasi asinkron. Callback bersarang (callback inside callback) membuat kode tidak terbaca dan sulit di-debug. Solusi: coroutine (Kotlin), async/await (Swift 5.5+), RxJava/RxSwift atau Combine. Menurut Google I/O 2023, proyek yang beralih dari gaya callback ke coroutine mengurangi jumlah bug sebesar 30% dan mempercepat penambahan fitur baru.
Platform Coupling — pengikatan kaku logika bisnis ke komponen platform. Menguji logika semacam itu memerlukan menjalankan emulator, yang memperlambat siklus umpan balik. Perbaikan: Clean Architecture membagi kode menjadi lapisan Domain (Kotlin/Swift murni tanpa ketergantungan platform) dan Data/UI (dengan ketergantungan platform). Logika bisnis diuji di JVM tanpa emulator.
Pertanyaan yang sering diajukan
Tidak — Code Smell bukanlah kesalahan. Kode dengan bau berfungsi dengan benar, tetapi sulit dipelihara, diubah, dan diuji. Bug adalah perilaku yang salah, bau adalah peringatan tentang potensi masalah di masa depan.
22 bau dalam edisi kedua buku “Refactoring” (2019). Di antaranya Long Method, Large Class, Primitive Obsession, Data Clumps, Switch Statements, Speculative Generality dan lainnya. Komunitas telah menambahkan puluhan bau baru untuk paradigma dan platform modern.
Kombinasi memberikan hasil terbaik: Detekt (Android/Kotlin), SwiftLint (iOS), SonarQube (keduanya) untuk analisis otomatis dan tinjauan kode untuk bau semantik. Tidak ada alat yang menemukan 100% masalah — pengalaman manusia tetap menentukan.
Bisa, jika kode jarang berubah atau akan sepenuhnya ditulis ulang dalam waktu dekat. Namun, akumulasi bau berubah menjadi utang teknis: setiap perubahan baru menjadi semakin sulit, dan biaya perbaikan meningkat secara eksponensial.
Ya — framework deklaratif menciptakan bau baru: blok @State raksasa, pekerjaan yang salah dengan render berulang, komposisi ulang berlebihan, kurangnya ekstraksi ke View terpisah. Untuk SwiftUI, bau khasnya adalah Massive View dengan puluhan variabel @State.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga