DRY (Don't Repeat Yourself): Setiap bagian pengetahuan harus punya satu representasi di dalam sistem. Jika kamu copy-paste kode, kemungkinan besar kamu melanggar DRY.
Mengapa duplikasi berbahaya? Saat ada bug atau perubahan requirement, kamu harus mengubah di semua tempat yang diduplikasi. Lupa satu tempat = bug yang sulit ditemukan.
Sebelum — duplikasi di mana-mana:
// BURUK: format harga ditulis 3 kali
function showProductCard(product) {
const price = "Rp " + product.price.toLocaleString("id-ID");
return `<div>${product.name} - ${price}</div>`;
}
function showCartItem(item) {
const price = "Rp " + item.price.toLocaleString("id-ID");
const total = "Rp " + (item.price * item.qty).toLocaleString("id-ID");
return `<li>${item.name}: ${price} x ${item.qty} = ${total}</li>`;
}
function showOrderSummary(order) {
const total = "Rp " + order.total.toLocaleString("id-ID");
return `<p>Total: ${total}</p>`;
}
// Kalau format berubah ke "IDR", ubah di 4 tempat!
Sesudah — satu fungsi reusable:
// BERSIH: format harga ada di satu tempat
function formatRupiah(amount) {
return "Rp " + amount.toLocaleString("id-ID");
}
function showProductCard(product) {
return `<div>${product.name} - ${formatRupiah(product.price)}</div>`;
}
function showCartItem(item) {
return `<li>${item.name}: ${formatRupiah(item.price)} x ${item.qty} = ${formatRupiah(item.price * item.qty)}</li>`;
}
function showOrderSummary(order) {
return `<p>Total: ${formatRupiah(order.total)}</p>`;
}
// Ubah format? Cukup ubah di formatRupiah()
Duplikasi logika — lebih bahaya dari duplikasi kode:
// BURUK: validasi email ditulis di 3 tempat
function registerUser(data) {
if (!/^[^@]+@[^@]+\.[^@]+$/.test(data.email)) {
throw new Error("Email tidak valid");
}
// ... register
}
function updateProfile(data) {
if (!/^[^@]+@[^@]+\.[^@]+$/.test(data.email)) {
throw new Error("Email tidak valid");
}
// ... update
}
// BERSIH: satu sumber kebenaran
function isValidEmail(email) {
return /^[^@]+@[^@]+\.[^@]+$/.test(email);
}
function registerUser(data) {
if (!isValidEmail(data.email)) throw new Error("Email tidak valid");
// ... register
}
function updateProfile(data) {
if (!isValidEmail(data.email)) throw new Error("Email tidak valid");
// ... update
}
Duplikasi konfigurasi:
// BURUK: magic numbers tersebar
if (password.length < 8) { ... } // di registrasi
if (newPass.length < 8) { ... } // di change password
if (pwd.length < 8) { ... } // di reset password
// BERSIH: satu konstanta
const MIN_PASSWORD_LENGTH = 8;
if (password.length < MIN_PASSWORD_LENGTH) { ... }
Kapan DRY berlebihan (WET — Write Everything Twice):
// Kadang sedikit duplikasi LEBIH BAIK dari abstraksi prematur
// Aturan "Rule of Three": duplikat ke-3 baru di-refactor
// Dua fungsi yang kebetulan mirip, tapi konteksnya berbeda:
function formatUserName(user) { return `${user.first} ${user.last}`; }
function formatAuthorName(author) { return `${author.first} ${author.last}`; }
// Jangan langsung digabung! Mungkin nanti formatnya berbeda.
// TAPI kalau sudah 3x dan konteksnya sama → refactor!
function formatFullName(person) {
return `${person.first} ${person.last}`;
}
Cara mengenali duplikasi:
- Kamu sering copy-paste lalu ubah sedikit
- Saat fix bug, kamu harus mengubah di banyak tempat
- Ada "magic number" yang sama di beberapa file
- Validasi yang sama ditulis berulang
🎭 Analogi sehari-hari
DRY itu kayak resep masakan ibu yang ditulis sekali di buku resep, dipake puluhan kali tanpa perlu ditulis ulang. Pas ibu nemu pakai garam terlalu sedikit, dia ubah sekali di buku resep — semua hidangan ke depan otomatis benar. Versus: WET (Write Everything Twice) kayak nyatet resep di kertas baru tiap mau masak — pas mau ubah garam, kamu cari semua kertas, edit satu-satu, beberapa pasti kelewat. Hasilnya: ada hidangan asin, ada yang hambar, gak konsisten. Gak konsisten = bug. TAPI awas duplikasi yang KEBETULAN — formatUserName() dan formatAuthorName() mungkin keliatan sama TAPI konteksnya beda (mungkin nanti format penulis butuh include suffix akademik). Premature DRY = tightly coupled code yang susah diubah pas konteks berkembang beda.
⚠️ Jebakan yang sering ditemui
- DRY-everything mentality — jadi WET (Write Everything Twice) kalau cuma 2x. Tunggu Rule of Three — refactor pas duplikat ke-3 muncul.
- Premature abstraction — extract function dari 2 fungsi yang KEBETULAN mirip, padahal konteks beda. Pas konteks divergen, abstraksi malah jadi penghalang.
- Coincidental duplication —
function calculateTax()di order vsfunction calculateTax()di payroll. Looks similar, conceptually beda. Kalau gabung = bug pas tax rule berubah di salah satu domain. - Over-DRY config — semua constant di-extract → susah scan kode (harus loncat antar file). DRY config yang BENERAN dipake banyak tempat saja.
- Hidden duplication — duplikasi yang gak kelihatan persis sama tapi konsep sama (manual loop sum vs reduce sum). Refactor ke abstraksi yang sama.
- Typing-savings priority — DRY bukan tentang ngirit ngetik. Tentang single source of truth. Lebih panjang tapi clearer = OK.
Tipe Duplikasi yang Harus Diburu
- Logic duplication — validasi email/password sama di banyak tempat
- Magic number duplication —
8(min password) di 5 file =MIN_PASSWORD_LENGTH - Configuration duplication — URL endpoint hardcoded di-mana-mana = config file
- Knowledge duplication — business rule "diskon 10% jika total > 500k" di 3 fungsi = extract ke 1 fungsi
- Test data duplication — fixture user di-define ulang tiap test = factory pattern
Counter: WET (Write Everything Twice) — Kadang OK
// Dua component berbeda KEBETULAN punya struktur mirip
// JANGAN langsung gabung — mungkin nanti divergen
function UserCard({ user }) { return <div>...</div> }
function ProductCard({ product }) { return <div>...</div> }
// Gabungnya pas:
// - Sudah 3x duplicate (Rule of Three)
// - Konteks BENERAN sama (semua jenis card display)
// - Yakin gak akan divergen
🎯 DRY atau biarin duplikat?
- Bug fix butuh ubah di 3+ tempat → DRY ✓ (tanda kuat)
- Magic number / string sama di banyak file → extract jadi constant
- Validasi sama (email, password) → extract function
- Cuma 2x duplikasi yang konteks bisa divergen → biarkan, tunggu Rule of Three
- Duplikasi struktur tapi data domain beda → hati-hati, mungkin coincidental
- Config / endpoint URL → extract jadi env var atau config file
- Test fixture berulang → extract jadi factory function
Aturan: DRY = single source of truth, BUKAN typing savings. Refactor pas pattern udah jelas (3x), bukan dari awal.
TL;DR: DRY = setiap pengetahuan punya 1 sumber kebenaran (source of truth). Refactor pas duplikat ke-3 muncul (Rule of Three). Hati-hati coincidental duplication — fungsi kebetulan mirip tapi konteks beda, JANGAN gabung. Tipe duplikasi: logic (validasi), magic number, config, knowledge (business rule), test data. WET (Write Everything Twice) kadang OK kalau konteks bisa divergen. DRY adalah filosofi, bukan dogma.