Puanlama
Clean Code Score formülü, Bayesçi büzülme, güven seviyeleri, sıralama, hesaplanmış örnek
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,structurevehygieneiçin,high/mediumgü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:
kloc = analyzedLines / 1000
adjusted(cat) = ( weighted(cat) + projectDensity(cat) × priorKLOC )
/ ( kloc + priorKLOC )
subScore(cat) = 100 × e^( −adjusted(cat) / scale(cat) )Sonra:
score = subScore(duplication) × 0.30
+ subScore(structure) × 0.45
+ subScore(hygiene) × 0.25Sonuç 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:
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
| Sabit | Varsayılan | Anlamı | Yapılandırma dosyasıyla ayarlanabilir mi? |
|---|---|---|---|
SEVERITY_WEIGHT | low 1, medium 3, high 5, critical 8 | İhlal başına ağırlık | Aşağıdaki nota bakın |
CATEGORY_SCALE | duplication 15, structure 45, hygiene 38 | Bir alt puanın ~37'ye düştüğü yoğunluk | ✅ scoring.categoryScales |
CATEGORY_WEIGHT | duplication 0.30, structure 0.45, hygiene 0.25 | Her alt puanın nihai puandaki payı | ✅ scoring.weights |
PRIOR_KLOC | 1 | Büzülmenin gücü | ❌ yalnızca kaynak kodda |
DEFAULT_MIN_LINES_FOR_RANKING | 1000 | Sıralanmak için gereken satırlar | ✅ scoring.minLinesForRanking |
ENGINE_VERSION | 2.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 puan | duplication (ölçek 15) | structure (ölçek 45) | hygiene (ölçek 38) |
|---|---|---|---|
| 90 | 1.6 | 4.7 | 4.0 |
| 80 | 3.3 | 10.0 | 8.5 |
| 70 | 5.4 | 16.1 | 13.6 |
| 50 | 10.4 | 31.2 | 26.3 |
| 37 | 15 | 45 | 38 |
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
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 → 76Rapor 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:
| Seviye | Analiz edilen satırlar | Nasıl okunur |
|---|---|---|
insufficient | < 300 | Çoğunlukla proje ortalamasıdır; karşılaştırmayın |
provisional | 300 – 999 | Yalnızca yol göstericidir |
reliable | 1.000 – 4.999 | Karşılaştırmak için makuldür |
highly_reliable | ≥ 5.000 | Güç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 veanalyzedLines ≥ 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)
| Alan | Formül | Puanda mı? |
|---|---|---|
violationDensity | toplam ağırlıklı puan ÷ KLOC, büzülmeden önce | Hayır |
contributionPercent | geliştiricinin analiz edilen satırları ÷ tüm analiz edilen satırlar | Hayır — bilerek ayrı gösterilir |
netQualityImpact | eklenen ağırlıklı − düzeltilen ağırlıklı | Hayır (pozitif = kaldırdığından fazla borç ekledi) |
activeDays, ilk/son katkı | git log'dan | Hayı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.