---
title: 'Statik Çözümleme'
source: 'https://academia.sh/tr/kurslar/android-uretim/statik-cozumleme'
course: 'Test, Başarım ve Dağıtım'
language: tr
updated: '2026-10-21T05:02:43+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Statik çözümlemeyi kodu çalıştırmadan kural ihlali arayan denetim olarak tanımlar'
    - 'Modül başına ihlal sayısının bütçeyi kaç modülde aştığını ölçer'
    - 'Yanlış alarmların ayıklanmasının sayımı ne kadar değiştirdiğini gösterir'
    - 'Temel değer dosyasının ihlalleri düzeltmediğini, yalnız sayımı değiştirdiğini ayırt eder'
---

# Statik Çözümleme

Statik çözümleme kodu çalıştırmadan okur ve kural ihlallerini listeler. Ders modül başına ihlal sayısının bütçeyi kaç modülde aştığını, temel değer dosyasının sayımı nasıl değiştirdiğini ölçer.

Önceki ders testi kararlı kıldı. Test kodu çalıştırarak doğrular; kodun bir kısmı ise hiç çalıştırılmadan da yanlış olduğunu söyler. Kullanılmayan bir kaynak, kapatılmamış bir akış, yanlış sürümde çağrılan bir API bunlardandır. Bu işi otomatik denetleyici yapar. Bu derste ölçülen iş birimi bir kural ihlalidir ve ölçüm modül başına yapılır. Kursun sorusu aynı: **bu ölçüm bütçesini kaç örnekte aşıyor?** Yanıtlar içinde, azında, çoğunda ve hepsinde; örnek bu kez bir modüldür.

Çekirdek önceki derslerle aynıdır.

```kotlin
// Overrun.kt — bir olcumun butcesini kac ornekte astigini siniflandirir
class Budget(val name: String, val limit: Int)

class Overrun(val label: String, val budget: Budget, samples: List<Int>) {
    val total: Int = samples.size
    val over: Int = samples.count { it > budget.limit }
    val verdict: String = when {
        over == 0 -> "icinde"
        over == total -> "hepsinde"
        over * 2 < total -> "azinda"
        else -> "cogunda"
    }

    fun line() {
        println("$label: butce=${budget.name}<=${budget.limit} | asan=$over/$total -> $verdict")
    }
}

fun countOverruns(overruns: List<Overrun>) {
    for (name in listOf("icinde", "azinda", "cogunda", "hepsinde")) {
        println("$name: ${overruns.count { it.verdict == name }}")
    }
}
```

## Kodu Çalıştırmadan Okumak

Statik çözümleme (static analysis), kaynak kodu çalıştırmadan okuyup bir kural listesine karşı denetler. Bulduğu her şeye ihlal denir. İhlal bir hata olabilir, bir uyarı olabilir ya da denetleyicinin yanlış alarmı (false positive) olabilir: kod doğrudur ama kural onu yanlış okur. Bu üçünü ayırmak denetleyicinin değil, ekibin işidir.

Denetleyicinin davranışı bir yapılandırma dosyasından gelir: hangi kuralın açık olduğu ve hangisinin hata sayıldığı orada yazılır. Temel değer olarak kabul edilen ihlaller ise ayrı bir dosyada tutulur.

```xml
<!-- Platform kodu: lint.xml -->
<lint>
    <issue id="UnusedResources" severity="error" />
    <issue id="HardcodedText" severity="warning" />
    <issue id="OldTargetApi" severity="error">
        <ignore path="legacy/**" />
    </issue>
</lint>
```

Bu parça platforma aittir: hangi kural hata sayılır, hangisi uyarı kalır, hangi yol bir kuraldan muaf tutulur. Model yapılandırmayı okumaz; modül başına ihlal sayısını sabit bir tablodan alır ve bütçeyle karşılaştırır.

**TA1.** Modelde sekiz modülün ihlal sayıları sabit bir tablodur; gerçek bir projede sayılar denetleyicinin sürümüne ve kural kümesine göre değişir. Tablo, aynı kural kümesiyle yapılmış tek bir denetimi temsil eder.

## Modül Başına İhlal

Yardımcı dosya modülleri ve ihlal sayısını tanımlar. Her modülün iki sayısı vardır: temel değerden önce var olan ihlaller ve yeni eklenen ihlaller. Ayrıca her modülde denetleyicinin yanlış alarm verdiği ihlaller ayrı sayılır.

