KISS (Keep It Simple) — Clean Code

KISS (Keep It Simple, Stupid): Solusi paling sederhana yang bekerja biasanya adalah solusi terbaik. Jangan membuat sesuatu jadi rumit kalau bisa sederhana…

KISS (Keep It Simple, Stupid) artinya pilih solusi paling sederhana yang benar. Kode yang "pintar" bikin penulisnya bangga, kode yang sederhana bikin pembacanya cepat paham. Bayangin petunjuk jalan ke rumahmu. "Dari masjid belok kiri, rumah ketiga yang catnya hijau" lebih berguna daripada koordinat GPS sampai delapan angka di belakang koma. Dua-duanya benar, tapi cuma satu yang bisa diikuti tanpa alat.

🧪 Tebakan cepat: di versi pintar di bawah ada potongan (t < 2e5) * 15e3. Kalau t bernilai 189000, hasilnya berapa? Tebak dulu, jawabannya ada di bagian "Membaca versi pintar".

Versi pintar dan versi biasa

Dua cara menulis kasir Toko Kaos Raka. Versi pintar, dua baris:

const calculateTotal = (c, v) =>
  'Total: Rp ' + (t => t + (t < 2e5) * 15e3)(c.reduce((s, i) => s + i.price * i.qty, 0) * (v === 'HEMAT10' ? 0.9 : 1)).toLocaleString('id-ID');

Versi biasa, dengan loop:

const VOUCHER_DISCOUNT = 0.1;
const FREE_SHIPPING_MIN = 200000;
const SHIPPING_FEE = 15000;

function calculateTotal(cart, voucherCode) {
  let total = 0;
  for (const item of cart) {
    total += item.price * item.qty;
  }
  if (voucherCode === 'HEMAT10') total -= total * VOUCHER_DISCOUNT;
  if (total < FREE_SHIPPING_MIN) total += SHIPPING_FEE;
  return 'Total: Rp ' + total.toLocaleString('id-ID');
}

Dijalankan dengan empat keranjang dari lesson pertama, hasilnya sama persis:

Keranjang Versi pintar Versi biasa
A + HEMAT10 Total: Rp 220.500 Total: Rp 220.500
A tanpa voucher Total: Rp 245.000 Total: Rp 245.000
C tanpa voucher Total: Rp 90.000 Total: Rp 90.000
D + HEMAT10 Total: Rp 204.000 Total: Rp 204.000

Jadi bedanya bukan di hasil, tapi di berapa trik yang harus dipahami pembaca.

Membaca versi pintar

Untuk membaca satu baris itu, kamu harus tahu lima hal:

  1. (t => ...)(...): fungsi panah yang langsung dipanggil, supaya hasil hitungan bisa diberi nama t.
  2. 2e5 itu 200000 dan 15e3 itu 15000 (notasi eksponen: 2 × 10⁵).
  3. (t < 2e5) * 15e3: boolean dikali angka. true dihitung 1 dan false dihitung 0, jadi hasilnya 15000 atau 0.
  4. * 0.9: potongan 10% ditulis terbalik, sebagai "bayar 90%".
  5. reduce((s, i) => ...): menjumlahkan, dengan nama satu huruf.

Dengan t = 189000, 189000 < 200000 itu true, dan true * 15000 = 15000. Itu jawaban tebakannya: ongkir ditambahkan. Versi biasa cuma butuh for...of dan if, dibaca dari atas ke bawah.

Bedanya terasa saat mencari bug

Pembeli dengan keranjang D bertanya kenapa dia bayar ongkir. Di versi biasa, kamu tinggal menaruh console.log di antara langkah:

  console.log('subtotal:', total);         // subtotal: 210000
  if (voucherCode === 'HEMAT10') total -= total * VOUCHER_DISCOUNT;
  console.log('setelah voucher:', total);  // setelah voucher: 189000
  if (total < FREE_SHIPPING_MIN) total += SHIPPING_FEE;
  console.log('setelah ongkir:', total);   // setelah ongkir: 204000

Jawabannya langsung terbaca: setelah potongan, totalnya 189.000, di bawah batas 200.000. Di versi pintar gak ada tempat untuk console.log di antara langkahnya. Kamu harus menulis ulang dulu jadi versi biasa. Kode yang susah dipahami juga susah dites dan di-debug, dan itu memperlambat semua perubahan berikutnya.

Kebanyakan jaga-jaga juga bukan sederhana

Kebalikan dari versi pintar adalah versi yang menjaga semua kemungkinan. Contohnya dari latihan:

function isAdult(age) {
  try {
    if (age !== null && age !== undefined) {
      if (typeof age === 'number') {
        if (age >= 18) {
          return true;
        } else {
          return false;
        }
      } else {
        return false;
      }
    } else {
      return false;
    }
  } catch (e) {
    return false;
  }
}

Semua ini cuma menjawab satu pertanyaan, dan jawabannya sudah berupa true atau false:

function isAdult(age) {
  return age >= 18;
}

Hal yang sama berlaku untuk class dan pola desain yang dipasang "siapa tahu nanti perlu", misalnya VoucherFactory dan DiscountStrategy untuk satu voucher HEMAT10. Prinsip pelengkapnya disebut YAGNI (You Aren't Gonna Need It): tambahkan abstraksi saat kebutuhannya sudah ada, misalnya saat ada puluhan voucher dengan aturan berbeda.

Latihan: isAdult

Sederhanakan isAdult(age) jadi satu ekspresi boolean. Yang dinilai: tiga baris output tetap true, false, true (untuk 20, 17, 18), isAdult(18) true, isAdult(17) false, isAdult(0) false, isAdult(65) true, dan gak ada lagi try { atau else if (. Nama fungsi tetap isAdult dan parameternya tetap age.

⚠️ Jebakan yang sering ketemu

TL;DR: KISS artinya solusi paling sederhana yang benar. Versi pintar kasir ((t < 2e5) * 15e3, * 0.9, fungsi panah yang langsung dipanggil) dan versi biasa dengan loop memberi hasil yang sama di keempat keranjang, tapi versi pintar butuh lima trik untuk dibaca dan gak bisa diberi console.log di antara langkahnya. Kebanyakan jaga-jaga juga bukan sederhana: isAdult dengan try, if bersarang dan return true/false cukup jadi return age >= 18;, dengan hasil sama untuk angka (18 true, 17 false, 0 false, 65 true). Over-engineering bikin kode lebih sulit dipahami, dites dan di-debug, jadi pengembangan melambat. Tambahkan abstraksi saat dibutuhkan (YAGNI), dan pastikan refactor tetap memberi hasil yang sama untuk input yang benar-benar masuk.

Yang akan kamu pelajari