08

Puanlama

Clean Code Score formülü, Bayesçi büzülme, güven seviyeleri, sıralama, hesaplanmış örnek

4 dk okuma8 bölüm

Bu doküman Clean Code Score'un tam olarak nasıl hesaplandığını açıklar. Kod src/scoring/ içindedir; her sabit scoringConfig.ts içindedir.

Geliştirici başına girdiler

Atama motorundan (07):

  • analyzedLines: analiz edilen commit'lerde, analiz edilebilir dosyalarda eklediği veya değiştirdiği satırlar;
  • weighted[category]: duplication, structure ve hygiene için, high/medium güvenle eklediği ihlallerin önem ağırlıkları toplamı.

Yalnızca eklenen ihlaller sayılır. Mevcut, düzeltilmiş, hariç tutulmuş ve atanamayan ihlaller puanı asla düşürmez.

Formül

Her kategori için:

text
kloc          = analyzedLines / 1000
adjusted(cat) = ( weighted(cat) + projectDensity(cat) × priorKLOC )
                / ( kloc + priorKLOC )
subScore(cat) = 100 × e^( −adjusted(cat) / scale(cat) )

Sonra:

text
score = subScore(duplication) × 0.30
      + subScore(structure)   × 0.45
      + subScore(hygiene)     × 0.25

Sonuç 0–100 aralığına sıkıştırılır ve yuvarlanır. Yuvarlanmamış değer scoreExact olarak saklanır.

Neden yoğunluk?

Ham ihlal sayıları üretken geliştiricileri cezalandırır: 20.000 satır yazan birinin, 500 satır yazandan daha fazla ihlali olur. KLOC'a bölmek, ne kadar yazdığını değil, yazdığı kodun ne kadar temiz olduğunu ölçer.

Neden üstel fonksiyon?

e^(−density / scale) her ≥ 0 yoğunluğu 100 … 0 aralığına eşler:

  • yoğunluk 0 → 100;
  • yoğunluk = scale → ~37 (bir "e-katı");
  • 0'a yumuşakça yaklaşır ve asla negatif olmaz.

Her ek yoğunluk birimi bir öncekinden daha az puana mal olur; bu yüzden çok kötü tek bir dosya puanı sıfıra indiremez.

Neden Bayesçi büzülme?

Olmasaydı, 50 temiz satır yazan bir geliştirici kusursuz 100 alır, bir gizli bilgi içeren 50 satır yazan ise 0'a yakın alırdı. İkisi de pek bir şey söylemez.

Büzülme, her geliştiriciye proje ortalama yoğunluğunda priorKLOC (= 1 KLOC) "sanal kod" ekler:

  • az kodu olan bir geliştirici proje ortalamasına güçlü şekilde çekilir;
  • çok kodu olan bir geliştirici neredeyse etkilenmez; kendi verisi baskındır.

Kategori başına proje yoğunluğu:

text
projectDensity(cat) = Σ over all developers of weighted(cat)
                      / (total analyzed lines of all commits / 1000)

Projenin tamamı temizse ön bilgi 0'dır ve sıfıra bölme olmaz.

Sabitler

SabitVarsayılanAnlamıYapılandırma dosyasıyla ayarlanabilir mi?
SEVERITY_WEIGHTlow 1, medium 3, high 5, critical 8İhlal başına ağırlıkAşağıdaki nota bakın
CATEGORY_SCALEduplication 15, structure 45, hygiene 38Bir alt puanın ~37'ye düştüğü yoğunluk✅ scoring.categoryScales
CATEGORY_WEIGHTduplication 0.30, structure 0.45, hygiene 0.25Her alt puanın nihai puandaki payı✅ scoring.weights
PRIOR_KLOC1Büzülmenin gücü❌ yalnızca kaynak kodda
DEFAULT_MIN_LINES_FOR_RANKING1000Sıralanmak için gereken satırlar✅ scoring.minLinesForRanking
ENGINE_VERSION2.0.0Önbellek geçersiz kılma anahtarı❌ yalnızca kaynak kodda

