Kompleksitas Siklomatik: Panduan untuk Tim Engineering
Summary
Kompleksitas siklomatik (McCabe, 1976) mengukur jumlah jalur induk melalui fungsi dengan menghitung keputusan: if, elif, case, while, for. Standar 10 dari NIST bukan hukum—ESLint menggunakan 20, Microsoft 25. Masalahnya: fungsi dengan skor 10 bisa mudah dibaca (flat switch), atau fungsi skor 6 bisa susah dipahami (nested conditional). Untuk repo enterprise dengan 5-50 engineer, kompleksitas tinggi sangat berbiaya saat onboarding junior—penelusuran cabang butuh waktu sekuensial. Solusi praktis: ukur baseline terlebih dahulu, gate new code di 10-15, review kedua di 20, technical debt ticket di 50+. Jangan biarkan score menjadi tujuan, tetapi proxy untuk readability.
Kompleksitas siklomatik menghitung jumlah jalur induk dalam sebuah fungsi. Fungsi tanpa cabang skornya 1. Tambah satu if, jadi 2. Tambah switch dengan empat case, loncat ke 6. Angka ini memberitahu berapa banyak test case yang perlu ditulis untuk mencakup setiap jalur, dan berkorelasi dengan berapa lama waktu yang dibutuhkan orang lain untuk memahami fungsi itu.
Itulah seluruh metrik. Yang penting adalah apa yang dilakukan tim dengan angka ini, dan di mana mereka biasanya salah.
Apa Sebenarnya yang Diukur Kompleksitas Siklomatik
McCabe mendefinisikan ini di 1976 sebagai edges dikurangi nodes ditambah dua dalam teori graf. Dalam praktik, tidak perlu teori graf. Hitung titik keputusan: if, else if, case, while, for, catch, &&, ||, ternary. Tambah 1. Itu skornya.
def hitung_diskon(order):
if order.is_vip: # +1
if order.total > 100: # +1
return order.total * 0.8
return order.total * 0.9
elif order.has_coupon: # +1
return order.total * 0.95
return order.totalFungsi ini skornya 4. Tidak tinggi. Tapi sudah tiga level branching untuk fungsi yang seharusnya cuma "apply discount." Itulah pattern yang perlu diperhatikan: kompleksitas bertambah satu elif setiap kali, dan tidak ada yang berbuat jahat.
Dari Mana Angka "10" Itu Berasal (Dan Mengapa Tools Tidak Sepakat)
Angka yang semua orang kutip adalah 10. Berasal dari NIST Special Publication 500-235, di mana McCabe dan Watson menulis bahwa batas di atas 10 sebaiknya dicadangkan untuk tim dengan staff berpengalaman, desain formal, dan rencana test comprehensive. Dengan kata lain: 10 adalah default, bukan hukum.
Tools tidak sepakat di mana harus menarik garis, dan ini penting diketahui sebelum mengatur gate CI:
NIST SP 500-235: 10
ESLint
complexityrule: 20Microsoft CA1502: 25
Steve McConnell, Code Complete: 0-5 ok, 6-10 perhatikan, 10+ refactor
Carnegie Mellon reference ranges: 1-10 simple, 11-20 lebih sulit ditest, 20+ hard to grasp, 50+ unmaintainable
Empat sumber, empat angka. Jika CI gate Anda gagal di 10 dan rekan tim gating di 25, tak satupun yang salah. Kalian hanya mengukur terhadap toleransi risiko yang berbeda. Dokumentasi Microsoft sendiri menjelaskan alasan NIST lebih detail jika ingin sumber aslinya.
Yang sebaiknya diset: 10-15 sebagai warning line untuk kode baru, 20 sebagai titik di mana PR mendapat tinjauan kedua, 50 sebagai stop mutlak. Di bawah 10, jangan habiskan waktu review untuk memperdebatkannya.
Jebakan: Skor Bagus Tidak Berarti Fungsi Mudah Dibaca
Di sinilah tim sering terpukul. Fungsi bisa skornya 6 dan genuinely sulit dibaca, dan fungsi bisa skornya 14 dan trivial.
Ambil flat switch dengan sepuluh case, masing-masing return konstanta. Itu kompleksitas 10, dan paling engineer membacanya dalam lima belas detik karena pattern jelas: satu input, satu output, nada state dibawa antar branch. Sekarang ambil fungsi dengan tiga nested if dan loop yang mutate shared variable. Mungkin skornya 6, tapi akan butuh lima menit bagi senior engineer untuk trace through, karena harus hold seluruh call stack untuk tahu branch mana yang sebenarnya dijalankan.
Kompleksitas siklomatik mengukur jalur. Tidak mengukur nesting depth, variable scope, atau jarak antara kondisi dan efeknya dalam file. Dua fungsi dengan skor sama bisa baca yang sama sekali berbeda.
Kami sudah lihat tim treat "under 10" sebagai proxy untuk "reviewable," push PR karena linter green, lalu lihat junior engineer hilang seharian di fungsi itu tiga minggu kemudian. Skor passed. Readability tidak dapat lebih baik.
Kompleksitas Siklomatik vs. Kompleksitas Kognitif: Dua Pertanyaan Berbeda
SonarSource memperkenalkan Cognitive Complexity di 2017 khusus untuk fix gap ini. Kompleksitas siklomatik menjawab "berapa banyak jalur yang dimiliki fungsi ini." Kompleksitas kognitif menjawab "seberapa sulit fungsi ini dipegang di kepala Anda," dan melakukannya dengan menghukum nesting lebih dari struktur flat.
Switch statement hampir tidak berpengaruh pada skor kognitif. Tiga-level-dalam if dalam loop meningkatkan score cepat, karena setiap level nesting menambah mental cost dari yang sebelumnya. Penjelasan SonarSource sendiri memecah scoring rules jika ingin implementasi sendiri, dan kebanyakan linter yang support kompleksitas siklomatik sekarang support kompleksitas kognitif sebagai rule terpisah kedua.
Skip kompleksitas kognitif jika tim cukup kecil sehingga semua orang sudah tahu di mana fungsi yang berantakan berada. Nyalakan saat memiliki lebih dari dua orang yang tidak menulis kode yang mereka review, karena itulah gap yang dibangun untuk menangkap.

