Managing Technical Debt — Clean Code

Technical debt adalah konsekuensi dari menulis kode yang cepat tapi tidak optimal — seperti utang finansial, makin lama dibiarkan, makin besar "bunganya" (biaya

Technical debt adalah konsekuensi dari menulis kode yang cepat tapi tidak optimal — seperti utang finansial, makin lama dibiarkan, makin besar "bunganya" (biaya maintenance).

Jenis-jenis technical debt:

1. Deliberate & Reckless

// "Kita tidak punya waktu untuk desain yang benar"
// Sadar ada masalah, tapi tidak peduli
function doEverything(data) {
  // 500 baris, validasi ada di mana-mana, tidak ada struktur
}

2. Deliberate & Prudent

// "Kita tahu ini tidak ideal, tapi kita perlu ship sekarang"
// TODO: Refactor setelah launch v1. Saat ini pakai pendekatan naive
// karena deadline 2 hari lagi.
const result = expensiveCalculation(data); // O(n²), perlu dioptimasi

3. Inadvertent & Reckless

// "Apa itu layering?"
// Developer tidak tahu best practices — hasilnya kode semrawut
// tanpa sadar ada masalah

4. Inadvertent & Prudent

// "Sekarang baru sadar cara yang lebih baik"
// Belajar setelah implementasi — ini normal dan sehat
// Refactor saat ada kesempatan

Cara mengukur technical debt:

// Indikator kuantitatif:
const debtIndicators = {
  duplicateCode: "Duplikasi > 20% → tinggi",
  cyclomaticComplexity: "Kompleksitas > 10 per fungsi → perlu refactor",
  testCoverage: "Coverage < 60% → risiko tinggi",
  outdatedDependencies: "Paket > 2 major version → security risk",
  buildTime: "Build > 5 menit → ada yang salah",
};

Strategi mengelola technical debt:

Boy Scout Rule

// Selalu tinggalkan kode lebih baik dari saat kamu temukan
// Bukan berarti refactor besar-besaran — cukup perbaikan kecil

// Sebelum: nama tidak jelas
function calcT(a, b) { return a + b; }

// Sesudah: rename saat lewat
function calculateTotal(price, tax) { return price + tax; }

Debt Register (Daftar Utang)

// Dokumentasikan debt secara eksplisit
// TECHNICAL DEBT [TD-042]
// Masalah: UserService terlalu besar (800 baris), melanggar SRP
// Dampak: Sulit test, sering konflik merge
// Estimasi perbaikan: 3 hari
// Owner: Tim Backend
// Target: Sprint Q2 2025
class UserService {
  // ... 800 baris
}

Kapan harus bayar debt:

  1. Sebelum menambah fitur baru di area yang berhutang
  2. Saat onboarding developer baru — debt membuat mereka kebingungan
  3. Saat bug berulang di area yang sama
  4. Saat performa mulai terasa lambat

Yang bukan technical debt:

Aturan praktis:

🎭 Analogi sehari-hari

Technical debt itu kayak utang kartu kredit. Pas startup ngebut launching, kamu ngutang ke "bank kode" — pinjem clean code untuk speed-up, janji bayar nanti. Tipis manfaatnya: shipping cepat, validasi market, beat kompetitor. Tapi kalo gak pernah bayar, bunga numpuk — bug nambah, dev baru bingung, fitur baru lambat dibangun, semuanya jadi takut sentuh kode legacy. Banyak startup tutup BUKAN karena gagal product-market fit, tapi karena tech debt udah nyekek. Aturan: ngutang OK kalo strategis (deadline penting, validasi MVP), TAPI jadwalin pembayaran (refactor sprint), catat di backlog, kalkulasi compound interest sebelum keputusan.

⚠️ Jebakan yang sering ditemui

Strategi Bayar Tech Debt

1. Boy Scout Rule — refactor kecil tiap kali sentuh kode (passive payment) 2. Refactor Sprint — 1 sprint per quarter fokus bayar debt besar 3. Strangler Fig — replace legacy bertahap, paralel jalan dengan new code 4. Big Rewrite — hampir selalu BAD IDEA (Joel Spolsky), kecuali tech foundation udah obsolete

Tools untuk Track Debt

// 1. TODO/FIXME comments dengan tanggal + ticket
// FIXME (#1234, ani, 2026-04): pakai cache in-memory, perlu Redis untuk multi-instance

// 2. Architecture Decision Records (ADR)
// docs/adr/0001-temporary-monolith.md
// docs/adr/0002-microservices-migration.md

// 3. Tech Debt Backlog (terpisah dari feature backlog)
// Linear/Jira label "tech-debt"

// 4. Code coverage thresholds
// Pasang minimum 80% coverage di CI — gagal merge kalau kurang

🎯 Bayar debt sekarang atau nanti?

  • Memblokir feature baru → bayar sekarang
  • Bug rate tinggi di area itu → bayar sekarang
  • Onboarding susah → bayar sekarang (impact growth)
  • Performa drop → bayar sekarang
  • Tidak ada masalah konkret → biarin (gak semua debt perlu dibayar)
  • Kode legacy yang stable + jarang disentuh → leave it alone (jangan refactor demi refactor)
  • Critical path production → bayar dengan SUPER hati-hati (tambah test dulu)

Aturan: bayar debt yang BLOKIR development. Jangan refactor demi "kode bersih" tanpa impact bisnis.

TL;DR: Technical debt = trade-off SADAR (kode "ngebut" untuk shipping speed) dengan rencana bayar. Bukan "kerjaan jelek" — itu sloppy, bukan debt. Catat di TODO/ADR/ticket. Alokasikan 20% sprint capacity untuk bayar. Bedain bug (fix sekarang) vs debt (scheduled payment). Strategi: Boy Scout Rule (passive), refactor sprint quarterly, strangler fig untuk legacy. Big rewrite hampir selalu bad idea. Bayar debt yang BLOKIR development, jangan refactor demi "perfect".