---
title: Sapma
source: 'https://academia.sh/tr/kurslar/kod-olarak-altyapi/sapma'
course: 'Kod Olarak Altyapı'
language: tr
updated: '2026-08-17T18:09:06+00:00'
license: 'CC BY-SA 4.0'
---

# Sapma

Bir sapma tespiti yazılır: kayıt okunur, gerçek durum diskten okunur, kalem kalem fark çıkarılır ve her farkın kaynağı ayrılır. Otuz günlük bir dönemde biriken sapma, tarama sıklığına göre tespit gecikmesi, kaydın kapsamı dışında kaldığı için hiç kapanmayan sapma ve geri almanın çalışan bir şeyi bozduğu durum sayılır.

Önceki dört ders aynı şeyi dört yerden söyledi. İki kurulum dokuz kalemde ayrıldı; kısmi
başarısızlıktan sonra kayıt ile ortam üç kalemde uyuşmadı; yeniden oluşturma acil düzeltmeleri
sildi; yeniden sağlamadan sonra dokuz kalem on beş dakika kaydın söylemediği değerde kaldı.
Hepsinin adı aynıdır.

**Sapma**, kaydın söylediği ile gerçeğin arasındaki farktır. Bu ders onu doğrudan ölçer: bir tespit
yazılır — kayıt okunur, gerçek durum **diskten** okunur, kalem kalem fark çıkarılır ve her farkın
kaynağı ayrılır. Ardından otuz günlük bir dönem koşturulur ve dört şey sayılır: biriken sapma,
tarama sıklığına göre **tespit gecikmesi**, kaydın kapsamı dışında kaldığı için hiç kapanmayan
sapma, ve düzeltmenin bedeli. Sonuncusu en az öteki üçü kadar önemli: bir sapmayı geri almak bazen
çalışan bir şeyi bozar.

Bir ayrım baştan konur. M22/K03'te küme mimarisi ele alınırken ölçülen uzlaşma döngüsü **sürekli**
koşuyordu ve fark doğduğu anda kapanıyordu; burada uygulama **tetiklenir** ve iki tetik arasında
sapma birikir. Bu dersin tüm sayıları o boşlukta doğuyor.

Ortam **bölgesel ölçüm ağı**nın hazırlık ortamıdır ve **kurgu**dur. Kayıt ile gerçek durum
gerçekten diske yazılır ve tespit gerçekten koşar; otuz günlük dönem `node` ile modellenir ve
üreteç kendi yazılıdır.

**AT25.** Kayıt yirmi kalem yazar. Gerçek durum bir dizin ağacıdır ve yirmi beş dosyadır; tespit onu
kayıttan değil, **diskten** okur.
**AT26.** Sağlayıcının belgelenmiş varsayılanları ayrı bir dosyadadır. Kayıtta olmayan bir kalem o
listedeyse kaynağı **sağlayıcı varsayılanı**, değilse **kayıt dışı kaynak**tır.
**AT27.** Otuz günlük dönemde olaylar üreteçle üretilir (tohum 4471903, üreteç kendi yazılıdır);
günlük olay sayısı sıfır, bir ya da ikidir.
**AT28.** Bir olayın kaynağı elle değişiklik, kayıt dışı kaynak ya da sağlayıcı varsayılanıdır.
Yalnız **elle değişiklik** kaydın kapsamındadır; ötekiler bir uygulamayla kapanmaz.
**AT29.** Uygulama tetiklenir: 1., 12. ve 25. günlerde. **Tarama uygulamadan ayrıdır** — tespit
eder, kapatmaz.
**AT30.** Elle değişikliklerin bir kısmı bir olayı kapatmak için yapılmış **canlı düzeltme**dir;
geri alındığında kapattığı sorun geri gelir.

## Kayıt ve Gerçek

