Kompleksitas Siklomatik: Build atau Refaktor Selanjutnya
Summary
Kompleksitas siklomatik adalah metrik yang menghitung berapa banyak jalur logis independen dalam satu fungsi. Skor di atas 10 butuh perhatian ekstra; di atas 25 artinya fungsi itu perlu segera direfaktor. Alat seperti SonarQube, CodeScene, dan CodeClimate bisa mendeteksinya secara otomatis. Gunakan metrik ini bukan sebagai target kesempurnaan, melainkan sebagai threshold objektif: kapan utang teknis sudah cukup berbahaya untuk diperbaiki sebelum melanjutkan build fitur berikutnya.
Kompleksitas Siklomatik: Build atau Refaktor Selanjutnya?
Kompleksitas siklomatik mengukur jumlah jalur independen yang bisa dilalui dalam satu fungsi kode. Angka di atas 10 adalah sinyal untuk mulai waspada; angka di atas 25 artinya fungsi itu sudah menjadi bom waktu yang menunggu meledak di produksi. Metrik ini tidak subjektif: bisa dihitung otomatis, bisa dipasang di CI/CD, dan bisa dijadikan threshold untuk memutuskan kapan kamu lanjut build fitur baru dan kapan kamu wajib berhenti dulu untuk beresin utang teknis yang menumpuk.
TL;DR: Kompleksitas siklomatik adalah metrik yang menghitung berapa banyak jalur logis independen dalam satu fungsi. Skor di atas 10 butuh perhatian ekstra; di atas 25 artinya fungsi itu perlu segera direfaktor. Alat seperti SonarQube, CodeScene, dan CodeClimate bisa mendeteksinya secara otomatis. Gunakan metrik ini bukan sebagai target kesempurnaan, melainkan sebagai threshold objektif: kapan utang teknis sudah cukup berbahaya untuk diperbaiki sebelum melanjutkan build fitur berikutnya.
Apa Itu Kompleksitas Siklomatik dan Kenapa Dev Sering Salah Paham?
Kompleksitas siklomatik pertama kali diperkenalkan Thomas McCabe pada 1976 dalam paper yang masih relevan sampai sekarang. Idenya sederhana: setiap percabangan logis dalam kode -- if, else, while, for, switch/case -- menambah satu jalur independen yang harus bisa diuji secara terpisah.
Rumus formalnya: CC = E - N + 2P, di mana E adalah jumlah edge dalam flow graph, N adalah jumlah node, dan P adalah jumlah komponen yang terhubung. Dalam praktik sehari-hari, ada cara yang lebih mudah: mulai dari 1, tambahkan 1 untuk setiap kondisi percabangan yang kamu temui.
def proses_pesanan(pesanan): # CC = 1
if pesanan.valid: # CC = 2
if pesanan.stok > 0: # CC = 3
if pesanan.user.premium: # CC = 4
kirim_ekspres()
else:
kirim_reguler()
else:
log_error()Fungsi di atas punya CC = 4 -- masih aman untuk diuji dan dipahami. Masalahnya, di proyek nyata, fungsi seperti ini tumbuh organik selama berbulan-bulan. Setiap edge case ditempel langsung di tempat. Sebelum tim sadar, ada fungsi dengan CC = 35+ yang tidak ada yang berani disentuh karena tidak ada yang tahu apa yang akan rusak kalau diubah.
Kesalahpahaman paling umum: developer panik melihat CC = 12 padahal yang lebih penting adalah tren perubahan dari waktu ke waktu. CC yang naik 3 poin per sprint jauh lebih berbahaya dari CC = 20 yang stabil tidak berubah selama setahun penuh.
Angka Berapa yang Benar-Benar Perlu Dikhawatirkan?
Standar industri menurut McCabe dan dikonfirmasi NIST Special Publication 500-235:
CC 1-10: Kode simpel, mudah diuji dan dipahami
CC 11-20: Kompleks, mulai butuh perhatian ekstra
CC 21-50: Risiko tinggi, jadwalkan refaktor secepatnya
CC di atas 50: Praktis tidak bisa diuji secara memadai
Angka ini bukan dogma yang harus diikuti buta. Konteks tetap penting. Sebuah parser bahasa atau finite state machine bisa punya CC = 40 tapi tetap terstruktur dengan baik, terdokumentasi, dan dilengkapi test yang memadai. Yang perlu dicermati adalah tren kenaikan dari commit ke commit -- bukan snapshot angka absolut di satu titik waktu.

