Code Smells Catalog — Clean Code

Code smell adalah tanda bahwa ada yang perlu diperbaiki di kode — bukan bug, tapi indikasi desain kurang baik. Istilah ini dipopulerkan Kent Beck dan dibukukan

Code smell adalah tanda bahwa ada yang perlu diperbaiki di kode — bukan bug, tapi indikasi desain kurang baik. Istilah ini dipopulerkan Kent Beck dan dibukukan Martin Fowler di Refactoring.

Smell bukan larangan mutlak — ia undangan untuk berpikir: "Apakah ada cara yang lebih baik?" Kadang jawabannya "tidak, ini sudah sesuai konteks". Tapi lebih sering, smell menunjukkan hutang teknis yang sebaiknya dilunasi.

Mengapa hafal katalognya? Saat kamu tahu nama sebuah smell, kamu bisa:

Katalog lengkap (18 smell klasik):

# Smell Ciri Refactoring
1 Duplicate Code Kode/logika sama di beberapa tempat Extract Function, Extract Class
2 Long Method Fungsi terlalu panjang (> 20 baris) Extract Function, Decompose Conditional
3 Large Class Class terlalu banyak tanggung jawab Extract Class, Extract Subclass
4 Long Parameter List > 3–4 parameter Introduce Parameter Object, Preserve Whole Object
5 Divergent Change Satu class berubah karena banyak alasan berbeda Split Class
6 Shotgun Surgery Satu perubahan butuh edit di banyak class Move Method, Inline Class
7 Feature Envy Method di class A terlalu sering akses data class B Move Method ke class B
8 Data Clumps Sekelompok field yang selalu muncul bersama Extract Class, Introduce Parameter Object
9 Primitive Obsession String/number untuk konsep domain (uang, email, tanggal) Replace Primitive with Object (Value Object)
10 Switch Statements switch/if panjang berdasarkan tipe Replace Conditional with Polymorphism
11 Parallel Inheritance Tambah subclass X → harus tambah subclass Y Move Method, Move Field
12 Lazy Class Class yang hampir tidak berguna Inline Class
13 Speculative Generality Abstraksi untuk kebutuhan masa depan yang belum ada Collapse Hierarchy, Inline Class
14 Temporary Field Field yang hanya terisi di kasus tertentu Extract Class, Introduce Null Object
15 Message Chains a.b().c().d().e() — rantai panjang Hide Delegate (lihat Law of Demeter)
16 Middle Man Class yang hanya mendelegasikan ke class lain Remove Middle Man, Inline Method
17 Refused Bequest Subclass menolak/override kebanyakan method parent Replace Inheritance with Delegation
18 Comments Komentar banyak = kode tidak self-explanatory Extract Function, Rename Variable

Contoh: Primitive Obsession

// BAU: uang direpresentasikan sebagai angka biasa
function charge(amount, currency) {
  if (currency !== "IDR") throw new Error("only IDR");
  return amount * 1.11; // PPN 11%
}

// BERSIH: Money sebagai Value Object
class Money {
  constructor(amount, currency = "IDR") {
    this.amount = amount;
    this.currency = currency;
  }
  add(other) {
    if (this.currency !== other.currency) throw new Error("currency mismatch");
    return new Money(this.amount + other.amount, this.currency);
  }
  withTax(rate) {
    return new Money(this.amount * (1 + rate), this.currency);
  }
}

Contoh: Feature Envy

// BAU: Order ngintip terlalu dalam ke Customer
class Order {
  calculateDiscount(customer) {
    if (customer.membership === "gold" && customer.yearsActive > 5) {
      return this.total * 0.2;
    }
    return 0;
  }
}

// BERSIH: biarkan Customer yang tahu dirinya sendiri
class Customer {
  isLoyalGoldMember() {
    return this.membership === "gold" && this.yearsActive > 5;
  }
}
class Order {
  calculateDiscount(customer) {
    return customer.isLoyalGoldMember() ? this.total * 0.2 : 0;
  }
}

