---
title: 'Şema Sözleşmeleri'
source: 'https://academia.sh/tr/kurslar/veri-muhendisligine-giris/sema-sozlesmeleri'
course: 'Veri Mühendisliğine Giriş'
language: tr
updated: '2026-08-17T18:08:52+00:00'
license: 'CC BY-SA 4.0'
---

# Şema Sözleşmeleri

Üretici ile tüketici arasındaki şema sözleşmesinin kimi kırdığının ve kendi bedelinin sayılması: bir alanın adı değiştiğinde üretici tarafında hatalı satır 0 kalırken tüketici tarafında 200 satır ayıklamada, 200 satır daha tüketimde düşüyor ve özet 55 hücreden 45'e iniyor; sözleşme yazıldığında aynı bozulma aşama 0'da yakalanıyor ama çıktı düzelmiyor; alan kümesini birebir sabitleyen katı sözleşme hiçbir bozulma yokken 1200 iyi satırı engelleyip özeti 25 hücreye düşürüyor; yük düzeyi uygulama 2200 iyi satırı engelleyip hiç çıktı vermiyor, bağdaştırma aşaması ise sunumu tabana döndürürken hattı altı aşamaya çıkarıyor.

Önceki dersin en hızlı yakalanan bozulması `sema_degisti` oldu: alan adı değiştiğinde `sema`
denetimi aşama 0'da ateşledi. O denetimin baktığı alan listesi kodun içine gömülüydü ve listeyi
kimin yazdığı sorulmadı. Liste tüketicinin varsayımıdır; üretici ondan habersizdir.

Bu ders o listeyi bir **veri sözleşmesine (data contract)** çevirir. Üç şey ölçülür: alan adı
değiştiğinde kimin tarafında kaç satır düşüyor, sözleşme yazıldığında bozulma hangi aşamada
yakalanıyor, ve sözleşmenin kendisi ne kadara mal oluyor. Üçüncü sayı en önemlisidir, çünkü
kursun ikinci iddiasının örneğidir: **denetim eklemek de bozar.**

- **VK8.** Kaynak, hat ve sözleşme **kurgudur**; gerçek bir veritabanı, dosya biçimi ya da
  orkestratör çağrılmaz. Tohum **20260218**, ölçü koşumdan bağımsızdır.
- **VK9.** İlişkisel şema, normalleştirme, kısıt ve tip yordamı Veritabanları müfredatında,
  Veri Modelleme ve İlişkisel Kuram kursunda ölçüldü ve **tekrarlanmaz**. Buradaki soru şemanın
  nasıl tasarlandığı değil, **değiştiğinde kimin kırıldığıdır**.
- **VK10.** **Şema değişimi bir saldırı değildir.** Üretici alanın adını daha açık olsun diye
  değiştirir ya da yeni bir alan ekler; ikisi de sıradan bakım işidir.
- **VK11.** Sözleşme **aşama 0'da**, kaynak hatta girmeden koşar ve satır düzeyinde uygulanır:
  uymayan satır engellenir, uyan satır geçer.
- **VK12.** Taban çizgisi **sözleşmesiz hattır**: engellenen satır **0**, yakalanan bozulma **0**.
- **VK13.** Çözünürlük: satır oranının adımı **0,0004**, özet hücresinin **0,0182**. **Sunum
  üzerinde oran basılmaz**, değerin kendisi yazılır.

## Sözleşme Bir Alan Listesi Değildir

Bir alan listesi yalnızca "şu adlar bulunsun" der. Sözleşme üç şeyi birden bildirmek zorundadır:
hangi alanlar **var**, her birinin **türü** ne, ve bildirilmeyen bir alan geldiğinde ne olacak.
Üçüncüsü çoğunlukla yazılmaz ve bu dersin en pahalı sayısı oradan çıkar.

İki uygulama arasındaki fark tek satırlıktır. **Kapsayan** sözleşme, bildirilen alanların var
olmasını ve türlerinin tutmasını ister; fazladan gelen alanı serbest bırakır. **Katı** sözleşme
alan kümesinin bildirilenle **birebir eşit** olmasını ister; fazladan gelen alan da ihlaldir. İkisi
de aynı sözleşme metnini okur ve bozulmuş kaynakta aynı davranır; ayrıştıkları yer **zararsız**
değişimdir.