```kotlin
// Lint.kt — modullerin ihlal tablosu
class Module(val name: String, val existing: Int, val added: Int, val falseAlarms: Int)

val modules: List<Module> = listOf(
    Module("app", 6, 2, 1),
    Module("core", 3, 0, 0),
    Module("data", 7, 1, 2),
    Module("ui", 9, 3, 1),
    Module("network", 2, 0, 0),
    Module("auth", 5, 1, 0),
    Module("feature-cart", 8, 0, 2),
    Module("feature-search", 4, 2, 1),
)

fun lintFindings(m: Module): Int = m.existing + m.added

fun cleanedFindings(m: Module): Int = lintFindings(m) - m.falseAlarms

fun newFindings(m: Module): Int = m.added
```

`lintFindings` modülün ham ihlal sayısıdır. `cleanedFindings` yanlış alarmlar ayıklandıktan sonraki sayıdır. `newFindings` temel değerden sonra kalan, yani yeni eklenen ihlaldir. Ekip, her modülün en çok beş ihlal taşımasına izin veriyor.

```kotlin
// Main.kt
fun main() {
    val samples = modules.map { lintFindings(it) }
    println("ihlaller: $samples")

    val overrun = Overrun("ham-ihlal", Budget("ihlal", 5), samples)
    overrun.line()
    countOverruns(listOf(overrun))
}
```

```text
ihlaller: [8, 3, 8, 12, 2, 6, 8, 6]
ham-ihlal: butce=ihlal<=5 | asan=6/8 -> cogunda
icinde: 0
azinda: 0
cogunda: 1
hepsinde: 0
```

Sekiz modülün altısı beş ihlalin üstünde. Yalnız `core` ve `network` bütçenin içinde. Ölçüm çoğundadır. Kural bu kez de büyüklüğü görmez: `ui` on iki, `auth` altı ihlalle aynı biçimde aşmış sayılır. Nedeni de görmez: bir modül ihlalleri yıllar içinde biriktirmiş olabilir, bir başkası bir hafta içinde yazılmış olabilir.

## Yanlış Alarmları Ayıklamak

İlk tepki ihlallerin bir kısmının yanlış alarm olduğunu söylemektir. Doğrudur: sekiz modülde toplam yedi yanlış alarm var. Ayıklanırsa sayım değişir. Bunun bütçeyi kaç modülde kurtardığına bakalım.

```kotlin
// Main.kt — yanlis alarmlar ayiklandiktan sonra
fun main() {
    val samples = modules.map { cleanedFindings(it) }
    println("ayiklanmis ihlaller: $samples")

    val overrun = Overrun("ayiklanmis-ihlal", Budget("ihlal", 5), samples)
    overrun.line()
    countOverruns(listOf(overrun))
}
```

```text
ayiklanmis ihlaller: [7, 3, 6, 11, 2, 6, 6, 5]
ayiklanmis-ihlal: butce=ihlal<=5 | asan=5/8 -> cogunda
icinde: 0
azinda: 0
cogunda: 1
hepsinde: 0
```

Beş modül hâlâ bütçenin üstünde ve ölçüm çoğunda kaldı. `feature-search` beş ihlale inerek bütçenin sınırında kaldı; sınırı kesin aşan sayıldığı için artık aşmış değil. Yanlış alarmı ayıklamak sayıyı düşürdü ama sınıfı değiştirmedi. Yanlış alarm, aşımın ana nedeni değildi.

## İhlalin Türleri

Bir otomatik denetleyici bulduğu her şeye aynı ağırlığı vermez. Her kuralın bir ciddiyeti vardır ve yapılandırma dosyası bunu belirler. Hata düzeyindeki bir ihlal sürekli tümleştirme hattını durdurur; uyarı düzeyindeki ihlal raporda görünür ama hattı durdurmaz; bilgi düzeyindeki ihlal ise yalnız bir öneridir. Aynı ihlal sayısı, ciddiyet dağılımına göre çok farklı anlamlar taşır. Bu derste ölçüm ciddiyeti ayırmaz: bütün ihlaller bir birim sayılır. Bu bir sadeleştirmedir ve gerçek bir projede ekip hata düzeyindekileri ayrı bir bütçeyle izleyebilir.