```bash
#!/usr/bin/env bash
# Kayit ve gercek ortam: kayit bir dosya, gercek durum bir dizin agacidir. Ikisi de diske yazilir.
set -e
rm -rf gercek

cat > kayit.alt <<'SON'
kaynak ag "olcum-agi" { blok = "10.40.0.0/16"  alt_ag_sayisi = 3  ozel = "dogru" }
kaynak makine "toplayici" { sayi = 3  boyut = "orta"  disk_gb = 40  imaj = "taban-7" }
kaynak makine "dogrulayici" { sayi = 2  boyut = "kucuk"  disk_gb = 20  imaj = "taban-7" }
kaynak kuyruk "okuma" { bolum = 6  saklama_saat = 72  olu_mektup = "acik" }
kaynak veri_deposu "olcum" { boyut_gb = 200  yedek_gun = 14  surum = "5.2" }
kaynak nesne_deposu "arsiv" { sinif = "seyrek"  surumleme = "acik"  yasam_gun = 365 }
SON

# Saglayicinin belgelenmis varsayilanlari: kayitta yazmayan, kendiliginden olusan alanlar.
cat > varsayilan.txt <<'SON'
ag.olcum-agi.cikis_yolu
kuyruk.okuma.sifreleme
veri_deposu.olcum.bakim_penceresi
nesne_deposu.arsiv.erisim_kurali
SON

yaz() { mkdir -p "gercek/$(dirname "$1")"; printf '%s\n' "$2" > "gercek/$1"; }
# Kayitla uyusan on dort kalem
yaz ag/olcum-agi/blok 10.40.0.0/16;        yaz ag/olcum-agi/ozel dogru
yaz makine/toplayici/boyut orta;           yaz makine/toplayici/imaj taban-7
yaz makine/dogrulayici/sayi 2;             yaz makine/dogrulayici/boyut kucuk
yaz makine/dogrulayici/disk_gb 20;         yaz makine/dogrulayici/imaj taban-7
yaz kuyruk/okuma/bolum 6;                  yaz kuyruk/okuma/olu_mektup acik
yaz veri_deposu/olcum/boyut_gb 200;        yaz veri_deposu/olcum/surum 5.2
yaz nesne_deposu/arsiv/surumleme acik;     yaz nesne_deposu/arsiv/yasam_gun 365
# Elle degistirilmis bes kalem (kayittaki degerden farkli)
yaz ag/olcum-agi/alt_ag_sayisi 4;          yaz makine/toplayici/sayi 5
yaz makine/toplayici/disk_gb 80;           yaz kuyruk/okuma/saklama_saat 24
yaz veri_deposu/olcum/yedek_gun 7
# nesne_deposu/arsiv/sinif silinmis: kayitta var, gercekte yok
# Saglayici varsayilani (uc kalem) ve kayit disi kaynak (uc kalem)
yaz ag/olcum-agi/cikis_yolu acik;          yaz kuyruk/okuma/sifreleme saglayici-anahtari
yaz veri_deposu/olcum/bakim_penceresi pazar-03:00
yaz guvenlik/gecici/giris 0.0.0.0-8443;    yaz ad_kaydi/toplayici/ic toplayici.ic
yaz makine/tanilama/sayi 1
printf 'kayit %s satir   gercek %s dosya\n' "$(wc -l < kayit.alt | tr -d ' ')" \
  "$(find gercek -type f | wc -l | tr -d ' ')"
```

```
kayit 6 satir   gercek 25 dosya
```

## Kalem Kalem Fark

