---
title: 'Kod Kalitesi Araçları'
source: 'https://academia.sh/tr/kurslar/ios-uretim/kod-kalitesi-araclari'
course: 'Mimari, Test ve Yayınlama'
language: tr
updated: '2026-10-21T05:03:07+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Biçimlendiricinin ve statik çözümleme kuralının ne denetlediğini birbirinden ayırır'
    - 'Biçim denetiminin zorla açma gibi bir kusuru göremediğini ölçer'
    - 'Kaynak metni tarayan bir kuralın kusuru ayırdığını gösterir'
    - 'Güvenli kullanımda yanlış alarm veren kuralın denetimi gürültülü yaptığını ve istisnanın bunu giderdiğini açıklar'
---

# Kod Kalitesi Araçları

Biçimlendirici ile statik çözümleme kurallarının görevleri ve sınırları; biçim denetiminin ve kaynak metni tarayan bir kuralın aynı kusuru ayırıp ayıramadığının, yanlış alarmın denetimi nasıl bozduğunun ölçümü.

Önceki derste (Başlangıç ve Kaydırma Başarımı) kusur, ölçülen bir işin miktarındaydı. Bu derste kusur kaynak metnin kendisinde: kod derlenir, testler geçer, ama bir satır uygun koşullarda uygulamayı çökertir. Kod kalitesi araçları kodu çalıştırmadan, metnine bakarak denetler.

İki tür araç vardır. **Biçimlendirici** boşlukları, girintiyi ve satır sonlarını düzenler; kodun ne yaptığına bakmaz. **Statik çözümleme** aracı ise kaynak metni okur ve tanımlı kurallara uymayan yapıları bulur: kullanılmayan değişken, çok uzun işlev, zorla açılan isteğe bağlı değer. İkisi de ekibin ortak bir düzende yazmasını sağlar; ama hangi kusuru yakaladıkları farklıdır.

Ölçü ekseni **ayrımdır**: aynı denetimi doğru sürüme ve kusurlu sürüme uygularız. **Ayıran** denetim doğru sürümde geçer, kusurlu sürümde kalır. **Kör** denetim ikisinde de geçer. **Gürültülü** denetim ikisinde de kalır. **Ters** denetim doğru sürümde kalır, kusurlu sürümde geçer. Çekirdek önceki derslerle aynıdır; her ders kendi başına çalıştığı için yeniden veriyoruz.

```swift
// Separation.swift — bir denetimin dogru surumu kusurlu surumden ayirip ayirmadigini siniflandirir
struct Contrast<Output: CustomStringConvertible> {
    let label: String
    let correct: Output
    let faulty: Output
    let passesCorrect: Bool
    let passesFaulty: Bool

    var separation: String {
        switch (passesCorrect, passesFaulty) {
        case (true, false): return "ayiran"
        case (true, true): return "kor"
        case (false, false): return "gurultulu"
        case (false, true): return "ters"
        }
    }

    func describe() -> String {
        let onCorrect = passesCorrect ? "gecti" : "kaldi"
        let onFaulty = passesFaulty ? "gecti" : "kaldi"
        print("\(label) | dogru=\(correct)/\(onCorrect) kusurlu=\(faulty)/\(onFaulty) -> \(separation)")
        return separation
    }
}

func contrast<Output>(_ label: String, correct: Output, faulty: Output, check: (Output) -> Bool) -> Contrast<Output> {
    Contrast(label: label, correct: correct, faulty: faulty, passesCorrect: check(correct), passesFaulty: check(faulty))
}

func countSeparations(_ results: [String]) {
    for name in ["ayiran", "kor", "gurultulu", "ters"] {
        print("\(name): \(results.filter { $0 == name }.count)")
    }
}
```

`Contrast` iki sürümün çıktısını ve denetimin her biri hakkındaki kararını tutar; `separation` etiketi bu iki karardan türer. `contrast` aynı kapanışı iki çıktıya uygular, `countSeparations` dört kategoriyi sayar. **Kural nedeni:** bir denetimin değeri geçmesinde değil, iki sürümü ayırmasında yatar.

## Zorla Açma

Swift'te isteğe bağlı bir değer `nil` olabilir. Ünlem işaretiyle zorla açmak, değerin `nil` olmadığını varsaymaktır; varsayım yanlışsa uygulama o satırda çöker. Kusurlu sürüm bir metni sayıya çevirir ve sonucu zorla açar. Doğru sürüm `guard let` ile `nil` durumunu ele alır.

```swift
// kusurlu ve duzeltilmis — KAYNAK
func total(of text: String) -> Int {
    let value = Int(text)!
    return value
}

func total(of text: String) -> Int {
    guard let value = Int(text) else { return 0 }
    return value
}
```

Kullanıcının girdiği "12" metni iki sürümde de on ikiye çevrilir. Girdi "on iki" olduğunda kusurlu sürüm çöker, doğru sürüm sıfır döner. Test bu girdiyi hiç denemediyse iki sürüm de geçer; kusur üretimde bir kullanıcının beklenmedik girdisinde ortaya çıkar.