İhlalin iki ayrı kökeni de vardır. Bazı kurallar gerçekten yanlış kodu yakalar: kapatılmayan bir akış, bildirim dosyasında eksik bir izin, kullanılmayan bir kaynak. Bazıları ise bir stil tercihini zorunlu kılar: sabit yazılmış metin ya da adlandırma. İlk grup hataya, ikinci grup uyuma yöneliktir. Ekip hangisini bütçeye saydığını bilmelidir; yoksa bütçe aşımı ne bir hata ne de bir stil sorunu olarak okunabilir.

## Yapılandırma Parçasının Satır Satır Okunuşu

`lint.xml` dosyasının kök öğesi `<lint>` yapılandırmanın kapsamını tanımlar. Her `<issue>` öğesi bir kuralı adlandırır ve `id` alanı kuralın kimliğidir. Birinci öğe `UnusedResources` kuralını `error` düzeyine çıkarır: kullanılmayan bir kaynak artık hattı durdurur. İkinci öğe `HardcodedText` kuralını `warning` düzeyinde bırakır: sabit yazılmış bir metin raporda görünür, ama hattı durdurmaz.

Üçüncü öğe `OldTargetApi` kuralını `error` yapar ve içinde bir `<ignore path="legacy/**" />` satırı taşır. Bu satır, `legacy` dizini altındaki dosyaların bu kural için denetlenmeyeceğini söyler. Bu bir temel değer değildir; kuralın belli bir yola uygulanmamasıdır. İkisi arasındaki fark önemlidir. Muafiyet bir karardır ve yapılandırmada görünür kalır. Temel değer ise bir geçmiş kaydıdır ve dosya olarak ayrı tutulur.

## Yanlış Alarmın Nedenleri

Yanlış alarm, denetleyicinin kodu yanlış anlaması demektir. Kural kodun yalnız yapısına bakar, çalışma zamanını bilmez. Bir kaynağın yalnız yansıma ile kullanılması, kuralın o kaynağı kullanılmamış sanmasına yol açar. Bir işlev başka bir modülden dinamik olarak çağrılıyorsa, kural onu ölü kod sayabilir. Bu durumlarda doğru çare ihlali kodda düzeltmek değil, satırı ya da yolu bilinçli olarak muaf tutmaktır.

Yanlış alarm ayıklamanın iki riski vardır. Birincisi, gerçek ihlallerin yanlış alarm diye ayıklanmasıdır; ekip sayıyı düşürmek için sınırı gevşetir. İkincisi, ayıklamanın belgelenmemesidir; bir yıl sonra kimse neden ayıklandığını bilmez. Bu derste yanlış alarm sayısını tabloda açıkça ayrı tuttuk, çünkü ayıklamayı görünür kılmak bütçenin dürüst kalmasını sağlar.

## Temel Değerin Riskleri

Temel değer dosyası bir borç defteridir ve her borç defteri gibi büyüyebilir. Üç risk öne çıkar.

Birincisi, görünmez borçtur. Gizlenen 44 ihlal ekip toplantılarında konuşulmaz; çünkü raporda yoktur. Yalnız yeni ihlalleri saymak, birikmiş borcun varlığını unutturur. Bu yüzden gizlenen sayı, görünen sayıyla birlikte raporlanır.

İkincisi, eşleşme kırılganlığıdır. Temel değer ihlali bir dosyaya ve bir kural kimliğine bağlar. Dosya yeniden düzenlenir ya da kod taşınırsa, aynı ihlal temel değerle eşleşmez ve yeni ihlal olarak yeniden görünür. Bu bir yanlış alarm gibi görünür, ama nedeni kodun değişmesidir.

Üçüncüsü, temel değerin yenilenmesidir. Ekip bir gün temel değeri baştan üretirse, o güne kadar eklenen bütün ihlaller eski borca dönüşür. Bu işlem bir karar olarak kaydedilmeli ve gerekçesi yazılmalıdır; yoksa temel değer, bütçeyi sıfırlamanın sessiz bir yoluna dönüşür.

## Denetimin Hatta Yeri

Statik çözümleme aynı kuralları üç yerde çalıştırılabilir ve her birinin ödünleşimi farklıdır. Geliştiricinin yerel makinesinde, kod yazılırken ya da kaydedilirken çalışırsa geri bildirim en hızlıdır ama ekibin herkesi aynı sürüm ve ayarla çalıştırdığının garantisi yoktur. Bir değişiklik birleştirilmeden önce çekme isteğinde çalışırsa, herkesin aynı ayarla denetlendiği bilinir ve yeni ihlal birleşmeden yakalanır. Gece koşan bir tam denetimde ise bütün modüllerin ham ihlal sayısı toplanır.