```js
// sapma.mjs — kaydi okur, gercek durumu diskten okur, kalem kalem fark cikarir. Hicbir sey duzeltmez.
import { readFileSync, readdirSync, statSync } from "node:fs";

const BLOK = /^kaynak\s+(\w+)\s+"([\w-]+)"\s*\{(.*)\}$/;
const kayit = new Map();
for (const s of readFileSync("kayit.alt", "utf8").split("\n")) {
  const m = BLOK.exec(s.trim());
  if (m) for (const x of m[3].matchAll(/(\w+)\s*=\s*("[^"]*"|[\w./-]+)/g))
    kayit.set(`${m[1]}.${m[2]}.${x[1]}`, x[2].replaceAll('"', ""));
}
const varsayilan = new Set(readFileSync("varsayilan.txt", "utf8").trim().split("\n"));

const gercek = new Map();                       // gercek durum diskten okunur, kayittan degil
const gez = (yol, on = []) => {
  for (const ad of readdirSync(yol).sort()) {
    const t = `${yol}/${ad}`;
    if (statSync(t).isDirectory()) gez(t, [...on, ad]);
    else gercek.set([...on, ad].join("."), readFileSync(t, "utf8").trim());
  }
};
gez("gercek");

const tum = [...new Set([...kayit.keys(), ...gercek.keys()])].sort();
const fark = tum.filter((k) => kayit.get(k) !== gercek.get(k)).map((k) => ({ k,
  kaynak: !gercek.has(k) ? "eksik kalem" : !kayit.has(k)
    ? (varsayilan.has(k) ? "saglayici varsayilani" : "kayit disi kaynak") : "elle degisiklik" }));
const say = (t) => fark.filter((f) => f.kaynak === t).length;

console.log(`kayit ${kayit.size} kalem   gercek ${gercek.size} kalem   birlesim ${tum.length}`);
console.log(`sapma ${fark.length} kalem` +
  `   elle ${say("elle degisiklik")}   eksik ${say("eksik kalem")}` +
  `   kayit disi ${say("kayit disi kaynak")}   varsayilan ${say("saglayici varsayilani")}`);
for (const f of fark)
  console.log(`  ${f.kaynak.padEnd(22)} ${f.k.padEnd(34)} kayit "${kayit.get(f.k) ?? "-"}"` +
    `  gercek "${gercek.get(f.k) ?? "-"}"`);
const gorunen = fark.filter((f) => kayit.has(f.k)).length;
console.log(`kaydin kapsaminda olan, yani bir uygulamanin kapatabilecegi sapma ${gorunen}` +
  `   kapsam disi ${fark.length - gorunen}`);
```

```
kayit 20 kalem   gercek 25 kalem   birlesim 26
sapma 12 kalem   elle 5   eksik 1   kayit disi 3   varsayilan 3
  kayit disi kaynak      ad_kaydi.toplayici.ic              kayit "-"  gercek "toplayici.ic"
  elle degisiklik        ag.olcum-agi.alt_ag_sayisi         kayit "3"  gercek "4"
  saglayici varsayilani  ag.olcum-agi.cikis_yolu            kayit "-"  gercek "acik"
  kayit disi kaynak      guvenlik.gecici.giris              kayit "-"  gercek "0.0.0.0-8443"
  elle degisiklik        kuyruk.okuma.saklama_saat          kayit "72"  gercek "24"
  saglayici varsayilani  kuyruk.okuma.sifreleme             kayit "-"  gercek "saglayici-anahtari"
  kayit disi kaynak      makine.tanilama.sayi               kayit "-"  gercek "1"
  elle degisiklik        makine.toplayici.disk_gb           kayit "40"  gercek "80"
  elle degisiklik        makine.toplayici.sayi              kayit "3"  gercek "5"
  eksik kalem            nesne_deposu.arsiv.sinif           kayit "seyrek"  gercek "-"
  saglayici varsayilani  veri_deposu.olcum.bakim_penceresi  kayit "-"  gercek "pazar-03:00"
  elle degisiklik        veri_deposu.olcum.yedek_gun        kayit "14"  gercek "7"
kaydin kapsaminda olan, yani bir uygulamanin kapatabilecegi sapma 6   kapsam disi 6
```

On iki kalem sapmış ve son satır ölçünün asıl yerini gösteriyor: on ikinin **altısı** kaydın
kapsamında. Kalan altı kalem için bir uygulama koşturmak hiçbir şey değiştirmez, çünkü kayıt o
kalemler hakkında bir şey söylemiyor — üçü sağlayıcının kendiliğinden açtığı alan, üçü kayıt
yazılmadan yaratılmış kaynak. Bunları görebilmenin tek nedeni tespitin **iki yönlü** olmasıdır:
yalnız kayıttaki kalemler taranmıyor, gerçek durumun tamamı dolaşılıyor ve kayıtta karşılığı
olmayanlar da yazılıyor.

