Döngüsel Karmaşıklık: Metriklerde Doğru Kararlar Almak
Summary
Döngüsel karmaşıklık bir fonksiyonun kaç bağımsız yolundan geçtiğini ölçer. NIST'in meşhur '10' eşiği belgelerdeki bağlamını kaybetmiştir. Aslında önemli olan okunabilirlik ve onboarding zamanıdır. Linter'a güvenmek yerine takım kültürünü inşa etmelisiniz. Bu metrik yalnızca bir araçtır, kültür değişimi en önemlidir şüphesiz.
Döngüsel karmaşıklık, bir fonksiyonun kaç bağımsız yolundan geçtiğini sayar. Hiçbir dallanması olmayan bir fonksiyon 1 puan alır. Bir if ekleyin, 2 olur. Dört durumlara sahip bir switch ekleyin, 6'ya sıçrar. Sayı aynı zamanda şu şeyi söyler: tüm yolları kaplamak için kaç test durumuna ihtiyacınız var ve bir yabancının fonksiyonu kafasında tutması ne kadar zaman alır.
Hepsi bu kadar. Gerçekten önemli olan takımların bununla ne yaptıklarıdır. Ve bunun hangi yerlerde yanlış kullanıldığıdır.
Döngüsel Karmaşıklık Gerçekte Ne Sayar
McCabe bunu 1976'da grafik teorisi terimleriyle tanımladı: kenarlar eksi düğümler artı iki. Uygulamada, grafik teorisine ihtiyacınız yok. Karar noktalarını sayın: if, else if, case, while, for, catch, &&, ||, ternary operatörler. 1 ekleyin. Sonuç score'dur.
def fiyat(siparis):
if siparis.vip_mi: # +1
if siparis.toplam > 100: # +1
return siparis.toplam * 0.8
return siparis.toplam * 0.9
elif siparis.kupon_var_mi: # +1
return siparis.toplam * 0.95
return siparis.toplamBu 4 puan alır. Yüksek değil. Ama zaten "indirim uygula" ile başlayan bir fonksiyon için üç seviye dallanma var. Bu fark etmesi gereken pattern: karmaşıklık bir elif sırasında yaşar ve kimse kötü adam değil. Her dallanma bir neden için eklenir, sonra başka bir neden, sonra üç ay sonra fonksiyon artık anlaşılması zor hale gelmiştir.
"10" Eşiği Nereden Geliyor (Ve Neden Araçlar Anlaşamıyor)
Herkes alıntı yapan sayı 10'dur. NIST Special Publication 500-235'ten gelir. McCabe ve Watson yazmışlardır ki 10'un üstündeki limitler, tecrübeli personeli olan, resmi tasarıma sahip ve kapsamlı test planı olan takımlar için ayrılmıştır. Başka bir deyişle: 10, bir kanun değil varsayılandır.
Toollar, çizgiyi nereye koymacak konusunda anlaşamaz ve bunu bir gate yapılandırmadan önce bilmek önemli:
NIST SP 500-235: 10
ESLint
complexitykuralı: 20Microsoft CA1502: 25
Steve McConnell, Code Complete: 0-5 sorun yok, 6-10 uyarı, 10+ refaktor
Carnegie Mellon referans aralıkları: 1-10 basit, 11-20 test etmesi zor, 20+ anlaşması zor, 50+ bakımı imkansız
Dört kaynak, dört sayı. CI gate'iniz 10'da başarısız olur ve bir iş arkadaşınızın yan proje 25'te gate yaparsa, ikisi de haksız değil. Sadece farklı risk toleranslarına karşı ölçüyorsunuz. Microsoft'un kendi belgeleri NIST mantığını daha detaylı şekilde açıklıyor. Hangi referansı seçersek seçelim, başlangıç noktası ölçüm olmak, henüz bir gate tanımlamadan önce bilgi toplamak.
Aslında ne yapacağız: 10-15 yeni kod için uyarı seviyesi, 20 PR'nin ikinci inceleme alması noktası, 50 zor durdurma. 10'un altında, review zamanı harcamayın tartışmaya.
Tuzak: Temiz Skor Okunabilir Fonksiyon Anlamına Gelmez
Burada ekipler yanılır. Bir fonksiyon 6 skor alabilir ve özünde okunması zor olabilir, ve bir fonksiyon 14 skor alabilir ve tamamen basit olabilir.
On durum döndüren düz bir switch alın, her bir sabit döner. Bu karmaşıklık 10 olur ve çoğu mühendis bunu on beş saniyede okur çünkü pattern açıktır: bir şey girer, bir şey çıkar, dallar arasında taşınan durum yok. Şimdi üç nested if blok ve paylaşılan bir değişkeni mutate eden loop'u olan bir fonksiyon alın. Bu 6 skor alabilir ve bir kıdemli mühendisi beş dakika harcayabilir, çünkü hangi dalda olduğunuzu bilmek için tüm call stack'i kafanızda tutmanız gerekiyor.
Döngüsel karmaşıklık yolları ölçer. Nesting derinliğini, değişken scope'unu ya da bir koşul ve onun etkisinin dosyada ne kadar ayrı oturduğunu ölçmez. Aynı skora sahip iki fonksiyon tamamen farklı bir okuma olabilir. Bu metrik ve okunabilirlik arasındaki fark büyüktür ve görmezden gelinemez.
Ekiplerin "10'un altı" olmasını "reviewable" için proxy olarak davranıştırırız ve linter yeşil olduğu için PR'yi geçiştirirler, sonra üç hafta sonra bir junior mühendisi bu fonksiyon içinde bir öğleden sonra kaybeder. Score geçti. Okuma kolay olmadı. Linter'ın başarısı kodu daha iyi hale getirmedi.
Döngüsel Karmaşıklık vs. Bilişsel Karmaşıklık: İki Farklı Soru
SonarSource, bilişsel karmaşıklığı bu boşluğu doldurmak için 2017'de tanıttı. Döngüsel karmaşıklık "bu fonksiyon kaç yola sahiptir" sorusunu cevaplar. Bilişsel karmaşıklık "bu fonksiyonu kafamda tutmam ne kadar zor" sorusunu cevaplar. Bunu nesting'i düz yapıdan daha fazla cezalandırarak yapar.
Bir switch deyimi bilişsel skoru biraz hareket ettirir. Loop içinde üç seviye-derin if, çünkü nesting'in her ek seviyesi, ondan önceki zihinsel maliyeti bileşikleştirir. SonarSource'un kendi yazısı kendi başınıza uygulamak isterseniz puanlama kurallarını çözer ve çoğu linter'ın döngüsel karmaşıklığı destekleyen artık ayrı bir kural olarak bilişsel karmaşıklığı destekledi.
Bilişsel karmaşıklığı atlayın eğer takımınız herkesin zaten hangi fonksiyonların karışık olduğunu bilecek kadar küçükse. Kodları yazmayan iki kişiden daha fazla olan herkesin onu açtığı anda açın, çünkü tam bu boşluğu yapacak şekilde inşa edildi. Döngüsel ve bilişsel karmaşıklığı birlikte çalıştırmak, ölçüm çeşitliliğini sağlar.