Bu derste ölçülen iki sayı iki farklı yere karşılık gelir. Yeni ihlal bütçesi çekme isteği denetimine uygundur: değişiklik en çok bir yeni ihlal getirebilir. Modül başına beş ihlallik ham bütçe gece koşan tam denetime uygundur: modülün toplam borcu izlenir.

## Bütçeyi Zamanla Sıkılaştırmak

Birikmiş ihlaller varken bütçeyi bir anda sıfıra çekmek mümkün değildir. Ekipler genellikle bütçeyi kademeli düşürür: bugün modül başına beş ihlal, üç ay sonra dört. Her düşüşte aşan modül sayısı artabilir, çünkü sınır sıkılaşmıştır. Bu derste 5'ten 4'e geçişin etkisi görülebilir: ayıklanmış sayımda `feature-search` beş ihlalle sınırda kalıyordu ve bütçe dörde inerse aşan modül sayısı altıya çıkar.

Sıkılaştırma ile iyileştirme aynı şey değildir. Aşan modül sayısı artınca ekip kodun kötüleştiğini sanabilir; oysa sınır değişmiştir. Bu yüzden bütçe değişikliği, ölçüm raporunda ayrı bir not olarak belirtilir. İyileştirme, aşan modül sayısının aynı bütçeyle azalmasıdır.

## Kural Seçimi

Kural kümesi büyüdükçe ihlal sayısı büyür, ama değer aynı oranda büyümez. Ekip bütün kuralları açarsa her modül bütçeyi aşar ve ölçüm hepsinde çıkar; hepsinde artık ayrım yapmaz. Bütün kurallar kapatılırsa hiçbir modül aşmaz ve ölçüm bir şey söylemez. Yararlı kural kümesi, ekibin gerçekten düzeltmeye razı olduğu kurallardan oluşur. Düzeltilmeyecek bir kuralı açık tutmak, yalnız gürültü üretir.

Kural eklemenin bir yolu da deneme süresidir. Yeni bir kural önce uyarı düzeyinde açılır, birkaç hafta boyunca ihlal sayısı izlenir ve yanlış alarm oranı gözlenir. Kural yararlı ihlaller buluyorsa hata düzeyine çıkarılır; gürültü üretiyorsa kapatılır ya da bir yola özgü muafiyetle daraltılır. Bu sıra, kuralın ekibe ani bir engel olarak çıkmasını önler ve bütçenin anlamını korur: bütçeye yalnız ekibin benimsediği kurallar sayılır.

Benimsenmemiş bir kuralın ihlali, bütçeyi şişirir ve gerçek sorunların görünmesini zorlaştırır. Bu yüzden kural kümesini gözden geçirmek, bütçeyi gözden geçirmek kadar düzenli bir iştir; ekip her çeyrekte hangi kuralların işe yaradığını sorar ve yaramayanı kümeden çıkarır.

## Yaygın Yanılgılar

İlk yanılgı, "ihlal sayısı sıfırsa kod doğrudur" düşüncesidir. Otomatik denetleyici yalnız tanımlı kuralları bilir. Mantık hatası, yanlış bir hesap ya da güvenlik açığı çoğu zaman kural kümesinin dışında kalır. Sıfır ihlal, kuralların bulabildiği ihlal olmadığı anlamına gelir.

İkinci yanılgı, "temel değer ihlalleri düzeltir" düşüncesidir. Ölçümde bunu gördük: 44 ihlal temel değerde durdu, sayım değişti, kod değişmedi. Temel değer bir ölçüm aracıdır, bir onarım aracı değildir.

Üçüncü yanılgı, "yanlış alarm çok olduğu için denetleyici işe yaramaz" düşüncesidir. Yedi yanlış alarm, kırk dört ihlalin küçük bir kısmıdır. Ölçümde yanlış alarmı ayıklamak aşan modül sayısını altıdan beşe indirdi; yani yanlış alarm gerçekti ama aşımın ana nedeni değildi. Denetleyiciden vazgeçmek, gerçek ihlalleri de bırakmak demektir.

