---
title: 'Doğrulama ve Hata İşleme'
source: 'https://academia.sh/tr/kurslar/kurumsal-uygulama-cercevesi/dogrulama-ve-hata-isleme'
course: 'Kurumsal Uygulama Çerçevesi'
language: tr
updated: '2026-08-23T14:25:05+00:00'
license: 'CC BY-SA 4.0'
---

# Doğrulama ve Hata İşleme

Dört alanın üçü doğrulama kuralını bir açıklamadan alıyor, biri hiç kural taşımıyor. Kural bozulduğunda ortak hata yanıtının zarfı nesne kabının varsayılanından, alan mesajları ise açıklamanın kendisinden geliyor; aynı geçersiz nesne kap dışında doğrudan işleyiciye verildiğinde hiçbir kural uygulanmıyor ve kusur sessiz kalıyor.

Önceki ders bir isteğin hangi yönteme ulaştığını ölçtü, ama o yönteme ulaşan verinin doğru
biçimde olup olmadığı hiç sorulmadı. Bu ders bunu ele alıyor: bir alanın doğrulama kuralının
kaynakta bir çağrı mı yoksa bir açıklama mı olduğunu, ve kural bozulduğunda ortak hata
yanıtının hangi alanları nereden topladığını ölçüyor.

Doğrulama burada da aynı üç kaynak sorusuna tabi: bir alanın kuralı kaynakta bir ifadeyle mi
yazılı, yoksa yalnız bir işaretle mi belirtiliyor, yoksa kap alan hakkında hiçbir şey
söylemeden mi geçiyor? Bu derste dördüncü bir olasılık daha var — bir alanın **hiçbir**
kuralı olmaması — ve bu, önceki iki dersten farklı bir ölçüm ekliyor: kap yalnız kuralları
nereden aldığını değil, hangi alanların hiç kural taşımadığını da ortaya koyuyor.

Hata işleme de bu dersin konusu, ve iki anlamda: bir isteğin **hangi** kuralı bozduğunu
toplamak (doğrulama), ve bu toplamı çağırana **nasıl** bir biçimde geri vermek (hata
işleme). İkisi ayrı sorular gibi görünse de aynı kapta yaşıyor — kap bir isteği reddederken
hem hangi alanların bozuk olduğunu bulmak hem de bunu tek bir tutarlı yanıta dönüştürmek
zorunda. Bu derste her iki iş de aynı `istek` yönteminde birleşiyor, ama kaynakları farklı
kalıyor: hangi kuralın bozulduğu açıklamadan geliyor, bozulan kuralların nasıl bir araya
toplanacağı ise kabın kendi kararı.

## Dört Alanın Üçü Açıklamadan Kural Alıyor

- **WV11.** Kural kontrolü yalnız alan düzeyinde yapılıyor; yöntem parametreleri, iç içe
  nesneler ya da koleksiyon elemanları burada doğrulanmıyor.
- **WV12.** Bir alanın birden çok kuralı olabilir, ama bu derste her alan en çok bir kural
  taşıyor; kuralların birbirini nasıl sıraladığı ayrı bir ölçüm konusu.

`KayitIstegi` dört alan taşıyor: `ad`, `miktar`, `kategori`, `kod`. İlk üçü sırasıyla
`@ZorunluAlan`, `@PozitifDeger` ve `@Secenekler` açıklamalarını taşıyor; dördüncüsü, `kod`,
hiçbir açıklama taşımıyor. Kaynakta bu dört alanı doğrulayan hiçbir çağrı yok — `dogrula`
yöntemi hangi alanların hangi kurala tabi olduğunu bilmiyor, yalnız yansımayla her alanı
tek tek gözden geçirip üzerinde hangi açıklamanın durduğuna bakıyor. `kod` alanı için
hiçbir açıklama bulunmadığından, bu alan hiçbir zaman doğrulanmıyor — istenen herhangi bir
değer kabul ediliyor.