Cara paling berguna untuk membaca angka CC: lihat distribusinya di seluruh codebase. Kalau 80% fungsi punya CC di bawah 10 tapi ada 5 fungsi dengan CC di atas 30 -- itu bukan masalah rata-rata, itu masalah 5 fungsi spesifik yang perlu ditangani segera sebelum mereka jadi sumber bug rutin di produksi.
Kenapa Kompleksitas Siklomatik Relevan untuk Keputusan Build vs Refaktor?
Ini bagian yang paling langsung berguna untuk dev solo atau indie hacker yang kerja tanpa tim besar.
Setiap sprint ada dua pilihan: ship fitur baru atau beresin utang teknis. Tanpa metrik objektif, pilihan hampir selalu jatuh ke fitur baru -- karena itu terasa produktif, bisa ditunjukkan ke pengguna atau investor, dan terasa seperti kemajuan nyata. Kompleksitas siklomatik memberikan threshold yang bisa diargumentasikan, bukan hanya ke diri sendiri tapi juga ke stakeholder yang selalu minta fitur.
Aturan praktis yang bisa langsung dipakai sekarang:
Fungsi dengan CC di atas 15: masukkan ke backlog refaktor. Jangan tambahkan fungsionalitas baru ke fungsi itu sampai ada test coverage minimal 70%.
Modul dengan rata-rata CC di atas 10 di semua fungsi: blokir penambahan fitur baru sampai angkanya turun ke bawah 10.
Pull request yang menaikkan CC lebih dari 5 poin sekaligus: wajib review tambahan sebelum merge.
Dengan threshold seperti ini, keputusan "build atau refaktor" tidak lagi ditentukan oleh intuisi, kebiasaan, atau siapa yang paling lantang bicara di standup.
Cara Mengukur Kompleksitas Siklomatik di Proyek Nyata
Tidak perlu hitung manual satu per satu. Sebagian besar alat static analysis sudah menghitungnya secara otomatis, dan banyak yang bisa langsung diintegrasikan ke pipeline CI/CD yang sudah ada.
Python: Install radon via pip dan jalankan radon cc src/ -s -a. Output langsung menampilkan CC per fungsi plus rata-rata seluruh project. Mudah dimasukkan ke Makefile atau pre-commit hook.
JavaScript / TypeScript: ESLint punya rule complexity bawaan. Tambahkan ke konfigurasi:
{
"rules": {
"complexity": ["error", 10]
}
}Build langsung fail kalau ada fungsi yang melewati threshold yang kamu set.
Java: PMD dan Checkstyle sudah memiliki rule bawaan untuk CC, bisa dikonfigurasi dengan threshold per project.
Go: Install gocyclo via go install github.com/fzipp/gocyclo/cmd/gocyclo@latest, lalu jalankan gocyclo -over 10 . untuk menampilkan semua fungsi yang CC-nya melewati 10.
Integrasi ke CI/CD adalah langkah yang membuat pengukuran ini benar-benar berguna jangka panjang. Kalau PR menaikkan rata-rata CC sebuah modul melewati threshold yang ditetapkan, build langsung fail tanpa perlu debat panjang di code review.