Kaynak ayrımı bir etiketleme işi değil, bir **eylem ayrımı**dır. Elle değişiklik bir uygulamayla
kapanır. Eksik kalem bir uygulamayla geri gelir. Kayıt dışı kaynak ancak kayda alınarak ya da
silinerek kapanır; sağlayıcı varsayılanı ise ne kapanır ne kapanmalıdır — yalnız kaydın onun
hakkında sessiz olduğu bilinmelidir. Dört ayrı fark türü, dört ayrı karar.

## Bir Dönem Boyunca

```js
// donem.mjs — otuz gunluk sapma birikimi, tespit gecikmesi ve duzeltmenin bedeli. Model.
const TOHUM = 4471903, GUN = 30, UYGULAMA = [1, 12, 25];   // uygulama tetiklenir, surekli kosmaz
const uretec = (t) => () => (t = (t * 1103515245 + 12345) % 2147483648) / 2147483648;
const r = uretec(TOHUM);

const olay = [];
for (let g = 1; g <= GUN; g++)
  for (let n = (r() < 0.55) + (r() < 0.18); n > 0; n--) {
    const p = r();
    const kaynak = p < 0.45 ? "elle" : p < 0.72 ? "kayit disi" : "varsayilan";
    olay.push({ g, kaynak, kapsamda: kaynak === "elle", canli: kaynak === "elle" && r() < 0.35 });
  }
const say = (t) => olay.filter((o) => o.kaynak === t).length;
const kapsamli = olay.filter((o) => o.kapsamda);
console.log(`tohum ${TOHUM}   gun ${GUN}   olay ${olay.length}   uygulama gunleri` +
  ` ${UYGULAMA.join(", ")}`);
console.log(`sapmanin kaynagi   elle ${say("elle")}   kayit disi ${say("kayit disi")}` +
  `   saglayici varsayilani ${say("varsayilan")}   kapsamda ${kapsamli.length}`);

// Iki rejim: uygulama tetiklenir (uc gun) ve surekli uzlasma (her gun). Ikisi de yalniz kapsamdakini kapatir.
const rejim = (gunler) => {
  const toplam = [], kapsam = [];
  let kapatilan = 0;
  for (let g = 1; g <= GUN; g++) {
    if (gunler.includes(g)) kapatilan = kapsamli.filter((o) => o.g <= g).length;
    kapsam.push(kapsamli.filter((o) => o.g <= g).length - kapatilan);
    toplam.push(olay.filter((o) => o.g <= g).length - kapatilan);
  }
  const alan = (x) => x.reduce((a, b) => a + b, 0);
  return { toplam, kapsam, alanT: alan(toplam), alanK: alan(kapsam) };
};
const A = rejim(UYGULAMA), B = rejim([...Array(GUN)].map((_, i) => i + 1));
console.log(`\nacik sapma (gun sonu, ${GUN} gun)`);
console.log(`  tetiklenen uygulama  toplam  ${A.toplam.join(" ")}`);
console.log(`  tetiklenen uygulama  kapsam  ${A.kapsam.join(" ")}`);
console.log(`  surekli uzlasma      toplam  ${B.toplam.join(" ")}`);
console.log(`  gun-kalem alani   kapsamdaki sapma: tetiklenen ${A.alanK}   surekli ${B.alanK}`);
console.log(`  gun-kalem alani   tum sapma:        tetiklenen ${A.alanT}   surekli ${B.alanT}` +
  `   fark ${A.alanT - B.alanT}`);

console.log(`\ntespit gecikmesi (yalniz kapsamdaki ${kapsamli.length} sapma; tarama tespit eder, kapatmaz)`);
for (const n of [1, 3, 7, 30]) {
  const gecikme = kapsamli
    .map((o) => { for (let g = o.g; g <= GUN; g++) if (g % n === 0) return g - o.g; return null; })
    .filter((x) => x !== null);
  console.log(`  tarama ${String(n).padStart(2)} gunde bir   ortalama` +
    ` ${(gecikme.reduce((a, b) => a + b, 0) / gecikme.length).toFixed(1)} gun` +
    `   en kotu ${Math.max(...gecikme)} gun   tespit edilen ${gecikme.length}/${kapsamli.length}`);
}

const geriAlinan = kapsamli.filter((o) => o.g <= UYGULAMA[UYGULAMA.length - 1]);
const bozulan = geriAlinan.filter((o) => o.canli);
console.log(`\nduzeltmenin bedeli`);
console.log(`  geri alinan sapma ${geriAlinan.length}   bunun canli duzeltme olani` +
  ` ${bozulan.length}   geri alinca calisan bir sey bozulur`);
console.log(`  kalici olarak kapanan ${geriAlinan.length - bozulan.length}` +
  `   geri gelen ${bozulan.length} (%${(100 * bozulan.length / geriAlinan.length).toFixed(0)})`);
console.log(`  kapsam disi ${olay.length - kapsamli.length} sapma hicbir uygulamayla kapanmadi;` +
  ` donem sonunda hepsi duruyor`);
```

