Statik analiz kurallarını ekibe dayatmadan benimsetmek
Lint kuralları neden CI'da sessizce kapatılıyor? Yeni koda çizgi çekmekten kaçış yollarını saymaya kadar, statik analizin ekipte tutunmasını sağlayan pratik yöntemler.
Statik analiz aracını projeye eklemek bir öğleden sonralık iş. Ekibin o aracı benimsemesi ise genellikle hiç olmuyor. Tipik seyir şu: birisi lint kurallarını açar, ilk çalıştırmada dört bin uyarı çıkar, kimse tek tek düzeltmeye girişmez, üç hafta sonra CI'da continue-on-error: true belirir ve araç orada sessizce ölür.
Sorulacak soru şu: kuralları kimseye dayatmadan nasıl işler hale getirirsiniz?
Sıfırdan başlamayın, çizgiyi bugüne çekin
Mevcut kod tabanında binlerce uyarı varsa hiçbir kural benimsenmez, çünkü uyarı listesi zaten gürültü. Çözüm, geçmişi affedip yalnızca yeni kodu denetlemek.
Çoğu araçta bunun bir karşılığı var. Ruff ve ESLint tarafında yaygın yol, mevcut ihlalleri bir taban dosyasına yazıp CI'da sadece taban dışına çıkanı hata saymak:
# tabanı bir kez üret
ruff check --statistics . > .ruff-baseline.txt
# CI'da yalnızca değişen dosyaları denetle
git diff --name-only origin/main...HEAD -- '*.py' \
| xargs -r ruff check --no-fix
ESLint için aynı fikir:
{
"scripts": {
"lint:changed": "eslint $(git diff --name-only origin/main...HEAD -- '*.ts' '*.tsx')"
}
}
Bu yaklaşımın maliyeti şeffaf: eski kod denetlenmiyor. Kazancı ise ekibin ilk gün gördüğü uyarı sayısının dörtten az olması. Benimsenme oranını belirleyen şey kuralın doğruluğu değil, ilk temasta çıkan liste uzunluğu.
Otomatik düzeltilebilen kuralı insana sormayın
Bir kural --fix ile düzeltilebiliyorsa, o kuralı pull request yorumu haline getirmek insanın zamanını çalmaktır. Biçimlendirme, import sıralaması, gereksiz parantez, tırnak tipi — bunların tamamı commit öncesi çalışan bir kancaya ait.
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.9
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
Kancanın tek şartı hızlı olması. İki saniyeyi geçen bir pre-commit kancası, ekipte --no-verify alışkanlığı üretir ve o alışkanlık geri dönmez. Bu yüzden kancada yalnız değişen dosyalar denetlenmeli, tip denetimi ve test gibi ağır işler kancaya konmamalı.
Kaba bir ayrım işe yarıyor:
- Otomatik düzeltilebilir → pre-commit, kimse görmez
- Düzeltilemez ama kesin → CI'da hata, tartışma yok
- Yoruma açık → kural değil, kod incelemesinde konuşulur
Üçüncü gruptaki bir şeyi ikinci gruba koymak, benimsenmeyi öldüren asıl hamle. "Fonksiyon 40 satırı geçmesin" kuralı buna iyi örnek: doğru bir sezgi, kötü bir CI hatası.
Kuralı açarken gerekçeyi koda yazın
Kural dosyasında çıplak bir kod listesi duruyorsa, altı ay sonra kimse neden açıldığını hatırlamaz ve ilk sürtünmede kural kapatılır. Gerekçe kural dosyasının içinde durmalı:
[tool.ruff.lint]
select = [
"E", "F", # temel hatalar
"B", # flake8-bugbear: B008 varsayılan argümanda fonksiyon çağrısı
# -> üretimde iki kez ısırdı, PR #412 ve #556
"ASYNC", # async fonksiyonda bloklayan çağrı
]
ignore = [
"E501", # satır uzunluğu formatter'ın işi, burada tekrar denetlemiyoruz
]
Bu yorumların pratik faydası tartışmayı kısaltmak. Kural yüzünden takılan geliştirici, gerekçeyi okuyup ya kabul ediyor ya da somut bir karşı örnekle geliyor. İkisi de "bu lint saçmalıyor" cümlesinden iyi.
Yeni kuralı önce uyarı olarak çalıştırın
Bir kuralı doğrudan hata seviyesinde açmak, o kuralın kod tabanınızda kaç kez tetiklendiğini bilmeden yapılan bir bahis. Aracın rapor kipi varsa iki hafta uyarı olarak bırakın, tetiklenme sayısını ölçün, sonra karar verin.
# kural gerçekten kaç yerde patlıyor?
ruff check --select B008 --statistics .
Sayı beklediğinizden büyükse, kural muhtemelen sizin kod tabanınıza uymuyor ya da düzeltmesi ayrı bir iş kalemi. İkisi de kuralı hata yapmadan önce bilinmesi gereken şey.
CI'daki hata mesajı çözüm önerisi içersin
Statik analiz hatası veren bir CI adımı, geliştiriciye ne yapacağını söylemiyorsa benimsenmez. Adımın çıktısına tek satır eklemek fark yaratıyor:
- name: Lint (yalnız değişen dosyalar)
run: |
if ! npm run lint:changed; then
echo "::error::Lint hatası. Yerelde düzeltmek için: npm run lint:changed -- --fix"
echo "Kuralın gerekçesi için eslint.config.js içindeki yorumlara bakın."
exit 1
fi
Kapatma yolunu açık bırakın, ama iz bırakarak
Kaçış yolu olmayan kural, --no-verify ile toptan atlanır. Kaçış yolu satır bazında ve gerekçe zorunlu olduğunda ise iz kalır:
# ruff: noqa: B008 -- FastAPI Depends() varsayılan argümanda kullanılıyor, kasıtlı
Bu satırları düzenli olarak saymak, kural setinizin sağlığı hakkında rapor niteliğinde:
grep -rn "noqa\|eslint-disable" --include='*.py' --include='*.ts' . | wc -l
Sayı sürekli artıyorsa kural yanlış, geliştirici değil.
Özetle ne yapacaksınız
Yeni kod için denetim açın, eskiyi affedin. Otomatik düzeltilebilen her şeyi kancaya alın ve insana hiç göstermeyin. Yeni kuralı önce ölçün, sonra hata seviyesine çıkarın. Gerekçeyi kural dosyasına yazın, kaçış yolunu bırakın, kaçışları sayın.
Bunları yaptığınızda kimseye kural dayatmış olmuyorsunuz; sadece kuralın maliyetini benimsenebilecek kadar düşürüyorsunuz.
- statik analiz
- lint
- CI
- kod kalitesi