Apa Yang Dilakukan AI Code Review Tools Dengan Angka Ini (Dan Apa Yang Mereka Lewatkan)
GitHub Copilot's code review, CodeRabbit, Qodo, dan Greptile semua surface complexity signals pada PR ke beberapa derajat. Beberapa flag fungsi yang cross threshold. Beberapa summary "PR ini increase complexity di tiga file." Hampir semua tidak bilang kenapa itu matters untuk orang yang akan buka file enam bulan dari sekarang tanpa context.
Itulah gap sebenarnya. Complexity warning pada PR adalah angka dalam komentar. Tidak bilang reviewers apakah branch yang ditambah belong di sini, apakah duplicate logic di tiga file, atau apakah fix yang tepat adalah guard clause versus full extract-method pass. Tools AI bagus di counting. Belum bagus di explain shape dari kacaunya.
Apa yang sebenarnya close gap dalam praktik adalah pair angka dengan pertanyaan yang masih harus dijawab manusia: apakah fungsi ini buat satu hal, atau buat tiga hal dibungkus dalam if statements? Tidak ada linter yang answer itu untuk Anda. Cuma bilang di mana harus lihat.
Kenapa Ini Lebih Penting di Repo 100K-LOC Daripada Side Project
Di codebase yang ditulis sendiri, kompleksitas adalah memory problem yang sudah diselesaikan. Tahu sepuluh fungsi yang berantakan dengan nama, tahu kenapa berantakan, dan route di sekitar tanpa berpikir. Itu bukan situasi kebanyakan audiens di sini.
Di shared repo dengan lima sampai lima puluh engineer, tidak ada yang hold seluruh map. Fungsi skor 22 yang fully understood original author, enam bulan kemudian, jadi fungsi yang engineer berbeda harus reconstruct dari nol, biasanya under deadline. Sudah pernah: grep nama fungsi, Ctrl+F through file, git blame lines yang suspicious, lalu message orang yang left tim delapan bulan lalu.
Di sini juga complexity number mulai interact dengan search. High-complexity function lebih sulit summarize correctly, yang berarti harder untuk teammate, atau code-search tool, untuk describe accurately dalam satu sentence. Tanya "apa yang dilakukan fungsi ini" tentang complexity-4 function dapat clean answer. Tanya hal sama tentang complexity-22 function dengan empat nested branches dan honest answer adalah "tergantung path mana yang ditanya." Ambiguity itu exactly apa yang slow down new hire di hari pertama, dan kenapa kompleksitas worth tracking di repo level, tidak hanya sebagai per-PR lint warning.
Cost Sebenarnya Yang Tidak Ada di Metrik: Onboarding Time
Berikut bagian yang tidak keluar di dashboard. Junior engineer yang join tim tidak experience "cyclomatic complexity of 23." Mereka experience: saya buka file ini, saya tidak tahu branch mana yang jalan, dan saya sudah baca empat puluh menit.
Kami loosely measure ini di beberapa onboarding cycle: function dengan complexity score di atas 15 ambil roughly tiga sampai empat kali lebih lama untuk junior explain dengan benar dalam walkthrough dari function skor di bawah 8. Bukan karena high-complexity function buat lebih banyak, tetapi karena trace mana branch fire di mana condition butuh real, sequential reading time, dan tidak ada yang skim nested conditional dengan benar di first pass.
Di sini metric earn keep-nya untuk team yang onboard frequent. Sebenarnya bukan code-quality number. Proxy untuk "berapa menit ini cost next person yang tidak menulisnya." Track dengan cara itu dan threshold conversation dapat jauh lebih konkret.