Kapan Kompleksitas Siklomatik Tidak Cukup Sebagai Satu-Satunya Metrik?
CC punya beberapa blind spot yang perlu diakui. Beberapa hal yang tidak diukur:
Coupling tersembunyi: dua fungsi dengan CC = 3 masing-masing, tapi saling ketergantungan parah lewat shared state global atau side effect tersembunyi, tetap menghasilkan kode yang rapuh dan sulit diubah tanpa cascade bug.
Cognitive complexity: beberapa pola kode -- nested ternary operator, callback hell berlapis tiga, closure yang saling mereferensi -- membuat kode sangat sulit dibaca manusia meski nilai CC-nya rendah secara matematis. SonarQube memperkenalkan "cognitive complexity" sebagai metrik terpisah tepat untuk menangkap dimensi ini.
Duplikasi: fungsi identik yang muncul di 15 tempat berbeda, masing-masing dengan CC = 2, tidak akan terdeteksi sebagai masalah oleh CC saja. Tapi ini sumber bug yang sama berbahayanya -- perbaikan bug di satu tempat tidak otomatis memperbaiki 14 tempat lain.
Di sinilah alat seperti CodeScene membedakan diri dari static analyzer biasa. Mereka menggabungkan CC dengan analisis historis dari data git: fungsi mana yang paling sering diubah, siapa yang paling sering menyentuhnya, dan berapa bug yang secara historis muncul di area tersebut. Hasilnya adalah prioritas refaktor yang jauh lebih actionable dari sekadar daftar fungsi dengan CC tinggi.
Untuk project solo atau tim kecil yang baru mulai, CC saja sudah cukup sebagai penjaga pertama. Untuk tim yang lebih besar atau codebase yang sudah bertahun-tahun dalam produksi, kombinasi metrik memberi sinyal yang lebih akurat tentang di mana perlu fokus.
Pola Refaktor yang Benar-Benar Berhasil Menurunkan CC
Ada tiga pola refaktor yang terbukti efektif menurunkan kompleksitas siklomatik tanpa mengubah perilaku program:
Extract method -- pisahkan cabang logis ke fungsi terpisah dengan nama yang menjelaskan intent. Hasilnya: setiap fungsi punya satu tanggung jawab yang jelas, lebih mudah diuji secara isolasi.
# Sebelum: satu fungsi dengan CC = 8
def proses(data):
if data.type == 'A':
# 15 baris handling
elif data.type == 'B':
# 12 baris handling
# Sesudah: dispatch table, CC = 2 per fungsi
HANDLER = {
'A': proses_type_a,
'B': proses_type_b,
}
def proses(data):
handler = HANDLER.get(data.type)
if handler:
handler(data)Guard clause -- balik kondisi negatif jadi early return, menghilangkan nesting yang dalam dan membuat alur utama lebih linear:
# Sebelum: bersarang, CC = 4
def kirim(pesanan):
if pesanan:
if pesanan.valid:
if pesanan.stok > 0:
kirim_paket()
# Sesudah: linear, CC = 3 tapi jauh lebih mudah dibaca
def kirim(pesanan):
if not pesanan: return
if not pesanan.valid: return
if pesanan.stok == 0: return
kirim_paket()Strategy pattern -- untuk switch/case besar yang terus bertambah seiring waktu. Alih-alih kondisi yang panjang dan terus diperpanjang, kamu register handler per tipe di sebuah dictionary atau registry yang bisa diperluas tanpa mengubah fungsi inti.
Tidak ada satu pola yang selalu tepat untuk semua situasi. Pilih berdasarkan seberapa sering bagian kode itu berubah dan seberapa banyak tipe baru yang kemungkinan besar akan ditambahkan dalam 3-6 bulan ke depan.
Apa yang Harus Kamu Build Setelah Tahu Angka CC Proyekmu?
Ini bagian yang membuat metrik ini berguna untuk builders dan indie hackers, bukan hanya untuk tim enterprise dengan proses review yang ketat dan terdokumentasi.
Kalau kamu sedang mempertimbangkan apakah akan lanjut build di atas codebase yang ada atau memulai dari awal -- CC bisa jadi bagian dari keputusan yang lebih berdasar data, bukan hanya perasaan.
Panduan sederhana untuk project solo:
Rata-rata CC per modul di bawah 8: lanjut build. Kamu masih di zona aman.
Rata-rata CC per modul antara 8 dan 15: build dengan hati-hati. Pastikan setiap fungsi baru punya test sebelum ditambahkan ke modul yang sama.
Rata-rata CC per modul di atas 15: pertimbangkan serius untuk refaktor dulu, atau ekstrak service baru daripada menambahkan kompleksitas ke modul yang sudah penuh sesak.
Timing adalah kunci. Kalau angkanya di atas 15 dan proyekmu belum punya pengguna aktif, sekarang adalah waktu terbaik dan termurah untuk beresin. Begitu ada pengguna yang bergantung pada sistemmu, prioritas selalu bergeser ke arah "jangan break yang sudah jalan" -- dan ruang untuk refaktor besar menyempit drastis.
Untuk keputusan rebuild total: kalau lebih dari 40% fungsi di modul inti punya CC di atas 20 dan test coverage di bawah 30%, refaktor bertahap berisiko tinggi. Setiap perubahan bisa memperkenalkan bug yang tidak terdeteksi karena tidak ada jaring pengaman. Di titik itu, rebuild dengan arsitektur yang lebih baik dan test dari awal sering lebih cepat dalam hitungan bulan, bukan lebih lambat seperti yang diasumsikan banyak tim.
Yang perlu selalu diingat: kompleksitas siklomatik adalah alat bantu pengambilan keputusan, bukan oracle kebenaran tunggal. Gunakan sebagai input tambahan bersama penilaian teknis dan konteks bisnis -- bukan sebagai pengganti keduanya.