Technical debt (utang teknis) adalah jalan pintas di kode yang menghemat waktu sekarang, tapi bikin tiap perubahan berikutnya lebih mahal sampai jalan pintas itu dibereskan. Bayangin beli HP pakai paylater. HP-nya kamu pegang hari ini, tapi selama utangnya belum lunas, tiap bulan ada bunga. Di kode, "HP hari ini" adalah fitur yang rilis tepat waktu, dan "bunga" adalah menit tambahan yang kamu bayar setiap kali menyentuh kode itu.
🧪 Tebakan cepat: utang TD-01 di kasir Raka butuh 60 menit untuk dilunasi, dan selama belum lunas, tiap perubahan voucher makan 20 menit ekstra. Setelah berapa kali perubahan voucher, melunasinya sudah balik modal: 1, 3, atau 10? Tebak dulu, jawabannya ada di bagian "Bunga dihitung, bukan dirasakan".
Jalan pintas waktu Harbolnas
Seminggu sebelum Harbolnas, Raka minta struk dan email konfirmasi menampilkan berapa yang dihemat pembeli. Biar keburu, potongannya dihitung ulang di dua tempat baru, gak lewat tabel VOUCHERS dari lesson Refactoring Techniques:
const VOUCHERS = { HEMAT10: 0.1 };
function applyVoucher(amount, voucherCode) { // tempat 1
return amount - amount * (VOUCHERS[voucherCode] ?? 0);
}
// TD-01: disalin waktu Harbolnas, ada di daftar utang
function savingLine(subtotal, voucherCode) { // tempat 2
const rate = voucherCode === 'HEMAT10' ? 0.1 : 0;
return 'Hemat: ' + formatRupiah(subtotal * rate);
}
function emailLine(email, subtotal, voucherCode) { // tempat 3
const rate = voucherCode === 'HEMAT10' ? 0.1 : 0;
return email + ': kamu hemat ' + formatRupiah(subtotal * rate);
}
Fiturnya rilis tepat waktu dan keempat keranjang tetap OK. Itu untungnya berutang. Tapi tarif voucher sekarang tertulis di tiga tempat.
Lalu PR #14 dari lesson Code Review menambah HEMAT20 ke VOUCHERS saja. Keranjang A dengan HEMAT20:
OK Total: Rp 211.000
BEDA Hemat: Rp 0, harusnya Hemat: Rp 49.000
BEDA [email protected]: kamu hemat Rp 0, harusnya [email protected]: kamu hemat Rp 49.000
Totalnya benar, tapi struk dan email bilang pembeli gak hemat apa-apa. Itulah bunganya: tiap perubahan voucher harus ingat tiga tempat, bukan satu.
Pokok dan bunga
Istilah ini dari Ward Cunningham, di laporan pengalamannya tentang sistem WyCash (konferensi OOPSLA, 1992): mengirim kode yang belum pas itu seperti berutang, dan "tiap menit yang dihabiskan untuk kode yang belum pas dihitung sebagai bunga utang itu". Jadi utang punya dua angka:
- Pokok: biaya melunasi. Untuk TD-01: bikin satu fungsi
discountForyang membacaVOUCHERS, pakai di tiga tempat, jalankan cek. Perkiraan tim Raka: 60 menit. - Bunga: biaya ekstra tiap kali kode itu disentuh. Perkiraan tim: 10 menit per tempat untuk mencari, mengubah dan mengecek. Satu perubahan voucher jadi 3 tempat (30 menit), padahal kalau lunas cuma 1 tempat (10 menit). Bunganya 20 menit per perubahan.
Bunga cuma dibayar saat kodenya disentuh. Kode jelek yang gak pernah diubah gak berbunga.
Bunga dihitung, bukan dirasakan
Total menit untuk sejumlah perubahan voucher ke depan:
| Perubahan voucher | Biarkan (30 per perubahan) | Lunasi dulu (60 + 10 per perubahan) |
|---|---|---|
| 1 | 30 | 70 |
| 2 | 60 | 80 |
| 3 | 90 | 90 |
| 4 | 120 | 100 |
| 6 | 180 | 120 |
Impas di perubahan ketiga, dan mulai yang keempat, melunasi lebih murah. Itu jawaban tebakannya: 3. Rumusnya pokok dibagi bunga, 60 ÷ 20 = 3. Voucher kasir Raka berubah kira-kira dua kali sebulan (perkiraan tim), jadi dalam dua bulan sudah balik modal. Angka seperti ini yang kamu bawa ke Raka, bukan "kodenya jelek".
Daftar utang (debt register)
Utang yang gak dicatat gak pernah dibayar, karena gak ada yang ingat. Daftar utang kasir Raka:
| ID | Utang | Bunga | Pokok | Keputusan |
|---|---|---|---|---|
| TD-01 | Tarif voucher di 3 tempat | +20 menit tiap perubahan voucher, kira-kira 2 kali sebulan | 60 menit | Lunasi sekarang |
| TD-02 | Gak ada keranjang tepat Rp 200.000 di test | <= yang salah lolos tiap aturan ongkir diubah |
5 menit | Bayar sambil lewat |
| TD-03 | hitung(k, v) lama di skrip laporan tahunan |
0, gak pernah diubah | 90 menit | Biarkan, tetap dicatat |
- ID yang sama ditulis di komentar kodenya (
// TD-01), jadi yang membaca kode bisa menemukan catatannya. - Simpan di tempat tim bekerja: issue tracker dengan label
tech-debt, atau fileDEBT.mddi repo. - TD-03 jelek, tapi bunganya nol. Melunasinya cuma menghabiskan 90 menit yang gak pernah balik modal.
Yang bukan utang: bug (hasilnya salah, perbaiki sekarang) dan fitur yang belum dibuat (itu backlog).
Sengaja atau gak sadar
Martin Fowler (artikel "Technical Debt Quadrant", 2009) membagi utang dengan dua pertanyaan: sadar atau gak waktu berutang (deliberate atau inadvertent), dan hati-hati atau ceroboh (prudent atau reckless).
- Deliberate: tim tahu sedang ambil jalan pintas. TD-01 begini: disalin dengan sadar demi Harbolnas, dicatat, ada rencana bayar. Sengaja dan hati-hati.
- Inadvertent: utangnya terjadi tanpa disadari, karena belum tahu cara yang lebih baik. Developer yang belum kenal
?? 0lalu menulisamount * VOUCHERS[voucherCode](dan dapatNaNtanpa voucher) berutang tanpa sadar. Ia baru tahu setelah belajar.
Utang yang sengaja lebih gampang dikelola, karena bisa langsung dicatat saat itu juga.
Bayar sambil lewat: Boy Scout Rule
Robert C. Martin di buku Clean Code (2008) memakai aturan pramuka: tinggalkan perkemahan lebih bersih daripada saat kamu datang. Untuk kode: tiap kali menyentuh sebuah bagian, rapikan sedikit. TD-02 dilunasi begini: lain kali kamu mengubah addShipping, tambahkan satu baris test.
const cartE = [{ name: 'Topi Raka', price: 40000, qty: 5 }]; // tepat Rp 200.000
check(calculateTotal(cartE, ''), 'Total: Rp 200.000');
Lima menit, dibayar saat kamu memang sudah di sana. Utang besar seperti TD-01 tetap butuh waktu khusus yang dijadwalkan.
Latihan: assessDebt
Selain daftar yang ditulis manusia, alat bisa mengukur gejala utang: persentase kode duplikat, cyclomatic complexity (jumlah jalur yang bisa dilewati sebuah fungsi; tiap if, loop, && atau || menambah satu), test coverage (persentase kode yang dijalankan test), dan jumlah paket yang ketinggalan versi (npm outdated). Latihan memberi skor dengan ambang di bawah ini. Ambangnya khusus latihan; tiap tim menyepakati ambangnya sendiri.
| Ukuran | Kena kalau | Poin | Saran |
|---|---|---|---|
duplicateLines |
> 20 | 25 | Kurangi duplikasi kode |
cyclomaticComplexity |
> 10 | 20 | Sederhanakan fungsi kompleks |
testCoverage |
< 60 | 30 | Tingkatkan test coverage |
outdatedDependencies |
> 5 | 25 | Perbarui dependensi yang outdated |
Tiap ukuran yang kena menambah poinnya ke debtScore (misalnya debtScore += 25) dan menambah sarannya ke recommendations dengan push, urut seperti tabel. Ambangnya ketat: tepat 20, 10, 60 atau 5 belum kena, jadi { 20, 10, 60, 5 } menghasilkan skor 0 dan low. Cuma coverage yang kena di { 5, 3, 50, 1 }: skor 30, medium, satu saran. Contoh di editor, { 25, 12, 45, 8 }, kena semua:
{"debtScore":100,"priority":"critical","recommendations":["Kurangi duplikasi kode","Sederhanakan fungsi kompleks","Tingkatkan test coverage","Perbarui dependensi yang outdated"]}
⚠️ Jebakan yang sering ketemu
- "Nanti dirapikan" tanpa catatan. Gak ada ID, gak ada pokok dan bunga, jadi gak pernah dibayar. Tulis di daftar utang saat kamu berutang.
- Melunasi semua utang. TD-03 jelek tapi bunganya nol. Dahulukan yang bunganya besar dan sering disentuh.
- Bilang "kodenya jelek" ke pemilik bisnis. Bilang "tiap perubahan voucher makan 20 menit ekstra, melunasinya 60 menit, impas setelah 3 perubahan".
- Menganggap bug sebagai utang. Struk yang bilang
Hemat: Rp 0untuk HEMAT20 itu bug yang lahir dari utang: perbaiki hari ini. - Di latihan, memakai
>=di ambang. Tepat di ambang belum kena;{ 20, 10, 60, 5 }harus0|low.
TL;DR: Technical debt adalah jalan pintas yang menghemat waktu sekarang dan menagih bunga tiap kali kodenya disentuh (metafora Ward Cunningham, 1992). Hitung dua angkanya: pokok (biaya melunasi) dan bunga (menit ekstra per perubahan). Tarif voucher yang disalin ke tiga tempat bikin HEMAT20 tampil Hemat: Rp 0 di struk dan email, dan tiap perubahan voucher makan 20 menit ekstra; pokok 60 menit impas setelah 3 perubahan. Catat tiap utang di daftar utang dengan ID, bunga, pokok dan keputusan; kode jelek yang gak pernah diubah bunganya nol, biarkan. Deliberate berarti sadar ambil jalan pintas, inadvertent berarti gak sadar karena belum tahu caranya. Boy Scout Rule: tinggalkan kode sedikit lebih baik dari saat kamu menemukannya. Di latihan, tiap ukuran yang melewati ambang (> 20, > 10, < 60, > 5) menambah 25, 20, 30, 25 poin dan satu saran; 80 ke atas critical, 60 high, 30 medium, di bawahnya low.