```java
// Kap.java — dogrulama kurallari aciklamadan doguyor, ortak hata yaniti kabin varsayilani
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;

public class Kap {

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD)
    @interface ZorunluAlan { String mesaj() default "alan bos olamaz"; }

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD)
    @interface PozitifDeger { String mesaj() default "deger sifirdan buyuk olmali"; }

    @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD)
    @interface Secenekler { String[] deger(); String mesaj() default "taninmayan secenek"; }

    interface Isleyici { String calistir(Object istek); }

    List<String> dogrula(Object nesne) throws ReflectiveOperationException {
        List<String> hatalar = new ArrayList<>();
        for (Field f : nesne.getClass().getDeclaredFields()) {
            f.setAccessible(true);
            Object deger = f.get(nesne);

            ZorunluAlan z = f.getAnnotation(ZorunluAlan.class);
            if (z != null && (deger == null || deger.toString().isBlank()))
                hatalar.add(f.getName() + ": " + z.mesaj());

            PozitifDeger p = f.getAnnotation(PozitifDeger.class);
            if (p != null && deger instanceof Integer i && i <= 0)
                hatalar.add(f.getName() + ": " + p.mesaj());

            Secenekler s = f.getAnnotation(Secenekler.class);
            if (s != null && !Arrays.asList(s.deger()).contains(deger))
                hatalar.add(f.getName() + ": " + s.mesaj());
        }
        return hatalar;
    }

    String istek(Object istekNesnesi, Isleyici isleyici) throws ReflectiveOperationException {
        List<String> hatalar = dogrula(istekNesnesi);
        if (!hatalar.isEmpty())
            return "hata; alan-sayisi=" + hatalar.size() + "; alanlar=" + hatalar;
        return isleyici.calistir(istekNesnesi);
    }

    static int kuralliAlanSayisi(Class<?> tip) {
        int n = 0;
        for (Field f : tip.getDeclaredFields())
            if (f.isAnnotationPresent(ZorunluAlan.class) || f.isAnnotationPresent(PozitifDeger.class)
                    || f.isAnnotationPresent(Secenekler.class)) n++;
        return n;
    }

    public static void main(String[] args) throws Exception {
        Kap kap = new Kap();
        Isleyici isleyici = istek -> {
            KayitIstegi k = (KayitIstegi) istek;
            return "kayit-tamam: ad=" + k.ad + ", miktar=" + k.miktar + ", kategori=" + k.kategori;
        };

        System.out.println("-- kacinin kurali aciklamadan geldi --");
        int toplamAlan = KayitIstegi.class.getDeclaredFields().length;
        int kuralliAlan = kuralliAlanSayisi(KayitIstegi.class);
        System.out.println("toplam alan: " + toplamAlan);
        System.out.println("aciklamayla kural tasiyan alan: " + kuralliAlan);

        KayitIstegi gecerli = new KayitIstegi("vida", 12, "elektronik", 501);
        System.out.println("-- gecerli istek --");
        System.out.println(kap.istek(gecerli, isleyici));

        KayitIstegi gecersiz = new KayitIstegi("", -3, "mobilya", 502);
        System.out.println("-- gecersiz istek: kap uzerinden --");
        System.out.println(kap.istek(gecersiz, isleyici));

        System.out.println("-- ayni gecersiz nesne, dogrudan isleyiciye verildi (kap devre disi) --");
        System.out.println(isleyici.calistir(gecersiz));
        System.out.println("kusur turu: sessiz (istisna yok, gecersiz veri isleyiciye ulasti)");
    }
}

class KayitIstegi {
    @Kap.ZorunluAlan String ad;
    @Kap.PozitifDeger int miktar;
    @Kap.Secenekler(deger = {"gida", "elektronik", "giyim"}) String kategori;
    long kod;

    KayitIstegi(String ad, int miktar, String kategori, long kod) {
        this.ad = ad;
        this.miktar = miktar;
        this.kategori = kategori;
        this.kod = kod;
    }
}
```

```
-- kacinin kurali aciklamadan geldi --
toplam alan: 4
aciklamayla kural tasiyan alan: 3
-- gecerli istek --
kayit-tamam: ad=vida, miktar=12, kategori=elektronik
-- gecersiz istek: kap uzerinden --
hata; alan-sayisi=3; alanlar=[ad: alan bos olamaz, miktar: deger sifirdan buyuk olmali, kategori: taninmayan secenek]
-- ayni gecersiz nesne, dogrudan isleyiciye verildi (kap devre disi) --
kayit-tamam: ad=, miktar=-3, kategori=mobilya
kusur turu: sessiz (istisna yok, gecersiz veri isleyiciye ulasti)
```

Dört alanın üçü kural taşıyor, biri taşımıyor. Bu oranın kendisi bir ölçüm: kaynağı okuyan
biri `kod` alanına bakıp hiçbir kısıtlama görmüyor, ve bu doğru bir okuma — kural gerçekten
yok, kap onu hiç doğrulamıyor. Diğer üç alan için durum farklı: kaynakta `ad`'ın boş
olamayacağını söyleyen hiçbir `if` yok, `miktar`'ın sıfırdan büyük olması gerektiğini söyleyen
hiçbir karşılaştırma yok. Bu kurallar yalnız açıklamalarda yazılı, ve onları okuyan `dogrula`
yöntemi olmadan hiçbir etkileri yok. Geçerli isteğin `kayit-tamam` ile sonuçlanması,
geçersiz isteğin ise üç ayrı hatayla dönmesi arasındaki fark, kodun hiçbir satırında açıkça
görünmeyen bu üç kuralın gerçekten çalıştığının kanıtı.