```python
# KURGUDUR. Sayac okumalari, bes asamali hat ve sozlesme ders icinde tanimlanir;
# gercek bir depo, dosya bicimi ya da orkestrator cagrilmaz.
TOHUM, M32 = 20260218, 0xFFFFFFFF


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
DONEM = [f"2026-{a:02d}" for a in range(1, 13)]
ABONE = {}
for i in range(200):
    r = uretec(TOHUM + 37 * i)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "baslangic": 10000 + int(r() * 60000)}


def kaynak_uret():
    kayit = []
    for i, (ab, a) in enumerate(ABONE.items()):
        e = a["baslangic"]
        for d in DONEM:
            r = uretec(TOHUM + 101 * i + 7 * DONEM.index(d))
            e += 4 + int(r() * 46)
            kayit.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"],
                          "endeks": e, "birim": "m3"})
    return kayit


# ---- HAT: bes asama, her biri kendi dusurdugu satiri sayar
def a1_ayikla(kayit):
    ZOR = ("abone", "donem", "bolge", "endeks", "birim")
    tut = [k for k in kayit if all(a in k for a in ZOR)]
    return tut, len(kayit) - len(tut)


def a2_tekille(kayit):
    gor, tut = set(), []
    for k in kayit:
        ad = (k["abone"], k["donem"])
        if ad in gor:
            continue
        gor.add(ad)
        tut.append(k)
    return tut, len(kayit) - len(tut)


def a3_tuketim(kayit):
    tablo = {(k["abone"], k["donem"]): k for k in kayit}
    cikti, dusen = [], 0
    for k in kayit:
        i = DONEM.index(k["donem"])
        if i == 0:
            continue
        onceki = tablo.get((k["abone"], DONEM[i - 1]))
        if onceki is None:
            dusen += 1
            continue
        try:
            f = int(k["endeks"]) - int(onceki["endeks"])
        except (TypeError, ValueError):
            dusen += 1
            continue
        cikti.append(dict(k, m3=f))
    return cikti, dusen


def a4_ozet(kayit):
    top = {}
    for k in kayit:
        ad = (k["bolge"], k["donem"])
        top[ad] = top.get(ad, 0) + k["m3"]
    return top, 0


def a5_sun(ozet):
    bolge = {}
    for (b, d), v in ozet.items():
        bolge.setdefault(b, []).append(v)
    return {b: round(sum(v) / len(v), 2) for b, v in bolge.items()}, 0


ASAMA = [("ayikla", a1_ayikla), ("tekille", a2_tekille), ("tuketim", a3_tuketim),
         ("ozet", a4_ozet), ("sun", a5_sun)]


def hat(kayit):
    iz, veri = [], kayit
    for ad, f in ASAMA:
        veri, dusen = f(veri)
        iz.append({"asama": ad, "kalan": len(veri), "dusen": dusen})
    return veri, iz


# ---- Ortak tanimin alti bozulma sinifindan bu ders yalnizca birini kosuyor.
def boz_sema(kayit, donem="2026-07"):
    """Uretici alanin adini degistirdi ; degerin kendisi ayni kaldi."""
    yeni, sayac = [], 0
    for k in kayit:
        if k["donem"] != donem:
            yeni.append(k)
            continue
        y = dict(k)
        y["endeks_degeri"] = y.pop("endeks")
        sayac += 1
        yeni.append(y)
    return yeni, sayac


def alan_ekle(kayit, ilk="2026-07"):
    """Uretici zararsiz bir alan ekledi ; var olan alanlar degismedi."""
    return [dict(k, sayac_seri="S" + k["abone"][1:]) if k["donem"] >= ilk else k
            for k in kayit]


# ---- SOZLESME: ureticinin yazdigini bildirdigi satirin tam semasi
SOZLESME = {"abone": str, "donem": str, "bolge": str, "tip": str,
            "endeks": int, "birim": str}


def kapsayan(k):
    """Bildirilen alanlar var ve turleri dogru ; fazla alan serbest."""
    return all(a in k and isinstance(k[a], t) for a, t in SOZLESME.items())


def kati(k):
    """Alan kumesi bildirilenle birebir esit olmali ; eklenen alan da ihlaldir."""
    return set(k) == set(SOZLESME) and kapsayan(k)


def sozlesmeli_al(kayit, kontrol=None):
    """Sozlesme asama 0'da kosar: uyan satir gecer , uymayan engellenir."""
    if kontrol is None:
        return kayit, 0
    gecen = [k for k in kayit if kontrol(k)]
    return gecen, len(kayit) - len(gecen)
```

## Şema Değişimi Kimi Kırıyor

