Cara Refactor Legacy Code Tanpa Bikin Sistem Ikut Rusak

Cara Refactor Legacy Code Tanpa Bikin Sistem Ikut Rusak

12/26/2025 Software Development By Tech Writers
Legacy CodeRefactoringTesting

Daftar Isi

Legacy Code Bukan Musuh: Pahami Dulu Kondisinya

Banyak tim melihat legacy code sebagai “musuh” yang harus segera dibersihkan total. Padahal, legacy code biasanya adalah kode yang sudah bertahun‑tahun menghasilkan uang untuk bisnis — hanya saja sekarang makin sulit dipahami dan diubah dengan aman.

Beberapa ciri umum legacy code:

  • Minim atau tanpa test sama sekali sehingga setiap perubahan terasa seperti berjudi.
  • Pengetahuan ada di kepala beberapa orang saja, sering kali yang sudah pindah tim atau bahkan keluar perusahaan.
  • Struktur kode terbentuk organik, mengikuti kebutuhan yang muncul bertahun‑tahun, bukan desain yang direncanakan dari awal.

Sebelum refactor, penting untuk:

  • Memahami aliran bisnis utama yang ditopang oleh kode tersebut (misalnya alur order, payment, atau onboarding).
  • Mengetahui bagian mana yang paling sensitif: yang sering diakses user, yang menyentuh uang, atau yang berhubungan dengan regulator.
  • Mengidentifikasi dependency eksternal: service lain, database lama, batch job, sampai cron misterius yang masih jalan.

Tujuannya sederhana: jangan pernah mulai refactor hanya karena kode “kelihatan jelek”. Mulailah karena ada alasan yang jelas: risiko terlalu tinggi, cost of change makin mahal, atau rencana produk ke depan akan sering menyentuh area tersebut.

Langkah 1: Pasang Safety Net Sebelum Menyentuh Apapun

Kesalahan paling umum saat berurusan dengan legacy code adalah langsung “beres‑beres” tanpa memasang pengaman. Di sistem yang sudah berjalan lama, bug kecil bisa punya dampak besar ke revenue atau operasi harian.

Safety net yang ideal biasanya kombinasi dari:

  • Characterization test: test yang tidak langsung “membetulkan” perilaku, tapi mendokumentasikan perilaku saat ini. Bahkan kalau ternyata perilakunya aneh, test ini memastikan kamu tidak tanpa sadar mengubah sesuatu yang user atau sistem lain sudah mengandalkan.
  • Monitoring & logging yang bisa dipercaya: sebelum mengubah kode, pastikan ada log dan metric yang cukup untuk mendeteksi kalau ada perilaku menyimpang setelah rilis.
  • Feature flag atau mekanisme rollback cepat: jika refactor menyentuh jalur kritis, pastikan ada cara mematikan perubahan tanpa perlu redeploy besar‑besaran.

Langkah praktis sebelum refactor:

  • Pilih satu flow bisnis yang ingin kamu amankan (misalnya “create order”).
  • Tulis beberapa characterization test end‑to‑end atau integration test yang memanggil sistem seperti client aslinya.
  • Tambahkan log penting di boundary (misalnya sebelum/ setelah hit DB, sebelum kirim request ke service lain).

Setelah safety net minimum ini ada, barulah refactor bisa dilakukan dengan lebih tenang: setiap perubahan bisa divalidasi cepat lewat test dan observabilitas.

Langkah 2: Petakan Area Panas yang Paling Sering Berubah

Tidak semua legacy code perlu disentuh sekaligus. Fokus ke hotspot: bagian yang paling sering berubah atau paling sering jadi sumber incident.

Cara memetakannya:

  • Gunakan data dari version control: file mana yang paling sering di‑commit dalam 3–6 bulan terakhir? File yang sering disentuh biasanya kandidat kuat untuk diperbaiki struktur dan test‑nya.
  • Lihat data incident/bug: modul apa yang paling sering muncul di post‑mortem, ticket bug, atau on‑call alert?
  • Tanya orang yang paling sering terpaksa menyentuh area itu: mereka biasanya tahu “daerah ranjau” yang tidak tertulis di mana‑mana.

Dari peta ini kamu bisa:

  • Memprioritaskan refactor di area yang paling sering mengganggu tim.
  • Menjelaskan ke stakeholder kenapa effort refactor layak: “70% incident 6 bulan terakhir datang dari modul ini.”
  • Menghindari refactor kosmetik di area yang jarang disentuh dan tidak memberi dampak nyata.

Langkah 3: Bersihkan Jalur yang Kamu Lewati Hari Ini

Alih‑alih membuat “project refactor besar” yang memakan waktu berbulan‑bulan, pendekatan yang lebih realistis adalah prinsip boy scout rule:

“Tinggalkan kode yang kamu sentuh dalam keadaan sedikit lebih baik dari saat kamu menemukannya.”

Contoh penerapan:

  • Saat menambah field baru di sebuah form, sekalian ekstrak validasi berulang ke helper atau service kecil.
  • Saat memperbaiki bug di function panjang, sekalian pecah logic kompleks menjadi beberapa function dengan nama yang lebih jelas.
  • Saat menemukan query yang dipakai di banyak tempat, pertimbangkan untuk membungkusnya di repository/service dengan satu API yang lebih jelas.

Kunci utamanya:

  • Jangan mengubah terlalu banyak hal sekaligus dalam satu PR.
  • Tetap jaga diff tetap fokus ke jalur yang memang kamu sentuh untuk kebutuhan feature/bug hari ini.
  • Pastikan setiap perubahan kecil tetap dilindungi dengan test (atau minimal menambah coverage sedikit demi sedikit).