`kod` alanının kural taşımaması, bir eksiklik olarak da okunabilir, bilinçli bir seçim
olarak da. Kaynak metin bu ikisini ayırt etmiyor — bir alanın üzerinde açıklama yoksa, o
alanın "kasıtlı olarak serbest bırakıldığı" ile "kuralı yazmayı unuttuk" arasındaki fark
kaynakta hiçbir iz bırakmıyor. Önceki iki derste eksik olan şey bir davranıştı (bir halka,
bir uç nokta); burada eksik olan şey bir **kısıtlama**, ve kısıtlamanın eksikliği kendini
hiçbir zaman bir hatayla göstermiyor — yalnız her değerin kabul edildiği bir sessizlikle.
Dört alanın üçünün kural taşıması, kalan birinin de aynı dikkatle gözden geçirildiği
anlamına gelmiyor; kural sayısı kadar, kuralsız bırakılan alanların bilinçli bir liste
olarak tutulması da bu yüzden ayrı bir disiplin gerektiriyor.

## Ortak Hata Yanıtı: Zarf Varsayılan, İçerik Açıklama

- **WV13.** Hata yanıtının zarfı (`"hata; alan-sayisi=...; alanlar=..."` biçimi) `istek`
  yönteminin gövdesine yazılı; hiçbir açıklama bu biçimi belirlemiyor.

Geçersiz isteğe verilen yanıt iki parçadan oluşuyor, ve ikisi de farklı bir kaynaktan
geliyor. Zarf — yanıtın kaç hata taşıdığını söyleyen ve hataları bir liste olarak saran
biçim — `Kap.istek` yönteminin kendi gövdesinde yazılı bir dizge kalıbı; bu, önceki
derslerdeki varsayılan davranışlarla aynı aileden: kaynakta hiçbir alan bunu istemedi, kap
her geçersiz istekte bu biçimi kendiliğinden üretiyor. İçerik ise farklı: `"ad: alan bos
olamaz"` ve `"kategori: taninmayan secenek"` dizgeleri doğrudan `ZorunluAlan` ile
`Secenekler` açıklamalarının `mesaj` alanından geliyor. Bu iki açıklama hiçbir özel mesaj
belirtmedi, bu yüzden kendi varsayılan mesajları kullanıldı — ama bir geliştirici
`@Kap.ZorunluAlan(mesaj = "ad girilmeden kayit olusturulamaz")` yazsaydı, yanıtta o metin
görünürdü. Zarf sabit, içerik açıklamanın elindedir.

Bu ayrım pratik bir sonuç doğuruyor: ortak hata yanıtının biçimini değiştirmek için (örneğin
alan sayısını en başa değil en sona koymak) kap'ın kendi kodu değiştirilmeli, hiçbir açıklama
bunu etkilemez. Ama tek bir alanın hata mesajını değiştirmek için kap'a hiç dokunmaya gerek
yok — açıklamanın `mesaj` alanı yeterli. İki değişiklik türü kaynakta iki ayrı yerde durur ve
biri diğerinden çok daha ucuz: mesaj metnini değiştirmek bir açıklama parametresi
düzenlemektir, zarfı değiştirmek kabın kendisini değiştirmektir.

Bu ayrımın bir de tersi var: `dogrula` yöntemi hataları topluyor ama hangi kuralın **önce**
kontrol edileceğine karar veriyor — burada alan bildirim sırasıyla aynı, `ad`, sonra
`miktar`, sonra `kategori`. Bu sıra da kabın kendi kararı; hiçbir açıklama "önce beni kontrol
et" demiyor. Sıralama görünüşte önemsiz duruyor, çünkü bu derste tüm kurallar birlikte
toplanıp tek bir yanıtta veriliyor — hiçbiri diğerini durdurmuyor. Ama bir kap "ilk hatada
dur" biçiminde tasarlansaydı, bu sıra hangi hatanın çağırana ulaşıp hangisinin hiç
görülmeyeceğini belirlerdi; o zaman sıra bir uygulama ayrıntısı olmaktan çıkıp davranışın
kendisi olurdu. Bu derste seçilen "hepsini topla" yaklaşımı bu riski taşımıyor, ama seçim
kabın kendisine ait — kaynakta hiçbir yerde "bütün hatalar toplansın" yazmıyor.

## Kap Dışında Doğrulama Hiç Çalışmıyor

- **WV14.** `isleyici.calistir(gecersiz)` çağrısı `Kap.istek` yöntemini hiç görmüyor;
  `dogrula` hiçbir zaman çağrılmıyor.
- **WV15.** `kod` alanı zaten kural taşımadığı için hiçbir kurulumda doğrulanmıyor;
  aradaki fark yalnız diğer üç alanda görünüyor.