İkinci blok altı kurulumu aynı kaynağa uygular. `giren` sütunu hatta giren satırı, `engel` sözleşme
tarafından aşama 0'da engellenen satırı, `ayikla` ile `tuketim` o iki aşamanın düşürdüğü satırı,
`ozet` dördüncü aşamanın hücre sayısını verir. Son sütun sunulan beş değerin tabanla aynı kalıp
kalmadığını yazar.

```python
KAYNAK_KAYIT = kaynak_uret()
TABAN, _ = hat(KAYNAK_KAYIT)


def olc(ad, kayit, kontrol):
    giren, eng = sozlesmeli_al(kayit, kontrol)
    sunum, iz = hat(giren)
    print(f"{ad:<28}{len(giren):>7}{eng:>7}{iz[0]['dusen']:>8}{iz[2]['dusen']:>8}"
          f"{iz[3]['kalan']:>6}{'ayni' if sunum == TABAN else 'degisti':>9}")


bozuk, n = boz_sema(KAYNAK_KAYIT)
eklenmis = alan_ekle(KAYNAK_KAYIT)
print("taban sunum:", TABAN)
print("adi degisen satir:", n, " eklenen alani tasiyan satir:",
      sum(1 for k in eklenmis if "sayac_seri" in k))
print()
print(f"{'kurulum':<28}{'giren':>7}{'engel':>7}{'ayikla':>8}{'tuketim':>8}"
      f"{'ozet':>6}{'sunum':>9}")
olc("saglam , sozlesme yok", KAYNAK_KAYIT, None)
olc("ad degisti , sozlesme yok", bozuk, None)
olc("ad degisti , kapsayan", bozuk, kapsayan)
olc("alan eklendi , sozlesme yok", eklenmis, None)
olc("alan eklendi , kapsayan", eklenmis, kapsayan)
olc("alan eklendi , kati", eklenmis, kati)
print()
URETICI = ("abone", "donem", "bolge", "tip", "endeks_degeri", "birim")
print("ureticinin kendi semasina uymayan satir:",
      sum(1 for k in bozuk if k["donem"] == "2026-07"
          and not all(a in k for a in URETICI)))
print("sozlesmenin bildirdigi alan:", len(SOZLESME), " hattin okudugu alan:", 5)
```

```
taban sunum: {'merkez': 1321.45, 'kuzey': 1212.55, 'dogu': 881.36, 'bati': 833.09, 'guney': 1065.55}
adi degisen satir: 200  eklenen alani tasiyan satir: 1200

kurulum                       giren  engel  ayikla tuketim  ozet    sunum
saglam , sozlesme yok          2400      0       0       0    55     ayni
ad degisti , sozlesme yok      2400      0     200     200    45  degisti
ad degisti , kapsayan          2200    200       0     200    45  degisti
alan eklendi , sozlesme yok    2400      0       0       0    55     ayni
alan eklendi , kapsayan        2400      0       0       0    55     ayni
alan eklendi , kati            1200   1200       0       0    25  degisti

ureticinin kendi semasina uymayan satir: 0
sozlesmenin bildirdigi alan: 6  hattin okudugu alan: 5
```

Sondan bir önceki satır sorunun yanıtıdır: **üreticinin kendi şemasına uymayan satır 0'dır.**
Üretici alanın adını değiştirmiş, bütün alanları eksiksiz yazmış, yazma işlemi hatasız
tamamlanmıştır. Onun tarafında ölçülebilen hiçbir kusur yoktur. Kırılan taraf tüketicidir ve bunu
ancak kendi hattında sayabilir.

İkinci satır sözleşmesiz durumu verir. Bozulmuş yük hatta olduğu gibi giriyor: ayıklama aşaması
zorunlu alanı bulamadığı için **200 satır** düşürüyor, tüketim aşaması bir dönem sonrasının önceki
değerini bulamadığı için **200 satır daha** düşürüyor. Toplam 400 satır, kaynağın altıda biri.
Özet 55 hücreden **45**'e iniyor ve sunulan beş değerin hepsi değişiyor. Hiçbir yerde bir hata
kaydı yok; hat başarıyla tamamlandı.

Üçüncü satır sözleşmeli durumu verir ve dikkatle okunmalıdır. Sözleşme aşama 0'da 200 satırı
engelliyor, **yakalama gecikmesi 0**. Ama özet yine **45** hücre, sunum yine değişmiş. Sözleşme
çıktıyı düzeltmedi; yalnızca haber verdi. Düşen satırlar aşamalar arasında dağılmaktan çıkıp tek
bir yerde toplandı: 400 satırın 200'ü artık ayıklama aşamasında değil kapıda duruyor, kalan 200'ü
hâlâ tüketimde düşüyor çünkü bir sonraki dönemin önceki değeri gerçekten yok. **Sözleşmenin
ürettiği şey doğru sayı değil, doğru zamanda gelen sinyaldir.**