AI Kod Review Araçları Bu Sayıyla Ne Yapar (Ve Neyi Kaçırır)
GitHub Copilot'un code review, CodeRabbit, Qodo ve Greptile'ı tümü karmaşıklık sinyallerini bir PR'ye bir dereceye kadar yüzeyine çıkarırlar. Bazısı eşiği aşan bir fonksiyonu işaretler. Bazısı "bu PR üç dosyada karmaşıklığı artırmıştır" özetler. Hemen hemen hiç biri neden bu kişi için altı ay sonra bağlam olmadan dosyayı açan kişi için önemli olduğunu söylemez.
Bu gerçek boşluk. Bir PR'deki karmaşıklık uyarısı bir yorum içindeki sayıdır. Bir reviewer'a eklenen dalın oraya ait olup olmadığını, onu üç dosya üzerine kopyalayan mantığı triplicate mi yaptığını ya da sağ çözüm koruma klozu ya da tam bir extract-method geçişi mi olduğunu söylemez. AI araçları iyi sayar. Mesharası henüz iyi açıklamıyor. Ölçüm ve açıklama arasında boşluk vardır.
Yapılan asıl boşluğu uygulamada sayıyla birleştirmek, bir insanın hala cevaplaması gereken bir soruyla: bu fonksiyon bir şey mi yapar, yoksa if deyimlerine sarılmış üç şey mi yapar? Hiçbir linter bunu sizin için cevaplamaz. Sadece nereye bakacağınızı söyler. AI tools bile bu noktada size gelir.
100K LOC Repodan Daha Fazla Önemli Neden Yan Proje
Yalnız yazdığınız codebase'te, karmaşıklık zaten çözdüğünüz bellek sorunu. On karışık fonksiyonu isimle bilirsiniz, neden karışık olduklarını bilirsiniz ve onları düşünmeden rotalandırırsınız. Çoğu izleyici bu durumda değil.
Beş ila elliye kadar mühendisle paylaşılan repo'da, kimse tüm haritayı tutmaz. 22 puan alan fonksiyon orijinal yazar tarafından mükemmel anlaşılmış, altı ay sonra başka bir mühendis tarafından sıfırdan yeniden inşa edilen, genellikle deadline altında. Bunu zaten yaptınız: fonksiyon adını grepleyebilir, dosya üzerinde Ctrl+F, şüpheli satırları git blame, sonra sekiz ay önce takımdan gitmek olan birinin mesajı. Evet, bu düzeni bilirsiniz.
Bu da karmaşıklık sayısının aramayla etkileşime girdiği yerdir. Yüksek-karmaşıklık fonksiyon doğru tanımlanması zordur, bu da bir iş arkadaşı ya da kod-araştırma aracının bunu bir cümle içinde doğru şekilde tanımlaması anlamına gelir. "Bu fonksiyon ne yapıyor" hakkında karmaşıklık-4 fonksiyondan sorun ve temiz cevap alırsınız. Karmaşıklık-22 fonksiyonla dört nested dalı olan aynı soruyu sorun ve gerçek cevap "hangi yolu sorduğunuza bağlı." Belirsizlik tam olarak ilk gün yeni işe almanız yavaşlatan şeydir ve bu neden karmaşıklığı per-PR lint uyarısı olarak değil takım düzeyinde izlemeye değer olduğu nedendir.
Gerçek Maliyet Hiç Kimse Metrikte Koymaz: Onboarding Zamanı
Bu dashboard'da gösterilmeyen kısımdır. Junior mühendis takıma katılan "döngüsel karmaşıklık 23" deneyimi yaşamaz. Deneyimledikleri: bu dosyayı açtım, hangi dalın ne zaman çalışacağını bilmiyorum, ve kırk dakika okuyorum. Bu, onboarding'in çoğunda tekrar ettirilir.
Bunu birkaç onboarding döngüsü üzerinden gevşek bir şekilde ölçtük: karmaşıklık puanı 15'in üstünde olan fonksiyonlar, fonksiyonları 8'in altında puan alan yürüyüşten çıkartırız yaklaşık üç ila dört kat daha fazla açıklama zamanı aldı. Yüksek-karmaşıklık fonksiyonları daha fazla yapı yaptığı için değil ama yürüyüş zamanı hangi dala karar verme yollamak dizisel okuma zamanı alır ve kimse ilk geçişte nested koşulu doğru atlar. Takımınız kişi sayısı arttıkça bu maliyet katlanır.
Bu metrik sık onboarding yapan takımlar için kazancını elde ettiği yerdir. Bu gerçekten kod-kalite sayısı değil. "Bunu yazmayan sonraki kişiye kaç dakika mal olacak" için proxy'dir. Bunu bu şekilde izleyin ve eşik konuşması çok daha az soyut hale gelir. Mühendislerin gerçek zamanı ölçülmek başladığında, kararlar anında netleşir.