Dengan cara ini, kualitas sistem meningkat secara bertahap seiring ritme pengembangan normal, tanpa perlu proyek refactor raksasa yang sulit diprioritaskan.

Pola Strangler Fig: Ganti Komponen Lama Secara Bertahap

Untuk modul besar yang sudah terlalu kusut, sering kali strategi terbaik adalah tidak mencoba membersihkan di tempat, tapi memindahkan fungsinya sedikit demi sedikit ke modul baru yang lebih sehat. Inilah inti dari Strangler Fig Pattern.

Pola dasarnya:

  1. Letakkan facade di depan modul lama: semua traffic masuk melalui satu pintu yang terkontrol.
  2. Implementasikan fitur baru di modul baru, tapi tetap lewat facade yang sama.
  3. Secara bertahap, pindahkan bagian‑bagian fungsi lama ke modul baru, dan route traffic yang relevan ke sana.
  4. Saat bagian lama benar‑benar tidak dipakai lagi, matikan dan bersihkan kode lama.

Keuntungan pendekatan ini:

  • Refactor bisa dirilis bertahap tanpa perlu big‑bang cutover.
  • Kamu bisa menguji modul baru di sebagian traffic (canary/partial rollout) sebelum memindahkan semuanya.
  • Risiko kegagalan jauh lebih kecil dibanding “sekali ganti semua”.

Contoh sederhana:

  • Hari ini, semua request pembayaran masuk ke LegacyPaymentService.
  • Kamu tambahkan PaymentFacade yang awalnya hanya meneruskan request ke LegacyPaymentService.
  • Fitur payment method baru (PayLater, misalnya) diimplementasikan di NewPaymentService, dan PaymentFacade mengarahkan jenis request itu ke service baru.
  • Seiring waktu, metode lama dipindah satu per satu sampai LegacyPaymentService kosong dan bisa dipensiunkan.

Kapan Harus Refactor, Kapan Lebih Baik Rewrite?

Pertanyaan klasik: lebih baik refactor bertahap atau rewrite total? Jawabannya jarang hitam‑putih, tapi ada beberapa pertimbangan praktis:

Refactor bertahap biasanya lebih tepat ketika:

  • Sistem saat ini masih menghasilkan revenue besar dan tidak boleh sering down.
  • Pengetahuan domain banyak tertanam di kode lama dan tidak terdokumentasi dengan baik.
  • Tim tidak punya kapasitas untuk mengerjakan sistem baru sambil tetap menjaga sistem lama tetap hidup.

Rewrite total bisa dipertimbangkan ketika:

  • Arsitektur lama benar‑benar menghambat (misalnya monolith yang tidak mungkin lagi diskalakan sesuai kebutuhan produk).
  • Ada lompatan kebutuhan besar (misalnya pindah dari on‑prem ke multi‑tenant SaaS) yang sulit diakomodasi dengan evolusi kecil.
  • Ada kejelasan domain yang jauh lebih baik sekarang, sehingga desain baru bisa dibuat dengan fondasi yang lebih kuat.

Apa pun pilihannya, pastikan:

  • Ada strategi migrasi data dan traffic yang jelas.
  • Risiko terhadap user dan bisnis dikomunikasikan dengan jujur.
  • Ada checkpoint berkala untuk menilai apakah pendekatan masih masuk akal, atau perlu diubah (misalnya dari rewrite penuh ke hybrid).

Cara Presentasi Rencana Refactor ke Tim Bisnis

Refactor yang baik sering kali gagal disetujui bukan karena idenya buruk, tapi karena cara menjelaskannya tidak nyambung dengan bahasa bisnis. Yang didengar hanya: “butuh waktu, tapi tidak ada fitur baru yang kelihatan”.

Beberapa cara mengemas proposal refactor:

  • Hubungkan langsung ke risiko bisnis
    Contoh: “60% incident produksi 6 bulan terakhir datang dari modul pembayaran lama. Setiap incident rata‑rata menyebabkan downtime 20–30 menit dan refund tambahan.”
  • Nyatakan benefit dalam bentuk cost atau kecepatan
    Misalnya: “Setelah refactor, estimasi perubahan di area ini bisa turun dari 5 hari jadi 2 hari, sehingga fitur‑fitur payment baru bisa rilis lebih cepat.”
  • Bagi refactor menjadi milestone kecil
    Daripada satu blok 3 bulan, pecah menjadi batch 2–3 minggu dengan hasil yang bisa diukur: penurunan incident, penurunan lead time, atau peningkatan coverage test.

Saat diskusi dengan stakeholder:

  • Jelaskan trade‑off secara eksplisit: apa yang harus diparkir sementara untuk memberi ruang ke refactor.
  • Tunjukkan bagaimana refactor bisa digabungkan dengan delivery fitur yang sedang direncanakan, bukan sepenuhnya terpisah.
  • Gunakan bahasa risiko dan peluang, bukan hanya bahasa teknis (class, function, modul, dan lain‑lain).

Dengan begitu, refactor legacy code tidak lagi dipandang sebagai “hobi engineer”, tapi sebagai investasi infrastruktur produk yang bisa diukur dampaknya ke kecepatan dan stabilitas bisnis.


Referensi

Artikel Terkait


Pernah berhasil refactor legacy code besar tanpa sistem ikut hancur? Atau malah pernah menyesal mulai? Ceritakan pengalaman kamu di komentar — strategi nyata dari lapangan selalu lebih berharga dari contoh buku! 💬