```
tohum 4471903   gun 30   olay 21   uygulama gunleri 1, 12, 25
sapmanin kaynagi   elle 9   kayit disi 6   saglayici varsayilani 6   kapsamda 9

acik sapma (gun sonu, 30 gun)
  tetiklenen uygulama  toplam  1 1 2 2 2 3 3 3 4 5 6 3 5 6 7 8 8 8 9 9 10 11 12 13 9 10 10 11 11 13
  tetiklenen uygulama  kapsam  0 0 1 1 1 1 1 1 2 3 3 0 1 2 2 2 2 2 2 2 2 2 3 4 0 1 1 1 1 1
  surekli uzlasma      toplam  1 1 1 1 1 2 2 2 2 2 3 3 4 4 5 6 6 6 7 7 8 9 9 9 9 9 9 10 10 12
  gun-kalem alani   kapsamdaki sapma: tetiklenen 45   surekli 0
  gun-kalem alani   tum sapma:        tetiklenen 205   surekli 160   fark 45

tespit gecikmesi (yalniz kapsamdaki 9 sapma; tarama tespit eder, kapatmaz)
  tarama  1 gunde bir   ortalama 0.0 gun   en kotu 0 gun   tespit edilen 9/9
  tarama  3 gunde bir   ortalama 1.0 gun   en kotu 2 gun   tespit edilen 9/9
  tarama  7 gunde bir   ortalama 3.1 gun   en kotu 5 gun   tespit edilen 9/9
  tarama 30 gunde bir   ortalama 13.7 gun   en kotu 27 gun   tespit edilen 9/9

duzeltmenin bedeli
  geri alinan sapma 8   bunun canli duzeltme olani 2   geri alinca calisan bir sey bozulur
  kalici olarak kapanan 6   geri gelen 2 (%25)
  kapsam disi 12 sapma hicbir uygulamayla kapanmadi; donem sonunda hepsi duruyor
```

Otuz günde yirmi bir sapma doğdu ve dokuzu kaydın kapsamındaydı. İki dizi arasındaki fark
tetiklenen uygulamanın ne demek olduğunu tek satıra indiriyor: kapsamdaki sapma tetiklenen rejimde
kırk beş gün-kalem açık kaldı, sürekli uzlaşmada sıfır. Üç tetik günü dizide açıkça görünüyor —
1., 12. ve 25. günlerde kapsam satırı sıfıra iniyor, sonra yeniden tırmanıyor. Sapma yok olmuyor,
her tetik arasında yeniden doğuyor; biriken şey sapmanın kendisi değil, **kapanmamış** sapmadır.

Toplam satırı ise iki rejimde de tırmanmaya devam ediyor ve otuzuncu günde on üç ile on ikide
duruyor. Aradaki fark yalnız kırk beş gün-kalemdir ve o da kapsamdaki dokuz kalemden geliyor. Kalan
on iki sapma hiçbir rejimde kapanmadı: uygulamanın sürekli koşması onları görünür kılmıyor, çünkü
görünmemelerinin nedeni sıklık değil, **kapsam**. Bu, konunun ilk dersinde beş kalem olarak
görülen şeyin bir dönem boyunca ne kadar büyüdüğünü gösteriyor.

## Tespit Gecikmesi ve Düzeltmenin Bedeli