Son ölçüm aynı geçersiz nesneyi — boş `ad`, negatif `miktar`, tanınmayan `kategori` — kap'ı
hiç devreye sokmadan doğrudan işleyiciye veriyor. Sonuç: `kayit-tamam: ad=, miktar=-3,
kategori=mobilya`. Hiçbir istisna yok, hiçbir hata mesajı yok — işleyici geçersiz veriyle de
aynı sadakatle çalışıyor, çünkü onun kendi kodu hiçbir doğrulama içermiyor. Doğrulama
mantığı yalnız `Kap.istek` yönteminin içinde yaşıyor, ve bu yöntem çağrılmadığı sürece üç
açıklamanın hiçbiri okunmuyor.

Bu, kursun tekrar eden sınırlayıcı kuralının bir başka örneği: bir kabın sağladığı garanti,
yalnız o kabın çağrıldığı yol üzerinde geçerlidir. `KayitIstegi` sınıfının üzerindeki
açıklamalar kaldırılmadı, hâlâ orada duruyor — ama onları okuyacak `dogrula` çağrısı devreye
girmediği sürece, sınıf sıradan bir veri taşıyıcısından farksız. Bu, önceki iki derste
görülenden biraz daha riskli bir sonuç doğuruyor, çünkü burada geçersiz veri yalnız yanlış
bir yanıt üretmiyor — geçerliymiş gibi görünen, "tamam" diyen bir yanıt üretiyor. Kural
bozulduğunda kap üzerinden geçen istek açıkça bir hata görüyor; kap dışından gelen aynı veri
ise hiçbir uyarı almadan "tamam" yanıtıyla devam ediyor. Doğrulamanın var olması, onu
uygulayan tek bir giriş noktası olduğu sürece bir güvence; birden fazla giriş noktası
olduğunda — burada kap üzerinden gelen ve doğrudan çağrılan iki yol — güvence yalnız
kullanılan yola bağlı kalıyor.

Bu, önceki iki dersteki sınırlayıcı ölçümlerle aynı köke iniyor ama sonucu bir derece daha
ağır. Birinci derste kap dışında kalan halka yalnız sırasını kaybediyordu, ikinci derste
elle çağrılan denetleyici yalnız kabın kayıt durumunu görmüyordu — ikisi de işlevsel olarak
doğru çalışmaya devam ediyordu. Burada ise kap dışında kalan çağrı, geçersiz veriyi
**geçerliymiş gibi** işliyor: `isleyici`'nin döndürdüğü dizge, doğru bir isteğin
döndürdüğü dizgeyle aynı `kayit-tamam` önekini taşıyor. Çağıran taraf yanıtın biçimine
bakarak iki durumu ayırt edemiyor — ayırt edebilmek için `ad` alanının boş olup olmadığını
ayrıca kontrol etmesi gerekiyor, ki bu da doğrulamanın kap dışında yeniden yazılması anlamına
gelir. Bir uygulamada bu tür bir ikinci giriş noktası genellikle bir arka plan işi, bir toplu
içe aktarma adımı ya da bir başka bileşenin doğrudan çağrısı biçiminde ortaya çıkıyor; hangi
biçimde olursa olsun, kap onun varlığından habersiz ve kural onun üzerinde hiç çalışmıyor.

## Özet

- Dört alanın üçü (`ad`, `miktar`, `kategori`) doğrulama kuralını bir açıklamadan aldı;
  dördüncüsü (`kod`) hiçbir kural taşımadı ve hiç doğrulanmadı.
- Geçersiz istek kap üzerinden geçtiğinde ortak bir hata yanıtı üretti; yanıtın zarfı
  kabın kendi kodunda sabit, alan mesajları ise açıklamaların `mesaj` alanından geldi.
- Bir açıklamanın mesajını değiştirmek yalnız açıklamayı düzenlemeyi gerektirdi; zarfı
  değiştirmek kabın kendi kodunu değiştirmeyi gerektirirdi.
- Aynı geçersiz nesne kap dışında doğrudan işleyiciye verildiğinde hiçbir kural
  uygulanmadı ve işleyici "tamam" anlamına gelen bir yanıt üretti; kusur sessiz kaldı.
- Doğrulamanın güvencesi yalnız kabın çağrıldığı yol üzerinde geçerli; kap dışındaki bir
  çağrı aynı sınıfı hiçbir kısıtlama olmadan kullanabiliyor.

## Sonraki Adım

Bu ders bir isteğin verisinin doğru olup olmadığını ölçtü, ama o veri işlendikten sonra
nereye yazıldığı hiç sorulmadı. Sıradaki ders bunu ele alıyor: bir depo arayüzünün
gerçekleştirimini kabın nasıl sağladığını, ve aynı çağıranın yeniden derlenmeden iki ayrı
gerçekleştirimle nasıl koşabildiğini ölçüyor.