## Sözleşmenin Bedeli

Son üç satır kursun ikinci iddiasını taşır. Üretici `2026-07` döneminden başlayarak satırlara
zararsız bir alan ekliyor: sayaç seri numarası. Var olan alanların hiçbiri değişmiyor, hiçbir tür
kaymıyor, hattın okuduğu beş alan yerinde duruyor.

Sözleşmesiz hat bu değişimden hiç etkilenmiyor: 2400 satır giriyor, 55 hücre, sunum aynı.
**Kapsayan** sözleşme de etkilenmiyor, çünkü fazladan gelen alanı ihlal saymıyor: engellenen satır
**0**, sunum aynı. **Katı** sözleşme ise **1200 satırı** engelliyor. Eklenen alanı taşıyan satır
sayısı da tam 1200'dür, yani katı sözleşme yeni alanı gören her satırı reddediyor. Özet 55
hücreden **25**'e düşüyor, sunulan beş değerin hepsi değişiyor.

Bu satır bir kaza değil, sözleşmenin tanımından çıkan sonuçtur. Bozulma **yok**. Yakalanan bozulma
**0**. Yanlış engellenen iyi satır **1200**. Kaynağın yarısı, hiçbir kalite kusuru taşımadığı hâlde
hatta girmedi. Bir denetimin bedeli yalnızca yazma ve bakım emeği değildir; **yanlış tanımlanmış
bir sözleşme hattı, hiçbir bozulma olmadan durdurabilir.**

Son satır bedelin ikinci yüzünü gösterir. Sözleşme **altı** alan bildiriyor, hat bunların
**beşini** okuyor; `tip` alanı hiçbir aşamada kullanılmıyor. Sözleşme genişledikçe üretici bağlanır
ve tüketicinin hiç okumadığı bir alanın türü değiştiğinde de hat durur. Kapsayan sözleşmenin
katıdan üstünlüğü bu yüzden mutlak değildir: kapsayan sözleşme fazla alanı serbest bırakırken,
bildirilen alanların değişimini de aynı sertlikte engeller. Sözleşme yazmanın kararı hangi alanın
bildirileceğidir ve her bildirilen alan hem bir güvence hem bir kilit üretir.

## Durdurmak ve Uyarlamak

Sözleşme ihlal edildiğinde ne yapılacağı ayrı bir karardır ve bedeli ayrı ölçülür. Buraya kadarki
bütün satırlar **satır düzeyi** uygulamadır: uymayan satır engellenir, uyan satır geçer. İkinci
seçenek **yük düzeyi** uygulamadır: yükte tek bir uymayan satır varsa tamamı reddedilir. Üçüncü
seçenek engellemek yerine **uyarlamaktır**: tüketici bilinen eski adı sözleşmedeki ada çeviren bir
aşama ekler.

```python
def yuk_duzeyi(kayit, kontrol):
    """Tek satir bile uymuyorsa yukun tamami reddedilir."""
    return ([], len(kayit)) if any(not kontrol(k) for k in kayit) else (kayit, 0)


ESLEME = {"endeks_degeri": "endeks"}


def uyarla(kayit):
    """Ek asama: bilinen eski adi sozlesmedeki ada cevirir."""
    yeni = []
    for k in kayit:
        y = dict(k)
        for eski, ad in ESLEME.items():
            if eski in y:
                y[ad] = y.pop(eski)
        yeni.append(y)
    return yeni


def yaz(ad, giren, eng):
    sunum, iz = hat(giren)
    durum = "ayni" if sunum == TABAN else ("yok" if not sunum else "degisti")
    print(f"{ad:<26}{len(giren):>7}{eng:>7}{iz[3]['kalan']:>6}{durum:>9}")


print(f"{'uygulama':<26}{'giren':>7}{'engel':>7}{'ozet':>6}{'sunum':>9}")
yaz("satir duzeyi , kapsayan", *sozlesmeli_al(bozuk, kapsayan))
yaz("yuk duzeyi , kapsayan", *yuk_duzeyi(bozuk, kapsayan))
yaz("uyarlama + kapsayan", *sozlesmeli_al(uyarla(bozuk), kapsayan))
print()
print("yuk duzeyinde yanlis engellenen iyi satir:", sum(1 for k in bozuk if kapsayan(k)))
print("uyarlamanin ekledigi asama:", 1, " esleme tablosundaki ad:", len(ESLEME))
```