## Biçim Denetimi ve Kural Denetimi

Aşağıdaki **model**, iki aracın görevini kaynak metin üzerinde kurar; gerçek bir aracın kendisi değildir. Kaynak, satırların bir dizisi olarak tutulur. Model kodu çalıştırmaz; yalnız metni tarar, tıpkı bir statik çözümleme aracı gibi.

`formatViolations` biçim denetimidir: tab, satır sonunda boşluk ve dört boşluğun katı olmayan girinti sayar. `forceUnwraps` kural denetimidir: bir isim, `)` ya da `]` hemen ardından gelen ve `=` ile devam etmeyen ünlem işaretlerini sayar. Eşit değildir karşılaştırması ve bir değeri olumsuzlayan başa gelen işaret zorla açma değildir ve sayılmaz. `allowLiterals` açıkken, bağımsız değişkeni yalnız bir sabit metin olan çağrının zorla açılmasına izin verilir.

```swift
// Lint.swift — bicim denetimi, zorla acma kurali, kaynak satirlari
func formatViolations(in lines: [String]) -> Int {
    var count = 0
    for line in lines {
        let indent = line.prefix(while: { $0 == " " }).count
        if line.contains("\t") || line.last == " " || indent % 4 != 0 {
            count += 1
        }
    }
    return count
}

func isLiteralCall(_ chars: [Character], closeIndex: Int) -> Bool {
    var depth = 0
    var open = closeIndex
    while open >= 0 {
        if chars[open] == ")" { depth += 1 }
        if chars[open] == "(" { depth -= 1 }
        if depth == 0 { break }
        open -= 1
    }
    guard open >= 0 else { return false }
    let inner = chars[(open + 1)..<closeIndex]
    let afterLabel = inner.firstIndex(of: ":").map { inner[($0 + 1)...] } ?? inner[...]
    let argument = afterLabel.drop(while: { $0 == " " })
    return argument.first == "\"" && argument.last == "\""
}

func forceUnwraps(in lines: [String], allowLiterals: Bool) -> Int {
    var count = 0
    for line in lines {
        let chars = Array(line)
        for index in chars.indices where chars[index] == "!" && index > 0 {
            let previous = chars[index - 1]
            let next: Character = index + 1 < chars.count ? chars[index + 1] : " "
            let postfix = previous.isLetter || previous.isNumber || previous == "_" || previous == ")" || previous == "]"
            if !postfix || next == "=" { continue }
            if allowLiterals && previous == ")" && isLiteralCall(chars, closeIndex: index - 1) { continue }
            count += 1
        }
    }
    return count
}

let correctLines = [
    "func total(of text: String) -> Int {",
    "    guard let value = Int(text) else { return 0 }",
    "    return value",
    "}"
]

let faultyLines = [
    "func total(of text: String) -> Int {",
    "    let value = Int(text)!",
    "    return value",
    "}"
]

let correctLiteralLines = [
    "func home() -> URL {",
    "    return URL(string: \"https://example.com\")!",
    "}"
]

let faultyLiteralLines = [
    "func link(_ input: String) -> URL {",
    "    return URL(string: input)!",
    "}"
]
```

Dört kaynak vardır. `correctLines` ve `faultyLines` aynı biçimde yazılmıştır; yalnız ikincisinin ikinci satırı zorla açar. `correctLiteralLines` sabit bir adresi zorla açar: bu adres derleme anında bellidir ve geçerlidir, yani çökme olasılığı yoktur. `faultyLiteralLines` girdiden gelen bir metni zorla açar ve geçersiz adreste çöker.

### Biçim Kör, Kural Ayırır

İlk ölçüm iki denetimi `total` işlevinin iki sürümüne uygular.

```swift
// main.swift — bicim denetimi ve zorla acma kurali
let format = contrast("bicim-denetimi", correct: formatViolations(in: correctLines), faulty: formatViolations(in: faultyLines), check: { $0 == 0 }).describe()
let rule = contrast("zorla-acma-kurali", correct: forceUnwraps(in: correctLines, allowLiterals: false), faulty: forceUnwraps(in: faultyLines, allowLiterals: false), check: { $0 == 0 }).describe()

countSeparations([format, rule])
```

```
bicim-denetimi | dogru=0/gecti kusurlu=0/gecti -> kor
zorla-acma-kurali | dogru=0/gecti kusurlu=1/kaldi -> ayiran
ayiran: 1
kor: 1
gurultulu: 0
ters: 0
```

`bicim-denetimi` kör: iki sürüm de düzgün girintilidir, satır sonunda boşluk yoktur. Kodun çökebileceğini biçim söylemez. `zorla-acma-kurali` ayıran: doğru sürümde ünlem yoktur, kusurlu sürümde bir tane vardır.