Cara pakai katalog dalam review:

  1. Scan perubahan — apakah ada pola familiar dari tabel di atas?
  2. Tulis komentar review dengan nama smell-nya: "Bagian ini terlihat seperti Shotgun Surgery — kalau kita tambah status baru, kita harus edit 4 file. Bisa kita pertimbangkan Move Method?"
  3. Sarankan refactoring kolom kanan tabel — bukan perintah, tapi alternatif.

Peringatan: Smell bukan absolut. Switch Statements bisa saja tepat untuk parser sederhana. Long Method boleh kalau memang sekuens linier yang jelas. Kriteria akhir: apakah kode ini mudah diubah besok?

🎭 Analogi sehari-hari

Code smells itu kayak bau aneh di dapur. Bau bawang busuk, asap dari kompor mati, drainase mampet — bau-bau ini gak otomatis berarti masakan rusak, tapi PERINGATAN buat investigasi. Mungkin emang baru bersih-bersih bawang (legitimate), atau mungkin ada bawang busuk di pojokan yang udah lama (perlu fix). Code smells sama: nama-nama signal pattern yang mungkin bermasalah. Long Method, God Class, Shotgun Surgery, Feature Envy — vocabulary yang bikin diskusi review jadi spesifik. "Ini smell-nya Long Method, refactor pakai Extract Function?" lebih actionable dari "Ini gak rapi". Tapi awas: smell bisa false positive — long method memang OK kalau sequential simple.

⚠️ Jebakan yang sering ditemui

Top 10 Smells Paling Sering

  1. Long Method — fungsi 50+ baris (Extract Function)
  2. Large Class — God Object 500+ baris (Extract Class)
  3. Long Parameter List — 4+ params (Introduce Parameter Object)
  4. Duplicated Code — kode sama di banyak tempat (Extract Function)
  5. Shotgun Surgery — 1 perubahan butuh edit banyak file (Move Method, consolidate)
  6. Feature Envy — method lebih banyak akses class lain (Move Method)
  7. Data Clumps — group fields yang selalu bareng (Extract Class)
  8. Primitive Obsession — terlalu banyak primitive string/int (Replace with Object)
  9. Switch Statements — banyak switch berdasar type (Replace with Polymorphism)
  10. Speculative Generality — abstraksi "siapa tau perlu nanti" yang gak pernah dipake (Inline / Hapus)

Cara Detect Smell

Manual — code review, pair programming, fresh eyes Static analysis tools — ESLint/SonarQube/PMD detect long method, complex condition, duplicated code Metrics — cyclomatic complexity, lines of code, coupling/cohesion ratio Smell test — "kalau saya kasih kode ini ke junior, mereka bingung gak?"

🎯 Smell terdeteksi — refactor sekarang atau biarin?

  • Smell + ada bug rate tinggi area itu → refactor SEKARANG
  • Smell + bakal ditambahin fitur → refactor DULU sebelum tambah fitur
  • Smell di kode legacy yang stable → biarin, gak worth resiko
  • Smell + clear better solution → refactor (improve)
  • Smell tapi gak yakin solusinya → diskusi tim dulu, jangan buru-buru
  • Smell tapi WORK ABOVE all (kode "nak dapur", legitimate context) → biarin
  • Smell di prototype 1-week throwaway → biarin

Aturan: smell = signal investigasi. Decision refactor based on cost (effort + risk) vs benefit (maintainability + future ease).

TL;DR: Code smells = vocabulary buat pattern yang MUNGKIN problematic. Bukan vonis, signal investigasi. Top: Long Method, God Class, Shotgun Surgery, Feature Envy, Duplicated Code. Detect via review, static analysis, metrics. Pakai vocabulary spesifik di review ("smells like Feature Envy") biar diskusi actionable. Refactor smell yang IMPACT (bug rate, blocking feature), biarin yang gak nimbulin pain. Smell-free ≠ good code (semantic correctness > syntactic cleanliness).

Yang akan kamu pelajari