Tarama tablosu ayrı bir kararı ölçüyor. Tarama uygulamadan bağımsızdır: bir sapmayı **kapatmadan**
görünür kılar. Günlük tarama gecikmeyi sıfırlıyor, üç günde bir tarama ortalama bir güne, haftalık
tarama üç virgül bir güne, aylık tarama on üç virgül yedi güne çıkarıyor — ve aylık taramada en kötü
gecikme yirmi yedi gün. Yirmi yedi gün, bir kalemin kaydın söylemediği değerde koştuğu ve kimsenin
bilmediği süredir. Tarama sıklığını seçmek, bu sayıyı seçmektir.

Son tablo bu dersin en ters sayısını taşıyor. Yirmi beşinci güne kadar sekiz sapma geri alındı ve
ikisi **canlı düzeltme**ydi: bir olayı kapatmak için elle yapılmış, sorunu gerçekten gideren
değişiklikler. Geri alındıklarında kapattıkları sorun geri geldi ve ikisi de sonraki günlerde
yeniden yapıldı. Geri almanın kalıcı olarak kapattığı sapma altı, geri geleni iki — yüzde yirmi
beş.

Bu iki kalem sapmanın tek yönlü okunamayacağını gösteriyor. Bir sapma "kayıt haklı, gerçek yanlış"
demek değildir; yalnız ikisinin **ayrıldığı** demektir. Ayrılmanın iki yorumu vardır ve hangisinin
doğru olduğu farkın kendisinden okunamaz: ya kayıt güncellenmeli ve düzeltme kayda işlenmeli, ya
gerçek geri alınmalı. Otomatik uygulama her zaman ikinciyi seçer, çünkü başka bir seçeneği yoktur.
Kaydın bir kalem hakkında sessiz kalmasının bedeli görünmezlikti; kaydın bir kalem hakkında **eski**
kalmasının bedeli, çalışan bir şeyin bozulmasıdır.

## Özet

- Tespit 26 kalemi karşılaştırdı ve 12 sapma buldu: 5 elle değişiklik, 1 eksik kalem, 3 kayıt dışı
  kaynak, 3 sağlayıcı varsayılanı; bunların yalnız 6'sı bir uygulamayla kapanabilir.
- Otuz günde 21 sapma doğdu; 9'u kaydın kapsamındaydı, 12'si dönem sonunda hâlâ açıktı ve hiçbir
  rejimde kapanmadı.
- Tetiklenen uygulama kapsamdaki sapmayı 45 gün-kalem açık bıraktı, sürekli uzlaşma 0; fark
  sıklıktan, kapanmayan 12 kalem ise kapsamdan geliyor.
- Tarama sıklığı gecikmeyi doğrudan belirliyor: günlük 0,0 gün, haftalık 3,1 gün, aylık 13,7 gün
  ortalama ve 27 gün en kötü.
- Geri alınan 8 sapmanın 2'si canlı düzeltmeydi ve geri alınca çalışan bir şeyi bozdu; geri almanın
  kalıcı kapattığı 6, geri gelen 2 kalemdir.

## Sonraki Adım

Sapma bu noktada sayılabilir bir şey. Kaydın kapsamı biliniyor, kapsam dışındaki kalem adıyla
yazılabiliyor, farkın kaynağı dörde ayrılabiliyor, tespit gecikmesi tarama sıklığına bağlanabiliyor
ve düzeltmenin bir bedeli olduğu ölçülmüş durumda. Ölçünün tamamı tek bir varsayıma yaslanıyor:
ortada okunabilir bir kayıt var.

O kaydın kendisi ise hiç ele alınmadı. Beş derste kayıt hep hazır bulundu — altı satırlık bir
dosya, kalemlerini değerleriyle sayan bir liste. Nasıl yazıldığı, hangi yapılarla kurulduğu, bir
kaynağın ötekine nasıl bağlandığı, aynı tanımın üç ortam için nasıl tekrar edilmeden yazılacağı,
bir değerin nereden geleceği ve bir değişiklik uygulanmadan önce ne göstereceği — bunların hiçbiri
sorulmadı. Sonraki konu kaydın kendisini yazmakla başlıyor.