Bu, biçimlendiricinin gereksiz olduğu anlamına gelmez; farklı bir soruyu yanıtlar. Biçim, kodun okunabilirliğini ve inceleme sırasında gereksiz fark çıkmamasını sağlar. Kusuru bulmak ise kural denetiminin işidir. Biri diğerinin yerine geçmez; "biçim denetimi temiz" cümlesi kodun doğru olduğu hakkında bir şey söylemez.

**TS1.** Model satırları metin olarak tarar ve dizgi içindeki bir ünlemi ayırt etmez. Gerçek bir araç sözdizimi ağacı üzerinde çalışır ve bu yanlış eşleşmeleri eler.

**TS2.** Model yalnız tek bir kuralı sayar. Gerçek bir araç onlarca kural çalıştırır ve her kuralın ayrımı ayrıca ölçülmelidir.

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

Bir kural kusuru bulabilir ve yine de kötü bir denetim olabilir: güvenli kullanımı da kusur sayarsa. Sabit bir adresi zorla açmak çökmez; kural bunu da işaretlerse ekip uyarıları görmezden gelmeyi öğrenir.

Aşağıdaki ölçüm sıkı kuralı ve sabit metin istisnalı kuralı, sabit adresi zorla açan doğru sürüme ve girdiden gelen metni zorla açan kusurlu sürüme uygular.

```swift
// main.swift — yanlis alarm ve istisna
let strict = contrast("siki-kural", correct: forceUnwraps(in: correctLiteralLines, allowLiterals: false), faulty: forceUnwraps(in: faultyLiteralLines, allowLiterals: false), check: { $0 == 0 }).describe()
let exempt = contrast("istisnali-kural", correct: forceUnwraps(in: correctLiteralLines, allowLiterals: true), faulty: forceUnwraps(in: faultyLiteralLines, allowLiterals: true), check: { $0 == 0 }).describe()

countSeparations([strict, exempt])
```

```
siki-kural | dogru=1/kaldi kusurlu=1/kaldi -> gurultulu
istisnali-kural | dogru=0/gecti kusurlu=1/kaldi -> ayiran
ayiran: 1
kor: 0
gurultulu: 1
ters: 0
```

`siki-kural` gürültülü: doğru sürüm de işaretlenir, çünkü kural sabit adresle girdiden gelen metni ayırt etmez. İki sürüm de kalır ve denetim bir şey söylemez. `istisnali-kural` ayıran: bağımsız değişkeni sabit metin olan çağrı serbesttir, girdiden gelen metin işaretlenir.

İstisna tanımlamak da bir karardır. Çok geniş bir istisna kusuru tekrar gizler; çok dar olan yanlış alarmı sürdürür. Burada istisna tek bir koşula, bağımsız değişkenin sabit metin olmasına bağlıdır ve bu koşul kuralın kendisinde yazılıdır; satırın üstüne eklenen "bu satırı atla" yorumları ise her biri ayrı bir denetim kaybıdır.

**TS3.** İstisna yalnız tek bir çağrı biçimini kapsar. Sabit bir metnin gerçekten geçerli olduğu kuralın dışında, ayrıca doğrulanmalıdır.

**TS4.** Model çökmeyi çalıştırmaz. Kusurlu sürümün girdiyle çöktüğü kaynak metnin yapısından bilinir, ölçülmemiştir.

## Sık Yapılan Hatalar

- Biçim denetiminin temiz çıkmasını kodun doğru olduğu diye okumak.
- Kuralları açıp sonuçlarını incelememek; yanlış alarm veren bir kuralı sessizce kapatmak.
- Tüm zorla açmaları işaretleyip güvenli olanları ayırmamak; ekip uyarıyı görmezden gelmeye alışır.
- Her uyarıyı satır yorumuyla susturmak. Bu, kuralı o satırda devre dışı bırakır.
- Statik çözümlemeyi testin yerine koymak. Kural yalnız yazdığı kalıbı bulur, davranışı sınamaz.

## Özet

- Biçimlendirici boşluğu ve girintiyi düzenler; statik çözümleme kuralı belirli bir yapıyı arar. İkisi farklı sorulara cevap verir.
- Zorla açma derlenir ve testlerde çalışır, ama beklenmedik girdide uygulamayı çökertir.
- Biçim denetimi iki sürümde de geçti ve kör kaldı; kural denetimi doğru sürümü geçirip kusurluyu kaldırdı ve ayırdı.
- Güvenli kullanımı da işaretleyen sıkı kural iki sürümde de kaldı ve gürültülü oldu; sabit metin istisnası ayrımı geri getirdi.
- Bir kuralın değeri, kusuru bulmasında ve güvenli kullanıma karışmamasında yatar.
- Bu dersin ayrımı: **kör**.

## Sonraki Adım

Test ve başarım denetimlerinin ardından kod, kullanıcıya ulaşmak üzere paketlenir. Sıradaki konu Dağıtım, ilk dersiyle İmzalama ve Sağlama Profilleri ile uygulamanın kimliğinin nasıl kanıtlandığını anlatır.