```
uygulama                    giren  engel  ozet    sunum
satir duzeyi , kapsayan      2200    200    45  degisti
yuk duzeyi , kapsayan           0   2400     0      yok
uyarlama + kapsayan          2400      0    55     ayni

yuk duzeyinde yanlis engellenen iyi satir: 2200
uyarlamanin ekledigi asama: 1  esleme tablosundaki ad: 1
```

Üç satır üç ayrı bedel gösterir. Satır düzeyi uygulama yanlış satırı ayıklar ve hattı yürütür;
karşılığında **eksik bir çıktı** üretir ve o çıktı eksik olduğunu kendi üstünde taşımaz. Yük düzeyi
uygulama hiç çıktı üretmez; sunum yoktur. Bu kimi zaman doğru karardır, çünkü yanlış sayı yayımlamak
sayı yayımlamamaktan pahalıdır — ama bedeli açıktır: **2200 iyi satır** yanlış engellenmiştir ve on
bir sağlam dönemin tamamı, tek bir dönemin kusuru yüzünden beklemeye alınmıştır.

Üçüncü satır tek onarım yoludur: bağdaştırma aşaması eski adı yeni ada çevirdiğinde 2400 satırın hepsi
geçiyor, özet **55** hücreye dönüyor ve sunum tabanla **birebir aynı** oluyor. Bedeli iki kalemde
yazılır. Hat artık **altı aşamalıdır**, beş değil; ve eşleme tablosu tüketicinin sonsuza dek
taşıyacağı bir yüktür. Bu tablo büyüdükçe sözleşme metni ile hattın gerçekte kabul ettiği şema
birbirinden uzaklaşır: sözleşme `endeks` der, hat iki adı da kabul eder. Üretici bir gün eski adı
başka bir anlamda geri getirirse eşleme sessizce yanlış alanı okur ve bu, bu kursun tanımıyla tam
olarak bir sessiz bozulmadır.

## Özet

- Bir veri sözleşmesi üç şeyi birden bildirir: hangi alanlar var, türleri ne, ve bildirilmeyen bir
  alan geldiğinde ne olacak. Üçüncüsü yazılmadığında bedel katı yorumdan çıkar.
- Alan adı değiştiğinde **üreticinin kendi şemasına uymayan satır 0**'dır; kırılan taraf
  tüketicidir ve 400 satır kaybını yalnızca kendi hattında sayabilir.
- Sözleşmesiz hatta bozulma sessizdir: 200 satır ayıklamada, 200 satır tüketimde düşer, özet 55
  hücreden 45'e iner, sunulan beş değer değişir ve hiçbir hata kaydı üretilmez.
- Sözleşme yazıldığında aynı bozulma **aşama 0'da** yakalanır, ama özet yine 45 hücredir; sözleşme
  çıktıyı düzeltmez, doğru zamanda sinyal üretir.
- Katı sözleşme zararsız bir alan eklemesinde **1200 iyi satırı** engeller, özeti 25 hücreye
  düşürür ve bunu **yakalanan bozulma 0** iken yapar; denetim eklemek de bozar.
- İhlal edildiğinde ne yapılacağı ayrı bir bedeldir: satır düzeyi uygulama eksik çıktı verir, yük
  düzeyi uygulama 2200 iyi satırı engelleyip hiç çıktı vermez, uyarlama sunumu tabana döndürür ama
  hattı altı aşamaya çıkarır ve tüketiciye kalıcı bir eşleme tablosu bırakır.

## Sonraki Adım

Sözleşme bozulmayı aşama 0'da yakaladı, ama yakalamak düzeltmek değildir: engellenen 200 satır bir
yerde durmalı, üretici düzeltmeli ve o dönem hatta **yeniden** verilmelidir. Bu dersin hiçbir
satırında hat iki kez koşmadı. İkinci koşum hattın en sık yapılan işidir ve kendi sayısını taşır:
aynı dönem yeniden işlendiğinde satır sayısına ne oluyor, hangi aşama fazlalığı yutuyor ve sunulan
değer bunu gösteriyor mu. Sonraki ders hattı **yinelemeye dayanıklı** olan ve olmayan iki biçimde
koşturur, çoğalan satırı sayar ve sunumdaki farkı ölçer.