Bagaimana Gate Tanpa Memblokir Tim
Ukur sebelum gate. Pilih satu:
Python:
radon cc -a -s .tunjukkan setiap function dengan letter grade;radon cc -n c .filter ke C-grade dan lebih buruk.JavaScript / TypeScript: ESLint's
complexityrule, set dengan['warn', { max: 15 }]untuk mulai.Go:
gocyclo, point ke package dan print setiap function di atas threshold.Java / C#: SonarQube atau PMD, biasanya sudah wired ke CI jika tim run salah satu.
Jalankan sekali di seluruh repo sebelum turn on enforcement. Dapat baseline, dan probably beberapa function di 40-plus range yang predate siapa pun saat ini di team. Jangan blokir build di retroactively; itu hanya teach people untuk route around linter.
Gate new code di 10-15. Flag apa pun cross 20 untuk reviewer kedua, bukan reject otomatis; beberapa dari fungsi itu, seperti flat switch, fine. Treat apa pun past 50 sebagai technical debt ticket, bukan komentar pada PR orang.

Limit hanya hold jika toolchain enforce dengan cara yang sama setiap kali. Rule yang waived untuk deadline sekali di-waive selamanya.
Chase Score atau Chase Fungsi?
Team yang gate hard di 10 dan ship flat, boring, easy-to-read function dalam good shape. Team yang gate hard di 10 dan mulai split function menjadi empat lebih kecil yang call satu sama lain dalam chain yang tidak ada yang bisa trace tanpa tiga tab open sudah buat number lebih baik dan codebase lebih buruk.
Kompleksitas siklomatik adalah smoke detector, bukan fire extinguisher. Bilang di mana untuk lihat. Tidak bilang apa untuk buat setelah di sana, dan treat score sebagai goal daripada readability yang supposed proxy adalah how team end up dengan green dashboard dan repo yang masih ambil new hire tiga minggu untuk feel useful di dalamnya. Metrik bekerja ketika menginformasikan keputusan manusia, bukan menggantikannya dalam proses review. Ingat: tool mengukur kompleksitas siklomatik, tetapi engineer yang mengukur cost sebenarnya dalam waktu onboarding dan produktivitas tim jangka panjang.