Gate Yapmadan Takımı Nasıl Engelle
Gate koymadan önce ölçün. Birini seçin:
Python:
radon cc -a -s .her fonksiyonu harf notunun gösterir;radon cc -n c .C-not ve daha kötüsüne filtre uygular.JavaScript / TypeScript: ESLint'in
complexitykuralı,['warn', { max: 15 }]ile başlayarak ayarlanmış.Go:
gocyclo, pakete işaret edin ve eşikten daha az olan her fonksiyonu yazdırır.Java / C#: SonarQube ya da PMD, genellikle biri veya öbürünü çalıştırıyorsa CI'a döşemiş.
Bir kez tüm repo üzerinde çalıştırın before you turn on enforcement. Bir taban alırsınız ve muhtemelen 40-artı aralığındaki birkaç fonksiyonu, şu anda takımda kimse tarafından yapılmamış. Bu retroaktif olarak yapıyı engellemeyin; bu sadece insanları linter etrafında rotaya öğretir. Ölçümü şeffaf yapın, ekip malıyetini anlamaya başlar.
Yeni kodu 10-15'te gate edin. 20'yi geçen her şeyin otomatik reddetme değil ikinci reviewer bayrağı; bazı fonksiyonlar, düz switch gibi, iyidir. 50' den sonraki her şeyi teknik borç bileti olarak davranın, PR üzerine yorum değil. Tutarlılık, kesinlikten çok önemli.

Limit sadece araçların her seferinde aynı şekilde zorlanması durumunda tutulur. Deadline'dan sonra bir kez aldatılmış olan kural sonsuza kadar aldatılmış olur. Linter hiçbir zaman insanı değiştirmez; kültür değiştirir.
Skoru İzle mi yoksa Fonksiyonu İzle mi
10'da zor bir şekilde gate yapan ve düz, sıkıcı, okunması kolay olan fonksiyonlar sevk eden takım iyi şekilde yapılmıştır. 10'da zor bir şekilde gate yapan ve fonksiyonları dört küçük fonksiyona bölme yapan, birbiri arar ve kimse üç sekme açmadan izleyemeyecek olan zincir içinde çağırıyor olan takım sayıyı daha iyi yaptı ve codebase'i daha kötü yaptı.
Döngüsel karmaşıklık bir smoke detectörü olur, yangın söndürücüsü değil. Nereye bakacağınızı söyler. Oraya vardıktan sonra ne yapacağınızı söylemez ve skoru hedef olarak davranmak yerine okunabilirlik için proxy'dir ve ekipler yeşil panolü ve yine de hisseden repo'yu gümrük zamanı yeni işe alma üç hafta hissettir. Metrik, codebase'in sağlığını korumaya yardım edebilir ama insanlar ve kültür olmadan yapamaz.