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.

Gece masa başında iki monitörlü mühendis, bir ekran kod düzenleyicisinin üzerinde parlayan dallanmış çizgilerin karışık ağını gösteriyor

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.toplam

Bu 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:

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.

Kırmızı ip ile bağlanan index kartlarının branching karar ağacı deseniyle irili ufaklı tahta

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.

Kıdemli mühendis dizüstü bilgisayar ekranını gösterirken junior mühendis not alırken pairing oturumu sırasında

Gate Yapmadan Takımı Nasıl Engelle

Gate koymadan önce ölçün. Birini seçin:

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.

Mekanik klavyede elle yazarken, kırmızı ve yeşil diff çubukları ile blurred pull request review arayüzünün önünde

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.

Frequently asked questions

Döngüsel karmaşıklık ne ölçer?
Bir fonksiyonun kaç bağımsız yolundan geçtiğini sayar. Her if/else if/case/while/for/catch/&&/||/ternary birer karar noktasıdır. Linter'lar bunu fonksiyon başına puanladıkça ve takımlar bu puanları bir gate tanımlamak için test ederlerse ekipler yüksek sayılara başvururlar.
NIST'in '10' eşiği ne anlama gelir?
NIST SP 500-235, McCabe ve Watson tarafından 10'un default bir konservatif sınır olduğunu söylediler; tecrübeli personeli olan, resmi tasarıma ve kapsamlı test planı olan takımlar için. Bu evrensel bir kanun değildir; ESLint 20 önerir, Microsoft 25 önerir. Takımınızı bilenlere göre ayarla.
Temiz skor okunabilirlik anlamına mı gelir?
Hayır. Düz switch-case 10 skor alabilir ve 15 saniyede okunabilir. Üç nested-if ve shared-state loop 6 skor alabilir ve beş dakika alabilir. Karmaşıklık yolları sayar, nesting derinliğini değil.
Bilişsel karmaşıklık döngüsel karmaşıklıktan nasıl farklı?
Bilişsel karmaşıklık nesting derinliğini cezalandırır. Daha gerçekçi öğedir: açısından nested yapısı ne kadar okunması zor. SonarSource 2017'de tanıttı. Çoğu modern linter şimdi her ikisini de destekler.
Nasıl gate yapabiliriz onu kırmaması?
Ölçün ilk (radon/ESLint/gocyclo/SonarQube). Yeni kodu 10-15'te uyarı. 20 = ikinci reviewer. 50+ = teknik borç. Retroaktif blokaj yapmayın; bu yeterli sadece insanları adımları öğretir.
Tüm yüksek-karmaşıklık fonksiyonları refactor etmeliyiz mi?
Hayır. Skor anı, okunabilirlik değil. Temiz bir düz-switch ya da ternary-chain da 10+ skor alabilir ve anlaşılması kolay. Metrik nereye bakacağınızı söyler; nerede karar sizin için hala ihtiyaç.