Dördüncü yanılgı, "bütçe bütün modüllerde aynı olmalıdır" düşüncesidir. Bir çekirdek modül ile bir deneme modülü aynı beklentiyle ölçülmeyebilir. Ama bütçeyi modül başına ayırmak ölçümü karıştırır: her modülün kendi sınırı varsa, aşan modül sayısı artık aynı soruyu yanıtlamaz. Bu derste tek bir bütçe koyduk ve bunun bir sadeleştirme olduğunu açıkça söylüyoruz.

## Sınırlayıcı Ölçüm

Bu ölçümün sınırlayıcısı temel değer dosyasıdır. Gerekçesi şudur: ham sayım borcu ve yeni ihlali birbirine karıştırır. Eski ihlalleri sayımdan düşürmek, modüllerin aynı tablosunu başka bir soruya yanıt verecek biçimde yeniden ölçer. Bütçe de bu soruya uyar: yeni ihlal bütçesi 1'dir, çünkü her değişiklik en çok bir yeni ihlal getirebilmelidir.

Birikmiş ihlalleri bir gecede düzeltmek mümkün değildir. Yaygın çare temel değer (baseline) dosyasıdır: denetleyici o günkü ihlalleri kaydeder ve sonraki denetimlerde yalnız yeni ihlalleri bildirir. Eski ihlaller sayımdan düşer. Bütçe de yeni ihlale göre konur: modül başına en çok bir.

```kotlin
// Main.kt — temel deger dosyasiyla yalniz yeni ihlaller
fun main() {
    val samples = modules.map { newFindings(it) }
    println("yeni ihlaller: $samples")

    val hidden = modules.sumOf { it.existing }
    val visible = modules.sumOf { newFindings(it) }
    println("temel degerde gizlenen: $hidden")
    println("gorunen: $visible")

    val overrun = Overrun("temel-deger", Budget("yeni-ihlal", 1), samples)
    overrun.line()
    countOverruns(listOf(overrun))
}
```

```text
yeni ihlaller: [2, 0, 1, 3, 0, 1, 0, 2]
temel degerde gizlenen: 44
gorunen: 9
temel-deger: butce=yeni-ihlal<=1 | asan=3/8 -> azinda
icinde: 0
azinda: 1
cogunda: 0
hepsinde: 0
```

Ölçüm çoğundadan azına geldi: yalnız `app`, `ui` ve `feature-search` yeni ihlal bütçesini aşıyor. Ama bunun nedeni ihlallerin düzelmesi değil, sayımın değişmesidir. Gizlenen 44 ihlal durduğu yerde duruyor. Temel değer dosyası ihlali düzeltmez; denetleyicinin neye bakacağını değiştirir. Bu iki ölçüm farklı sorulara cevap verir: ilki "bu modülde ne kadar borç var" diye, ikincisi "bu modüle yeni ne eklendi" diye sorar. İkisi birbirinin yerini tutmaz.

**TA2.** Temel değer modelde tek sayıdır: önceki ihlal sayısı. Gerçek bir temel değer dosyası ihlalleri tek tek kaydeder; kod değiştiğinde bir ihlal kaydıyla eşleşmeyebilir ve yeni ihlal olarak yeniden görünebilir.

## Özet

- Bu dersin aşımı: çoğunda. Modül başına beş ihlallik bütçeyi sekiz modülün altısı aştı.
- Yanlış alarmları ayıklamak aşan modül sayısını altıdan beşe indirdi ama ölçümü çoğunda bıraktı; ana neden yanlış alarm değildi.
- Temel değer dosyası ihlalleri düzeltmez, sayımı değiştirir: 44 ihlal gizlendi, 9 yeni ihlal göründü ve ölçüm azına geldi.
- Ham sayım "ne kadar borç var", temel değerli sayım "ne eklendi" sorusunu yanıtlar; ikisi birlikte okunur.
- Kural ihlalin büyüklüğünü ve nedenini görmez; yalnız bütçenin kaç modülde aşıldığını sayar.

## Sonraki Adım

Test ve denetim kodun doğruluğunu ve düzenini sınadı. Uygulamanın kullanıcıya ilk görünüşü ise ayrı bir ölçümdür. Sıradaki ders, `Başlangıç Süresi`, uygulama açılırken yapılan işin başlangıç bütçesini kaç örnekte aştığını ölçer.