Ölçekler gerçek depolar üzerinde (CleanLens'in kendisi, bir Django + React monorepo'su, iki CLI aracı) kalibre edilmiştir; böylece varsayılan kurallarla iyi bakılmış bir kod tabanı yaklaşık 70–85, gerçek teknik borcu olan bir kod tabanı yaklaşık 40–55 puan alır.

Önem ağırlıkları

Ölçek pratikte ne anlama gelir

Bir alt puanın belirli bir değere ulaştığı yoğunluk (KLOC başına ağırlıklı puan):

Alt puanduplication (ölçek 15)structure (ölçek 45)hygiene (ölçek 38)
901.64.74.0
803.310.08.5
705.416.113.6
5010.431.226.3
37154538

Formül: density = −scale × ln(subScore / 100).

Örneğin structure 80, 1.000 satır başına yaklaşık 10 ağırlıklı puana izin verir; bu da KLOC başına kabaca üç medium yapı bulgusu (3 × 3 = 9) demektir.

Hesaplanmış örnek

Proje ortalamaları: KLOC başına duplication 4, structure 20, hygiene 8 ağırlıklı puan.

Geliştirici Alice 2.000 satır (2 KLOC) yazdı ve şunları ekledi:

  • duplication: 2 medium kopya → 6 puan
  • structure: 10 medium bulgu → 30 puan
  • hygiene: 1 low + 3 medium → 10 puan
text
duplication: adjusted = (6 + 4×1)  / (2 + 1) = 3.33  → 100·e^(−3.33/15) = 80.1
structure:   adjusted = (30 + 20×1)/ (2 + 1) = 16.67 → 100·e^(−16.67/45) = 69.1
hygiene:     adjusted = (10 + 8×1) / (2 + 1) = 6.00  → 100·e^(−6/38)     = 85.4

score = 80.1×0.30 + 69.1×0.45 + 85.4×0.25 = 24.0 + 31.1 + 21.3 = 76.4 → 76

Rapor 76/100 (duplication 80 · structure 69 · hygiene 85) gösterir. Alt puanlar Alice'e yapıya odaklanmasını söyler.

Puan güven seviyeleri

Yalnızca analyzedLines değerine dayanır:

SeviyeAnaliz edilen satırlarNasıl okunur
insufficient< 300Çoğunlukla proje ortalamasıdır; karşılaştırmayın
provisional300 – 999Yalnızca yol göstericidir
reliable1.000 – 4.999Karşılaştırmak için makuldür
highly_reliable≥ 5.000Güçlü sinyal

Bu eşikler confidenceLevel() içindedir ve yalnızca kaynak kodda değiştirilebilir.

Sıralama

  • rankable = geliştiricinin bir puanı vardır ve analyzedLines ≥ minLinesForRanking (varsayılan 1.000).
  • Sıralanamayan geliştiriciler yine de puan alır ama ayrı listelenir ("Not ranked — insufficient analysed code").
  • 0 analiz edilen satırı olan bir geliştirici score = null ("no analysed code") alır; bu, kusursuz puandan farklıdır.
  • Sıralama (CLI, Markdown, pano): sıralanabilir geliştiriciler puana göre, en düşük önce, ardından sıralanamayanlar, ardından puanı olmayanlar.

Geliştirici başına diğer sayılar (yalnızca gösterim)

AlanFormülPuanda mı?
violationDensitytoplam ağırlıklı puan ÷ KLOC, büzülmeden önceHayır
contributionPercentgeliştiricinin analiz edilen satırları ÷ tüm analiz edilen satırlarHayır — bilerek ayrı gösterilir
netQualityImpacteklenen ağırlıklı − düzeltilen ağırlıklıHayır (pozitif = kaldırdığından fazla borç ekledi)
activeDays, ilk/son katkıgit log'danHayır

Testler

test/scoring.test.ts şunları denetler: sıfır satırda null; küçük temiz bir örneklem büyük temiz bir örneklemden düşük puan alır; hacim cezalandırılmaz; tek bir kategori bağımsız olarak düşer; puanlar 0–100 içinde kalır; sıfıra bölme yok; ağırlıklar 0.30/0.45/0.25; güven eşikleri; ve yapılandırılabilir sıralama eşiği.