---
title: 'DevOps Kültürü ve Temelleri'
source: 'https://academia.sh/tr/kurslar/devops-temelleri'
language: tr
updated: '2026-08-17T04:40:35+00:00'
license: 'CC BY-SA 4.0'
lessons: 12
outcomes:
    - 'Teslimat ölçütlerini birbirine bağlı bir küme olarak okur'
    - 'Ortamlar arası farkın nerede saklandığını sayar'
    - 'Yapı çıktısının değişmezliğini bir denetime bağlar'
---

# DevOps Kültürü ve Temelleri

Fikirden üretime giden yolda farkın nerede saklandığı: sorumluluk paylaşımının teknik karşılığı, ayrık ekiplerin ürettiği gecikme ve risk, değer akışının haritalanması, dağıtım sıklığı, öncü süre, geri dönüş ve kurtarma süresinin birbirini oynatması, geri bildirim döngülerinin kurulması, ortam ayrımı, bir kez üret her yere dağıt ilkesi, yapı çıktısı depoları, yapılandırma ile sırrın ayrılması, taşınabilir uygulama ilkeleri ve altyapı sağlama modelleri.

## Kültür ve Akış

Fikirden üretime giden yolun ölçülmesi: sorumluluk paylaşımının teknik karşılığı ve kimin hangi sinyali gördüğü, ayrık ekiplerin ürettiği gecikme ve risk, değer akışının adım adım haritalanması, dağıtım sıklığı, öncü süre, geri dönüş oranı ve kurtarma süresinin birbirini oynatması, işletim yaklaşımlarının örtüşen alanı ve geri bildirim döngüsünün uzunluğu.

### DevOps Nedir

Source: https://academia.sh/tr/kurslar/devops-temelleri/devops-nedir

Sorumluluk paylaşımının teknik ve örgütsel yanı: aynı 22 olgunun ayrık gözlem alanlarında 9'unun yalnız işletenin, 1'inin yalnız yazanın alanında ve 1'inin hiçbir alanda görünmesi, 4 olgunun sahibine hiç ulaşmaması ve sahibe ulaşmanın ortalama 7,0 adım sürmesi, üç yüzeyin paylaşılmasıyla ulaşmayanın 1'e ve ulaşmanın 5,0 adıma inmesi, alanların tümüyle birleştirilmesiyle ulaşmanın 1,6 adıma inerken yazan ekibin yükünün 95'ten 107 adıma, öncü sürenin 25,8'den 34,8 adıma çıkması ve dağıtım sıklığının 5'ten 4 yayına düşmesi.

Önceki ders devri bir **sözleşme** olarak ölçtü: yirmi sekiz sorumluluk kaleminin yirmisi
devredildi, sekizi bilgi, araç ya da yordam yokluğunda geliştirmede kaldı. Sözleşme kimin neyi
yapacağını yazıyordu. Yazmadığı şey, kimin neyi **göreceği**ydi. İki taraf aynı servisten sorumlu
olabilir ve yine de aynı olguyu farklı adımda, farklı yüzeyde, kimi zaman hiç görmez.

**Sorumluluk paylaşımı**, yazan ve işleten rollerin bir servisin sonucundan birlikte sorumlu
tutulmasıdır. Devir sözleşmesi *kalemleri* böler, sorumluluk paylaşımı *sonucu* böler; ikincisinin
ön koşulu, iki tarafın aynı olguyu görebilmesidir. Bu ders o ön koşulu ölçer: aynı olgu kümesi iki
rolün gözlem alanına düşürülür, kaç olgunun yalnız bir tarafta kaldığı sayılır ve alanları
birleştirmenin faturası çıkarılır.

#### Gözlem Alanı Bir Veri Yapısıdır

Örnek, bu müfredatın kurgu **bölgesel ölçüm ağı**dır: bir belediyenin su sayaçlarından okuma
toplayan, okumaları doğrulayan, faturaya çeviren ve saha ekiplerine iş emri açan bir yazılım. Ağ
da ekipler de kurgudur. **KA1:** üç ortam (geliştirme, sınama, üretim), iki ekip (yazan ve
işleten) ve bir gecelik toplu iş vardır. **KA2:** sekiz gözlem yüzeyi vardır; üçü yazan ekibin,
dördü işleten ekibin alanındadır, `fatura-dokumu` hiç kimsenin alanında değildir. **KA3:** bir
pencerede yirmi iki olgu doğar; her olgunun bir sınıfı (hata, gecikme, sapma), bir doğuş adımı ve
göründüğü yüzeylerle o yüzeydeki gecikmesi vardır. **KA4:** her olgunun onu kapatabilen bir sahibi
vardır — yazan, işleten ya da ortak; ortak olgu iki alanda da görünmedikçe kapatılamaz, kapatma
sırasıyla 4, 2 ve 5 adım tutar. **KA5:** alanında görünen olgu role 2 adım inceleme yazar; sahibine
30 adımda ulaşmamış olgu üstten duyulur ve bağlam ikinci elden kurulduğu için 2 adım fazladan
tutar. **KA6:** yazan ekip boş adımlarında yayına çalışır, bir yayın 8 adım iş ister; her olgu
kendinden önceki son yayına bağlanır ve bağlı olgusu sahibine hiç ulaşmayan yayın başarısız
sayılır. Pencere 140 adımdır.

Olgular, yüzeyler ve iki rolün nöbeti süreç içi bir **modeldir**; gerçek bir uyarı akışı ya da olay
kaydı yoktur.

```js
// gozlem/alan.mjs — kurgu bolgesel olcum aginin olgu ve gozlem alani modeli (model): gercek bir
// uyari akisi ya da olay kaydi yok, adimlar veri yapisidir. Rastgelelik yok.

export const PENCERE = 140;                 // olculen adim penceresi
export const INCELEME = 2;                  // bir olgunun bir role inceleme maliyeti (adim)
export const YAYIN_ISI = 8;                 // bir yayin icin gereken calisma adimi
export const KAPATMA = { yazan: 4, isleten: 2, ortak: 5 };
export const TAVAN = 30;                    // sahibine ulasmayan olgu bu gecikmeyle ustten duyulur
export const IKINCI_EL = 2;                 // ustten duyulan olgunun ek baglam maliyeti

export const YUZEY = {                      // yuzey -> ayrik duzende kimin alaninda
  "uygulama-kaydi": "yazan", "hata-izleme": "yazan", "surum-gunlugu": "yazan",
  "is-cizelgesi": "isleten", "makine-olcumu": "isleten", "uyari-akisi": "isleten",
  "destek-kaydi": "isleten", "fatura-dokumu": "-",
};
export const ROL = ["yazan", "isleten"];

const cizelge = (s, f) => s.trim().split("\n").map((r) => f(r.trim().split(/\s+/)));

// olgu: dogus adimi, sinif, kapatabilen rol, ad, gorundugu yuzeyler (yuzey:gecikme)
export const OLGU = cizelge(`
    2  hata     yazan    okuma-ayristirici       uygulama-kaydi:0 destek-kaydi:12
    6  gecikme  isleten  toplu-is-tasmasi        is-cizelgesi:1 makine-olcumu:2
   11  sapma    yazan    sinamada-olmayan-ayar   surum-gunlugu:0 uyari-akisi:9
   17  hata     isleten  kuyruk-tikanmasi        makine-olcumu:0 uyari-akisi:1
   21  gecikme  yazan    sorgu-yavaslamasi       uygulama-kaydi:3 makine-olcumu:1
   26  hata     yazan    yinelenen-fatura        destek-kaydi:16
   31  sapma    isleten  disk-doluluk            makine-olcumu:0
   36  hata     yazan    bos-adresli-is-emri     hata-izleme:2 destek-kaydi:9
   42  gecikme  isleten  ag-gecikmesi            makine-olcumu:1 uyari-akisi:2
   46  sapma    yazan    kutuphane-sapmasi       surum-gunlugu:1
   51  hata     ortak    gecelik-is-yarim        is-cizelgesi:1 uygulama-kaydi:4
   57  hata     yazan    negatif-tuketim         fatura-dokumu:0 destek-kaydi:14
   61  gecikme  isleten  yedekleme-cakismasi     is-cizelgesi:2 makine-olcumu:3
   66  sapma    ortak    zaman-dilimi-farki      uygulama-kaydi:6 is-cizelgesi:3
   71  hata     yazan    yuvarlama-farki         fatura-dokumu:0
   77  gecikme  yazan    onbellek-isinmasi       hata-izleme:2 makine-olcumu:1
   81  hata     isleten  baglanti-havuzu         uyari-akisi:1 uygulama-kaydi:0
   86  sapma    yazan    eksik-ortam-degiskeni   uygulama-kaydi:0 uyari-akisi:5
   91  hata     yazan    sayac-kimligi-catismasi hata-izleme:2 destek-kaydi:10
   96  gecikme  isleten  is-yeniden-kosumu       is-cizelgesi:1
  102  sapma    yazan    bicim-kirilmasi         fatura-dokumu:0 destek-kaydi:15
  107  hata     ortak    yinelenen-is-emri       uygulama-kaydi:3 destek-kaydi:8`,
([dogus, sinif, sahip, ad, ...y]) => ({ dogus: +dogus, sinif, sahip, ad,
  yuzey: y.map((p) => ({ ad: p.split(":")[0], gec: +p.split(":")[1] })) }));

// Duzen: ayrik duzenin uzerine hangi rol hangi yuzeyi ek olarak goruyor (karsit kosum).
export const DUZEN = {
  ayrik: { yazan: [], isleten: [] },
  secili: { yazan: ["destek-kaydi"], isleten: ["surum-gunlugu", "fatura-dokumu"] },
  birlesik: { yazan: Object.keys(YUZEY), isleten: Object.keys(YUZEY) },
};

export const alan = (d) => Object.fromEntries(ROL.map((r) =>
  [r, new Set([...Object.keys(YUZEY).filter((y) => YUZEY[y] === r), ...DUZEN[d][r]])]));

export function kos(d) {
  const A = alan(d);
  const G = OLGU.map((o) => {                 // her olgu her rolde kacinci adimda goruluyor
    const g = Object.fromEntries(ROL.map((r) => {
      const v = o.yuzey.filter((y) => A[r].has(y.ad)).map((y) => y.gec);
      return [r, v.length ? Math.min(...v) : null];
    }));
    const kapi = o.sahip === "ortak"          // ortak olgu iki alanda da gorunmus olmali
      ? (g.yazan === null || g.isleten === null ? null : Math.max(g.yazan, g.isleten))
      : g[o.sahip];
    return { o, g, kapi, sahipRol: o.sahip === "ortak" ? "yazan" : o.sahip };
  });

  const kuyruk = Object.fromEntries(ROL.map((r) => [r, []]));
  const kalan = Object.fromEntries(ROL.map((r) => [r, 0]));
  const yuk = Object.fromEntries(ROL.map((r) => [r, 0]));
  const kapanis = new Map(), yayin = [];
  let birikim = 0, basla = 0;

  for (let t = 0; t <= PENCERE; t++) {
    for (const x of G) {
      for (const r of ROL)                    // alaninda gorunen olgu inceleme isi acar
        if (x.g[r] !== null && t === x.o.dogus + x.g[r]) kuyruk[r].push([INCELEME, null]);
      if (x.kapi !== null && t === x.o.dogus + x.kapi)
        kuyruk[x.sahipRol].push([KAPATMA[x.o.sahip], x]);
      else if (x.kapi === null && t === x.o.dogus + TAVAN)      // ustten duyulma
        kuyruk[x.sahipRol].push([KAPATMA[x.o.sahip] + IKINCI_EL, x]);
    }
    for (const r of ROL) {
      if (kalan[r] === 0 && kuyruk[r].length) [kalan[r]] = kuyruk[r][0];
      if (kalan[r] > 0) {                     // rol bu adimda olguyla ugrasiyor
        kalan[r]--; yuk[r]++;
        if (kalan[r] === 0) { const [, x] = kuyruk[r].shift(); if (x) kapanis.set(x.o.ad, t + 1); }
        continue;
      }
      if (r !== "yazan") continue;            // bos adim: yazan ekip yayina calisir
      if (birikim === 0) basla = t;
      if (++birikim === YAYIN_ISI) { yayin.push({ t: t + 1, basla, olgu: [] }); birikim = 0; }
    }
  }
  for (const x of G) {                        // olgu kendinden onceki son yayina baglanir
    const y = [...yayin].reverse().find((v) => v.t <= x.o.dogus);
    if (y) y.olgu.push(x);
  }
  return { G, yuk, kapanis, yayin };
}

export const ort = (a) => (a.length ? (a.reduce((s, v) => s + v, 0) / a.length).toFixed(1) : "-");

export function olc(d) {
  const R = kos(d), say = (f) => R.G.filter(f).length;
  const ulasma = R.G.map((x) => (x.kapi === null ? TAVAN : x.kapi));   // ulasmayana tavan yazilir
  const sure = R.G.map((x) => (R.kapanis.get(x.o.ad) ?? PENCERE) - x.o.dogus);
  const bozuk = R.yayin.filter((y) => y.olgu.some((x) => x.kapi === null)).length;
  return { R,
    yalnizYazan: say((x) => x.g.yazan !== null && x.g.isleten === null),
    yalnizIsleten: say((x) => x.g.isleten !== null && x.g.yazan === null),
    ikisi: say((x) => x.g.yazan !== null && x.g.isleten !== null),
    hicbiri: say((x) => x.g.yazan === null && x.g.isleten === null),
    ulasmayan: say((x) => x.kapi === null), ulasmaAdimi: ort(ulasma),
    gurultuYazan: say((x) => x.g.yazan !== null && x.o.sahip === "isleten"),
    gurultuIsleten: say((x) => x.g.isleten !== null && x.o.sahip === "yazan"),
    yukYazan: R.yuk.yazan, yukIsleten: R.yuk.isleten, kurtarma: ort(sure),
    yayinSayisi: R.yayin.length, onculSure: ort(R.yayin.map((y) => y.t - y.basla)),
    geriDonus: R.yayin.length ? (100 * bozuk / R.yayin.length).toFixed(0) + "%" : "-" };
}
```

Dört teslimat ölçütü aynı koşumdan okunur: **dağıtım sıklığı** penceredeki yayın sayısı, **öncü
süre** bir yayının işine başlanmasından yayına girmesine kadar geçen adım, **geri dönüş oranı**
başarısız yayınların payı, **kurtarma süresi** olgunun doğuşundan kapanışına kadar geçen adımdır.

```js
// gozlem/olc.mjs — olgu iki rolun gozlem alanina nasil dusuyor, birlestirmenin bedeli ne.
import { OLGU, YUZEY, ROL, olc, alan, TAVAN } from "./alan.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const D = ["ayrik", "secili", "birlesik"];
const R = Object.fromEntries(D.map((d) => [d, olc(d)]));

console.log(`${OLGU.length} olgu, ${Object.keys(YUZEY).length} gozlem yuzeyi; ` +
  ["hata", "gecikme", "sapma"].map((s) =>
    `${s} ${OLGU.filter((o) => o.sinif === s).length}`).join(", "));
for (const r of ROL) console.log(`  ${r}: ${[...alan("ayrik")[r]].join(", ")}`);
console.log(`  kimsenin alaninda degil: ` +
  Object.keys(YUZEY).filter((y) => YUZEY[y] === "-").join(", "));

const A = [-27, 9, 9, 11];
console.log("\n1. ayni 22 olgu, uc gozlem duzeni");
yaz(A, "olcu", "ayrik", "secili", "birlesik");
for (const [ad, k] of [["yalniz yazanin alaninda", "yalnizYazan"],
  ["yalniz isletenin alaninda", "yalnizIsleten"], ["iki alanda birden", "ikisi"],
  ["hicbir alanda", "hicbiri"], ["sahibine hic ulasmayan", "ulasmayan"],
  [`sahibe ulasma (ort. adim)`, "ulasmaAdimi"], ["yazana gurultu (olgu)", "gurultuYazan"],
  ["isletene gurultu (olgu)", "gurultuIsleten"], ["yazanin yuku (adim)", "yukYazan"],
  ["isletenin yuku (adim)", "yukIsleten"]]) yaz(A, ad, ...D.map((d) => R[d][k]));

console.log("\n2. dort teslimat olcutu, ayni pencerede");
yaz(A, "olcut", "ayrik", "secili", "birlesik");
for (const [ad, k] of [["dagitim sikligi (yayin)", "yayinSayisi"],
  ["oncu sure (ort. adim)", "onculSure"], ["geri donus orani", "geriDonus"],
  ["kurtarma suresi (ort. adim)", "kurtarma"]]) yaz(A, ad, ...D.map((d) => R[d][k]));

const B = [-9, 7, 16, 18, 18];
console.log("\n3. ayrik duzende olgu sinifi kimin alanina dusuyor");
yaz(B, "sinif", "olgu", "yalniz yazanda", "yalniz isletende", "sahibe ulasmayan");
for (const s of ["hata", "gecikme", "sapma"]) {
  const g = R.ayrik.R.G.filter((x) => x.o.sinif === s);
  yaz(B, s, g.length, g.filter((x) => x.g.yazan !== null && x.g.isleten === null).length,
    g.filter((x) => x.g.isleten !== null && x.g.yazan === null).length,
    g.filter((x) => x.kapi === null).length);
}

console.log("\n4. ayrik duzende sahibine ulasmayan olgular (tavan " + TAVAN + " adim)");
const C = [-24, -9, 10, 16];
yaz(C, "olgu", "sahip", "kapanis", "gorundugu alan");
for (const x of R.ayrik.R.G.filter((x) => x.kapi === null))
  yaz(C, x.o.ad, x.o.sahip, R.ayrik.R.kapanis.get(x.o.ad) - x.o.dogus,
    ROL.filter((r) => x.g[r] !== null).join("+") || "hicbiri");
```

```
22 olgu, 8 gozlem yuzeyi; hata 10, gecikme 6, sapma 6
  yazan: uygulama-kaydi, hata-izleme, surum-gunlugu
  isleten: is-cizelgesi, makine-olcumu, uyari-akisi, destek-kaydi
  kimsenin alaninda degil: fatura-dokumu

1. ayni 22 olgu, uc gozlem duzeni
olcu                           ayrik   secili   birlesik
yalniz yazanin alaninda            1        0          0
yalniz isletenin alaninda          9        7          0
iki alanda birden                 11       15         22
hicbir alanda                      1        0          0
sahibine hic ulasmayan             4        1          0
sahibe ulasma (ort. adim)        7.0      5.0        1.6
yazana gurultu (olgu)              1        1          7
isletene gurultu (olgu)           10       12         12
yazanin yuku (adim)               95       95        107
isletenin yuku (adim)             54       58         58

2. dort teslimat olcutu, ayni pencerede
olcut                          ayrik   secili   birlesik
dagitim sikligi (yayin)            5        5          4
oncu sure (ort. adim)           25.8     27.0       34.8
geri donus orani                 40%      20%         0%
kurtarma suresi (ort. adim)     13.5     11.9       10.2

3. ayrik duzende olgu sinifi kimin alanina dusuyor
sinif       olgu  yalniz yazanda  yalniz isletende  sahibe ulasmayan
hata          10               0                 3                 3
gecikme        6               0                 4                 0
sapma          6               1                 2                 1

4. ayrik duzende sahibine ulasmayan olgular (tavan 30 adim)
olgu                    sahip       kapanis  gorundugu alan
yinelenen-fatura        yazan            42         isleten
negatif-tuketim         yazan            42         isleten
yuvarlama-farki         yazan            40         hicbiri
bicim-kirilmasi         yazan            36         isleten
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır.

#### Aynı Olgu, İki Ayrı Alan

Birinci tablonun `ayrik` sütunu bugünkü bölüşmedir. Yirmi iki olgunun on biri iki alanda birden
görünür, dokuzu yalnız işletenin, biri yalnız yazanın alanındadır, biri de **hiçbir alanda**
görünmez — `fatura-dokumu` yüzeyine düşen `yuvarlama-farki` kimsenin nöbet listesinde yoktur.
Üçüncü tablo bunu sınıfa göre böler: altı gecikmenin dördü yalnız işletenin alanındadır, çünkü
gecikme makine ölçümüne ve iş çizelgesine düşer; altı sapmanın biri yalnız yazanın alanındadır,
çünkü sürüm günlüğünü yalnız yazan ekip okur.

Asıl sayı alt satırdadır: **dört olgu sahibine hiç ulaşmaz.** Dördüncü tablo bunları adıyla verir
ve dördünün de sahibi yazan ekiptir. Üçü işletenin alanında görünür — destek kaydına düşerler,
işleten ekip onları görür ama kapatamaz; biri hiçbir yerde görünmez. Üstten duyulmaları 30 adım
sürer, kapanışları 36 ile 42 adım arasındadır. Aynı pencerede sahibine ulaşan olguların ortalama
ulaşma adımı ile birlikte hesaplandığında **sinyalin sahibine ortalama ulaşma süresi 7,0 adımdır.**

İşletenin alanındaki on olgu, işletenin kapatamayacağı olgudur; yani ayrık düzende işleten ekip
zaten kapatamadığı bir olgu yığınına bakmaktadır. **Bölünmüş gözlem alanı sinyali yok etmez, yanlış
tarafa koyar.**

#### Alanı Birleştirmenin Faturası

`birlesik` sütunu iki role sekiz yüzeyin tamamını verir. Görünürlük tamamlanır: yirmi iki olgunun
yirmi ikisi iki alanda birden, sahibine ulaşmayan sıfır, ortalama ulaşma 7,0 adımdan **1,6 adıma**
iner. Bedel de aynı sütundadır: yazan ekibe düşen gürültü — kapatamayacağı olgu — 1'den 7'ye,
inceleme yükü 95 adımdan 107 adıma çıkar.

Bu on iki adım ikinci tabloda teslimat ölçütü olarak görünür. Dağıtım sıklığı 5 yayından 4'e iner,
öncü süre 25,8 adımdan 34,8 adıma çıkar. Karşılığında geri dönüş oranı %40'tan %0'a, kurtarma
süresi 13,5 adımdan 10,2 adıma iner. **Dört ölçütün ikisi iyileşir, ikisi bozulur;** bir tek ölçüte
bakan cümle bu kararı taşıyamaz.

`secili` sütunu üçüncü seçenektir: sekiz yüzeyden yalnız üçü paylaşılır — yazan ekip destek
kaydını, işleten ekip sürüm günlüğü ile fatura dökümünü görür. Sahibine ulaşmayan olgu 4'ten 1'e,
ortalama ulaşma 7,0'dan 5,0 adıma, geri dönüş oranı %40'tan %20'ye, kurtarma süresi 13,5'ten 11,9
adıma iner. Dağıtım sıklığı 5 yayında kalır ve öncü süre yalnız 1,2 adım artar. Yazan ekibin yükü
hiç değişmez: **95 adımdan 95 adıma.** Üç yüzeyin getirdiği inceleme işi, artık üstten duyulmayan
üç olgunun ikinci elden bağlam kurma maliyetini tam olarak karşılar.

#### Farkın Saklandığı Yer

Bu derste fark **gözlem alanının bölünmesinde** saklıdır ve sayısı şudur: sekiz yüzeyin yedisi tek
bir rolde, biri hiçbir roldedir; yirmi iki olgunun onu tek alanda, biri hiçbir alanda görünür.
Farkın bildirilmiş kısmı yüzey bölüşmesidir — hangi ekibin neye baktığı bellidir. Bildirilmemiş
kısmı, o bölüşmenin hangi olguyu hangi tarafta bıraktığıdır; bu ancak koşumda görünür.

Sinyalin kime kaç adımda ulaştığı da buradan okunur: ayrık düzende sahibine ortalama 7,0 adımda,
üç yüzey paylaşıldığında 5,0 adımda, alanlar birleştirildiğinde 1,6 adımda ulaşır. Sorumluluk
paylaşımının teknik yanı budur — yüzeylerin kime açıldığı; örgütsel yanı ise açılan yüzeyin
getirdiği inceleme yükünün kimin akışından düşüldüğüdür.

#### Özet

- Yirmi iki olgu ayrık gözlem alanlarında bölünür: 11'i iki alanda, 9'u yalnız işletenin, 1'i
  yalnız yazanın alanında, 1'i hiçbir alanda görünür; 4 olgu sahibine hiç ulaşmaz ve dördünün de
  sahibi yazan ekiptir.
- Sinyalin sahibine ulaşması ayrık düzende ortalama 7,0 adım, üç yüzey paylaşıldığında 5,0 adım,
  alanlar birleştirildiğinde 1,6 adım sürer.
- Birleştirmenin bedeli yazan ekibin akışındadır: gürültü 1'den 7 olguya, yük 95'ten 107 adıma
  çıkar; dağıtım sıklığı 5'ten 4 yayına iner ve öncü süre 25,8'den 34,8 adıma uzar.
- Karşılığında geri dönüş oranı %40'tan %0'a, kurtarma süresi 13,5'ten 10,2 adıma iner: dört
  ölçütün ikisi iyileşir, ikisi bozulur.
- Üç yüzeyin seçilerek paylaşılması iyileşmenin çoğunu getirir (ulaşmayan 1, ulaşma 5,0 adım, geri
  dönüş %20) ve yazan ekibin yükünü 95 adımda sabit bırakır.

#### Sonraki Adım

Gözlem alanı bölünmüşse sinyal geç ulaşır ya da hiç ulaşmaz; bu ölçüldü. Ama bölünme yalnız
gözlemde değildir: işin kendisi de bölünmüştür ve bir değişiklik ekipten ekibe **atılır**. Sonraki
ders aynı değişiklik kümesini iki düzende koşturur — ayrık ekipler ve paylaşılan sorumluluk — ve
sınır başına beklemeyi, aktarılamayan bağlam yüzünden geri dönen değişikliği ve üretimde ortaya
çıkan hata sayısını sayar.

### Duvar Üzerinden Atma

Source: https://academia.sh/tr/kurslar/devops-temelleri/duvar-uzerinden-atma

Ayrık ekiplerin ürettiği gecikme ve risk: aynı 18 değişikliğin taşıdığı 29 bağlam kaleminin 21'inin yazılı olmaması, ayrık düzende 14 kalemin sınırda düşüp 10 sınırdan dönüş ile 4 üretim hatası üretmesi, paylaşılan sorumlulukta düşen kalemin 5'e, dönüşün 3'e, üretim hatasının 2'ye inmesi ve geri dönüş oranının %22'den %11'e düşmesi, buna karşılık dağıtım sıklığının 9,5'ten 7,9'a, iç geçiş beklemesinin 8,1'den 12,2 adıma ve kurtarma süresinin 61,0'dan 65,0 adıma çıkması, sessiz bağlam taşıyan 7 değişiklikte iki düzenin de aynı 3 dönüş ve 2 hatayı üretmesi.

Önceki ders gözlem alanının bölünmesini ölçtü: yirmi iki olgunun dördü sahibine hiç ulaşmadı, üç
yüzeyin paylaşılması ulaşma süresini 7,0 adımdan 5,0 adıma indirdi. Bölünen yalnız gözlem değildir.
Bir değişikliğin fikirden üretime giden yolu da bölünmüştür ve değişiklik o bölünmenin üstünden
**atılır**.

**Duvar üzerinden atma**, bir değişikliğin taşıdığı bağlam yazıya dökülmeden bir ekip sınırının
ötesine verilmesidir. Atılan şey değişikliğin kendisi değil, onun hakkında bilinenlerdir: hangi
ayarın değiştiği, hangi veri biçiminin beklendiği, geri almanın nasıl yapılacağı. Bu ders aynı
değişiklik kümesini iki düzende koşturur ve sınırda düşen bağlamı sayar. M20/K05 el değiştirmeyi
bir iş kaleminin ekipler arası yolunda saymıştı; buradaki ölçek başkadır — sayılan şey bir
değişikliğin fikirden üretime giden yolundaki ekip sınırı ve o sınırda düşen bağlamdır.

#### Değişikliğin Yolu ve Taşıdığı Bağlam

Örnek yine kurgu **bölgesel ölçüm ağı**dır; ağ da ekipler de kurgudur. **KA7:** bir değişikliğin
yolu yedi adımdır — tanım, yazma, gözden geçirme, sınama kurulumu, kabul sınaması, üretim kurulumu,
üretim doğrulaması; ayrık düzende son dört adım işleten ekiptedir. **KA8:** on sekiz değişiklik
sekizer adım arayla akışa girer ve her ekip aynı anda tek değişiklik yürütür. **KA9:** her
değişiklik bağlam kalemi taşır; kalemin durduğu yer sınıfına bağlıdır — ayar, veri biçimi,
bağımlılık ve geri alma yazan ekipte, zamanlama ile kaynak işleten ekipte durur. **KA10:** kalem
üç durumdan birindedir: **yazılı** (her rolde elde), **sorulabilir** (yazılı değil ama ötekine
sorulabilir), **sessiz** (yazılı değil ve kimse eksik olduğunu bilmiyor). **KA11:** adımı yürüten
rol kalemin durduğu rol değilse ve kalem yazılı değilse, paylaşılan düzende sorulabilir kalem 2
adım sorma bedeliyle geçer, sessiz kalem düşer; ayrık düzende ikisi de düşer. Düşen kalem o
koşumda öğrenilir. **KA12:** düşen kalem üretim doğrulamasından önceyse değişiklik gözden geçirmeye
döner ve 3 adım yeniden iş yazar; üretim doğrulamasındaysa üretimde hata olur, 4 adım tutar ve
düzeltme yolu baştan yürür. Ekip sınırı geçişi 5, iç geçiş 1 adım devir beklemesi yazar.

Paylaşılan düzende sınama kurulumu ile üretim doğrulaması yazan ekibe geçer. Yol ve iki düzen
süreç içi bir **modeldir**; gerçek bir hat ya da değişiklik kaydı yoktur.

```js
// duvar/akis.mjs — bir degisikligin fikirden uretime giden yolu (model): gercek bir hat ya da
// degisiklik kaydi yok, adimlar veri yapisidir. Rastgelelik yok.

export const SINIR = 5, IC = 1, SORMA = 2, YENIDEN = 3, KURTARMA = 4, VARIS = 8, LIMIT = 900;
export const DONUS = 2;                       // sinirdan donen degisiklik gozden-gecirmeye doner
export const ROL = ["yazan", "isleten"];

export const ADIM = [["tanim", "yazan", 2], ["yazma", "yazan", 0], ["gozden-gecirme", "yazan", 2],
  ["sinama-kurulumu", "isleten", 2], ["kabul-sinamasi", "isleten", 3],
  ["uretim-kurulumu", "isleten", 2], ["uretim-dogrulama", "isleten", 2]]
  .map(([ad, rol, sure]) => ({ ad, rol, sure }));
export const PAYLASILAN = new Set(["sinama-kurulumu", "uretim-dogrulama"]);
const KISA = { k: "sinama-kurulumu", s: "kabul-sinamasi", u: "uretim-kurulumu",
  d: "uretim-dogrulama" };
// baglam sinifinin kaynagi: ayar/veri-bicimi/bagimlilik/geri-alma yazan ekipte, zamanlama ve
// kaynak isleten ekipte durur. Kalem durumu: y yazili, h yazili degil ama sorulabilir,
// x yazili degil ve sessiz (kimse eksik oldugunu bilmiyor).
export const SAHIP = { ayar: "yazan", "veri-bicimi": "yazan", bagimlilik: "yazan",
  "geri-alma": "yazan", zamanlama: "isleten", kaynak: "isleten" };

// degisiklik: ad, yazma adimi, tasidigi baglam kalemleri (sinif/gerektigi adim/durum)
export const DEGISIKLIK = `
  d01  5  ayar/k/h         veri-bicimi/s/y
  d02  3  zamanlama/u/h
  d03  6  bagimlilik/k/y   kaynak/u/h
  d04  4  ayar/s/h         geri-alma/d/h
  d05  7  veri-bicimi/k/x
  d06  3  zamanlama/d/x    ayar/u/y
  d07  5  kaynak/s/y       bagimlilik/u/h
  d08  4  geri-alma/d/h
  d09  6  ayar/k/h         zamanlama/s/h
  d10  3  veri-bicimi/u/h
  d11  5  bagimlilik/d/x   kaynak/k/y
  d12  4  ayar/s/y
  d13  6  zamanlama/k/x    geri-alma/u/h
  d14  3  kaynak/d/x
  d15  5  veri-bicimi/s/h  bagimlilik/k/y
  d16  4  ayar/u/x         zamanlama/d/y
  d17  6  geri-alma/s/h
  d18  3  kaynak/k/x       veri-bicimi/d/h`
  .trim().split("\n").map((r) => r.trim().split(/\s+/)).map(([ad, boyut, ...k]) => ({
    ad, boyut: +boyut, kalem: k.map((p) => { const [sinif, a, y] = p.split("/");
      return { sinif, adim: KISA[a], durum: y, sahip: SAHIP[sinif] }; }) }));

export function kos(duzen) {
  const adim = ADIM.map((a) => ({ ...a,
    rol: duzen === "paylasilan" && PAYLASILAN.has(a.ad) ? "yazan" : a.rol }));
  const D = DEGISIKLIK.map((d, i) => ({ ...d, i, adim: 0, hazir: i * VARIS, ek: 0, gecis: null,
    bilinen: new Set(d.kalem.filter((k) => k.durum === "y").map((k) => k.sinif)),
    kayip: null, dusen: [], bitti: false, uretimBitis: null, hataAt: null,
    kurtarma: null, hata: false, donus: 0 }));
  const sunucu = { yazan: null, isleten: null };
  const S = { kayip: 0, donus: 0, uretimHata: 0, dagitim: 0, sorma: 0, yenidenIs: 0,
    sinirGecis: 0, sinirBekleme: 0, icGecis: 0, icBekleme: 0 };

  const ilerle = (d, hedef, t, ek) => {
    const sinirMi = adim[hedef].rol !== adim[d.adim].rol;
    if (sinirMi) { S.sinirGecis++; S.sinirBekleme += SINIR; d.gecis = "sinir"; }
    else { S.icGecis++; S.icBekleme += IC; d.gecis = "ic"; }
    d.hazir = t + (sinirMi ? SINIR : IC); d.adim = hedef; d.ek = ek;
  };

  const basla = (d, r) => {
    const a = adim[d.adim];
    let sure = (a.ad === "yazma" ? d.boyut : a.sure) + d.ek;
    d.ek = 0; d.kayip = null;
    for (const k of d.kalem.filter((k) => k.adim === a.ad && !d.bilinen.has(k.sinif))) {
      d.bilinen.add(k.sinif);                 // kalem her durumda burada ogrenilir
      if (k.sahip === r) continue;            // adimi yuruten rol kalemi zaten tasiyor
      if (duzen === "paylasilan" && k.durum === "h") {   // otekine sorulur, bedeli adimdir
        sure += SORMA; S.sorma += SORMA; continue;
      }
      S.kayip++; d.kayip = k; d.dusen.push(k);          // sinirda duser
    }
    d.kalan = sure;
  };

  const bitir = (d, t) => {
    const a = adim[d.adim];
    if (a.ad === "uretim-kurulumu") { S.dagitim++; if (d.uretimBitis === null) d.uretimBitis = t; }
    if (d.kayip) {
      const uretimde = a.ad === "uretim-dogrulama";
      if (uretimde) { S.uretimHata++; d.hata = true; d.hataAt = t; } else { S.donus++; d.donus++; }
      S.yenidenIs += uretimde ? KURTARMA : YENIDEN;
      return ilerle(d, DONUS, t, uretimde ? KURTARMA : YENIDEN);
    }
    if (d.adim < adim.length - 1) return ilerle(d, d.adim + 1, t, 0);
    if (d.hata && d.kurtarma === null) d.kurtarma = t - d.hataAt;
    d.bitti = true;
  };

  for (let t = 0; t < LIMIT; t++) for (const r of ROL) {
    if (sunucu[r] === null) {
      const aday = D.filter((d) => !d.bitti && d !== sunucu.yazan && d !== sunucu.isleten
        && d.hazir <= t && adim[d.adim].rol === r).sort((a, b) => a.hazir - b.hazir || a.i - b.i)[0];
      if (aday) {
        if (aday.gecis === "sinir") S.sinirBekleme += t - aday.hazir;
        else if (aday.gecis === "ic") S.icBekleme += t - aday.hazir;
        basla(aday, r); sunucu[r] = aday;
      }
    }
    const d = sunucu[r];
    if (d && --d.kalan === 0) { sunucu[r] = null; bitir(d, t + 1); }
  }
  return { D, S, pencere: Math.max(...D.map((d) => d.uretimBitis ?? 0)) };
}

export const ort = (a) => (a.length ? (a.reduce((s, v) => s + v, 0) / a.length).toFixed(1) : "-");

export function olc(duzen) {
  const { D, S, pencere } = kos(duzen);
  const oncu = D.map((d) => d.uretimBitis - d.i * VARIS);
  return { D, S, pencere,
    sinirGecis: S.sinirGecis, sinirBasinaBekleme: (S.sinirBekleme / S.sinirGecis).toFixed(1),
    icBasinaBekleme: (S.icBekleme / S.icGecis).toFixed(1), bilgiKaybi: S.kayip,
    sorma: S.sorma, sinirdanDonen: S.donus, uretimHata: S.uretimHata, yenidenIs: S.yenidenIs,
    onculSure: ort(oncu), dagitimSikligi: (100 * S.dagitim / pencere).toFixed(1),
    geriDonusOrani: (100 * D.filter((d) => d.hata).length / D.length).toFixed(0) + "%",
    kurtarma: ort(D.filter((d) => d.hata).map((d) => d.kurtarma)),
    bitmeyen: D.filter((d) => !d.bitti).length };
}
```

Dört teslimat ölçütü aynı koşumdan okunur: **dağıtım sıklığı** 100 adımda tamamlanan üretim
kurulumu (yeniden dağıtımlar dahil), **öncü süre** değişikliğin akışa girişinden ilk kez üretime
kurulmasına kadar geçen adım, **geri dönüş oranı** üretimde hata çıkaran değişikliğin payı,
**kurtarma süresi** hatanın çıktığı andan düzeltmenin üretimde doğrulanmasına kadar geçen adımdır.

```js
// duvar/olc.mjs — ayni 18 degisiklik iki duzende: sinir beklemesi, bilgi kaybi, uretim hatasi.
import { DEGISIKLIK, ADIM, PAYLASILAN, VARIS, olc, ort } from "./akis.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const kalem = DEGISIKLIK.flatMap((d) => d.kalem);
const say = (f) => kalem.filter(f).length;
const R = { ayrik: olc("ayrik"), paylasilan: olc("paylasilan") };

console.log(`${DEGISIKLIK.length} degisiklik, ${ADIM.length} adim, ${kalem.length} baglam kalemi: ` +
  `${say((k) => k.durum === "y")} yazili, ${say((k) => k.durum === "h")} sorulabilir, ` +
  `${say((k) => k.durum === "x")} sessiz`);
console.log(`  kalemin durdugu yer: ` + ["yazan", "isleten"].map((r) =>
  `${r} ${say((k) => k.sahip === r)}`).join(", "));
console.log(`  ayrik: ${ADIM.filter((a) => a.rol === "isleten").length} adim isletende; ` +
  `paylasilan: ${[...PAYLASILAN].join(" ve ")} yazana gecer`);
console.log(`  penceresinde bitmeyen degisiklik: ayrik ${R.ayrik.bitmeyen}, ` +
  `paylasilan ${R.paylasilan.bitmeyen}`);

const A = [-31, 9, 13];
console.log("\n1. ayni degisiklik kumesi iki duzende");
yaz(A, "olcu", "ayrik", "paylasilan");
for (const [ad, k] of [["ekip siniri gecisi", "sinirGecis"],
  ["sinir basina bekleme (adim)", "sinirBasinaBekleme"],
  ["ic gecis basina bekleme (adim)", "icBasinaBekleme"],
  ["bilgi kaybi (dusen kalem)", "bilgiKaybi"], ["sorma maliyeti (adim)", "sorma"],
  ["sinirdan donen degisiklik", "sinirdanDonen"], ["uretimde cikan hata", "uretimHata"],
  ["yeniden is (adim)", "yenidenIs"]]) yaz(A, ad, R.ayrik[k], R.paylasilan[k]);

console.log("\n2. dort teslimat olcutu");
yaz(A, "olcut", "ayrik", "paylasilan");
for (const [ad, k] of [["dagitim sikligi (100 adimda)", "dagitimSikligi"],
  ["oncu sure (ort. adim)", "onculSure"], ["geri donus orani", "geriDonusOrani"],
  ["kurtarma suresi (ort. adim)", "kurtarma"], ["son degisikligin uretime girisi", "pencere"]])
  yaz(A, ad, R.ayrik[k], R.paylasilan[k]);

const B = [-18, 7, 12, 9, 13, 16];
console.log("\n3. kalem hangi adimda dustu (dusen: ayrik / paylasilan)");
yaz(B, "adim", "kalem", "yazilmamis", "yazan", "sessiz", "dusen");
for (const a of ADIM.filter((a) => a.rol === "isleten")) {
  const g = kalem.filter((k) => k.adim === a.ad), h = g.filter((k) => k.durum !== "y");
  const d = (dz) => R[dz].D.flatMap((x) => x.dusen ?? []).filter((k) => k.adim === a.ad).length;
  yaz(B, a.ad, g.length, h.length, h.filter((k) => k.sahip === "yazan").length,
    h.filter((k) => k.durum === "x").length, `${d("ayrik")} / ${d("paylasilan")}`);
}

const C = [-21, -12, 11, 16, 15];
console.log("\n4. degisiklik basina yol");
yaz(C, "degisiklik", "duzen", "oncu sure", "sinirdan donus", "uretim hatasi");
for (const [ad, f] of [["yalniz yazili", (d) => d.kalem.every((k) => k.durum === "y")],
  ["sorulabilir var", (d) => d.kalem.some((k) => k.durum === "h") &&
    !d.kalem.some((k) => k.durum === "x")],
  ["sessiz var", (d) => d.kalem.some((k) => k.durum === "x")]])
  for (const dz of ["ayrik", "paylasilan"]) {
    const g = R[dz].D.filter(f);
    if (!g.length) continue;
    yaz(C, dz === "ayrik" ? `${ad} (${g.length})` : "", dz,
      ort(g.map((d) => d.uretimBitis - d.i * VARIS)),
      g.reduce((s, d) => s + d.donus, 0), g.filter((d) => d.hata).length);
  }
```

```
18 degisiklik, 7 adim, 29 baglam kalemi: 8 yazili, 14 sorulabilir, 7 sessiz
  kalemin durdugu yer: yazan 19, isleten 10
  ayrik: 4 adim isletende; paylasilan: sinama-kurulumu ve uretim-dogrulama yazana gecer
  penceresinde bitmeyen degisiklik: ayrik 0, paylasilan 0

1. ayni degisiklik kumesi iki duzende
olcu                               ayrik   paylasilan
ekip siniri gecisi                    46           42
sinir basina bekleme (adim)         11.2         11.0
ic gecis basina bekleme (adim)       8.1         12.2
bilgi kaybi (dusen kalem)             14            5
sorma maliyeti (adim)                  0           12
sinirdan donen degisiklik             10            3
uretimde cikan hata                    4            2
yeniden is (adim)                     46           17

2. dort teslimat olcutu
olcut                              ayrik   paylasilan
dagitim sikligi (100 adimda)         9.5          7.9
oncu sure (ort. adim)               85.6         87.2
geri donus orani                     22%          11%
kurtarma suresi (ort. adim)         61.0         65.0
son degisikligin uretime girisi      275          267

3. kalem hangi adimda dustu (dusen: ayrik / paylasilan)
adim                kalem  yazilmamis    yazan       sessiz           dusen
sinama-kurulumu         8           5        3            3           3 / 2
kabul-sinamasi          7           4        3            0           3 / 0
uretim-kurulumu         7           6        4            1           4 / 1
uretim-dogrulama        7           6        4            3           4 / 2

4. degisiklik basina yol
degisiklik           duzen         oncu sure  sinirdan donus  uretim hatasi
yalniz yazili (1)    ayrik              93.0               0              0
                     paylasilan        115.0               0              0
sorulabilir var (10) ayrik              77.2               7              2
                     paylasilan         70.0               0              0
sessiz var (7)       ayrik              96.4               3              2
                     paylasilan        107.7               3              2
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır.

#### Sınırda Ne Düşüyor

Ayrık düzende on dört kalem sınırda **düşer**: yazan ekipte duran ve işleten ekibin yürüttüğü
adımda gereken her yazılmamış kalem kaybolur. Sonucu on sınırdan dönüş, dört üretim hatası ve 46
adım yeniden iştir.

Paylaşılan sorumlulukta düşen kalem 5'e, sınırdan dönüş 3'e, üretim hatası 2'ye iner; karşılığında
12 adım sorma bedeli ödenir. Ama üçüncü tablo asıl değişimin bir **yön değişimi** olduğunu
gösterir. Ayrık düzende düşenler yazan ekipte duran kalemlerdir: sınama kurulumunda 3,
kabul sınamasında 3, üretim kurulumunda 4, üretim doğrulamasında 4. Paylaşılan düzende sınama
kurulumu ile üretim doğrulaması yazan ekibe geçtiği için o adımlarda artık işleten ekipte duran
kalemler düşer — zamanlama ve kaynak. **Duvarı kaldırmak bilgi kaybını yok etmez, ters yöne
çevirir;** kalan beş kaybın tamamı işletenin bildiği ve yazanın bilmediği şeydir.

Dördüncü tablo ayrımı keskinleştirir. Sorulabilir bağlam taşıyan on değişiklikte paylaşılan düzen
sınırdan dönüşü 7'den 0'a, üretim hatasını 2'den 0'a indirir ve öncü süreyi 77,2'den 70,0 adıma
düşürür. Sessiz bağlam taşıyan yedi değişiklikte **hiçbir şey değişmez**: iki düzen de aynı 3
dönüşü ve aynı 2 hatayı üretir, üstelik öncü süre 96,4'ten 107,7 adıma çıkar. Sorma ancak eksik
olduğu bilinen şey için işler.

#### Duvarı Kaldırmanın Bedeli

İkinci tablo dört ölçütü yan yana koyar. Geri dönüş oranı %22'den %11'e iner; paylaşılan düzenin
kazandığı tek ölçüt budur. Dağıtım sıklığı 9,5'ten 7,9'a, öncü süre 85,6'dan 87,2 adıma, kurtarma
süresi 61,0'dan 65,0 adıma gider. **Dört ölçütün biri iyileşir, üçü bozulur.**

Nedeni birinci tablonun üçüncü satırındadır: iç geçiş başına bekleme 8,1 adımdan 12,2 adıma çıkar.
Paylaşılan düzende yazan ekip yedi adımın beşini yürütür ve darboğaz oraya taşınır. Ekip sınırı
geçişi değişiklik başına 1'den 2'ye çıkmasına karşın toplamda 46'dan 42'ye iner, çünkü geri dönüş
azalmıştır; sınır başına bekleme ise 11,2 adımdan 11,0 adıma, yani neredeyse hiç değişmez. **Duvarı
kaldırmak sınırı ucuzlatmaz, sınırdan geçen iş sayısını azaltır.**

#### Farkın Saklandığı Yer

Bu derste fark **yazılmamış bağlamda** saklıdır: yirmi dokuz kalemin yirmi biri yazılı değildir —
on dördü sorulabilir, yedisi sessiz. Bildirilmiş kısım yalnız sekiz kalemdir. On dördü ancak
koşumda, düştüğü adımda görünür; yedisi düştüğünde bile nedeni görünmez, çünkü kimse o kalemin
gerektiğini bilmemektedir.

Sinyalin kime kaç adımda ulaştığı da buradan okunur: düşen kalem üretim doğrulamasından önceyse
sinyal yazan ekibe bir sınır geçişi ve ortalama 11,2 adım beklemeyle döner; üretim doğrulamasında
düşerse aynı sinyal ortalama 61,0 adım sonra, üretimde çıkmış bir hata olarak ulaşır. **Aynı eksik
kalem, düştüğü adıma göre beş kattan fazla pahalıdır.**

#### Özet

- Aynı 18 değişikliğin taşıdığı 29 bağlam kaleminin 21'i yazılı değildir: 14'ü sorulabilir, 7'si
  sessiz.
- Ayrık düzende 14 kalem sınırda düşer, 10 sınırdan dönüş ve 4 üretim hatası üretir, 46 adım
  yeniden iş yazar; paylaşılan sorumlulukta bunlar 5, 3, 2 ve 17 olur, karşılığında 12 adım sorma
  bedeli ödenir.
- Kayıp yok olmaz, yön değiştirir: paylaşılan düzende düşen beş kalemin tamamı işleten ekipte duran
  zamanlama ve kaynak kalemleridir.
- Dört ölçütten yalnız geri dönüş oranı iyileşir (%22 → %11); dağıtım sıklığı 9,5'ten 7,9'a, öncü
  süre 85,6'dan 87,2 adıma, kurtarma süresi 61,0'dan 65,0 adıma gider — darboğaz yazan ekibe
  taşınır (iç geçiş beklemesi 8,1 → 12,2 adım).
- Sorulabilir bağlam taşıyan 10 değişiklikte paylaşılan düzen dönüşü 7'den 0'a indirir; sessiz
  bağlam taşıyan 7 değişiklikte aynı 3 dönüş ve 2 hata iki düzende de çıkar.

#### Sonraki Adım

İki düzen de aynı yol üzerinde ölçüldü; yolun kendisi sabit tutuldu. Oysa asıl soru bu yolun
neresinde ne kadar durulduğudur. Sonraki ders yolu bir **değer akışı haritası** olarak kurar: her
adım için işlem süresi, bekleme süresi ve ilk seferde doğru oranı ölçülür; toplam öncü sürenin ne
kadarının katma değerli olduğu, en uzun beklemenin nerede durduğu ve bir adımı iyileştirmenin
toplam süreye neden çoğu zaman yansımadığı sayılır.

### Değer Akışı

Source: https://academia.sh/tr/kurslar/devops-temelleri/deger-akisi

Fikirden üretime giden yolun haritalanması: dokuz adımlı akışta 20 iş kaleminin ortalama 182,0 adımlık öncü süresinin 70,2 adımının işlem ve 111,8 adımının bekleme olması (katma değerli pay %38,5), toplam 2237 adım beklemenin 1485'inin tek bir adımda — yayın penceresinde — durması, yayın penceresi 20 adımken hiçbir tek adım iyileştirmesinin öncü süreyi 2 adımdan fazla kısaltmaması, pencere 5 adıma indirildiğinde aynı iyileştirmelerin ayrışıp yazma 10'dan 5'e inince 32 adım kazandırması ama kabul onayı 2'den 1'e inince 4 adım kaybettirmesi ve darboğazın yayın penceresinden yazmaya, oradan tümleşik sınamaya kayması.

Önceki ders aynı yolu iki düzende koşturdu ve sınırda düşen bağlamı saydı, ama yolun kendisini
sabit tuttu: yedi adım, sabit süreler. Bir değişikliğin fikirden üretime giden yolunda asıl soru
kaç adım olduğu değil, o adımların hangisinde ne kadar **durulduğu**dur.

**Değer akışı haritası**, bu yoldaki her adımı üç sayıyla yazan çizelgedir: işlem süresi, bekleme
süresi ve ilk seferde doğru oranı. M20/K05'in `iş kalemi` ile aynı nesneyi ölçer, ölçeği farklıdır
— orada ölçülen bir iş kaleminin ekipler arası yoluydu, burada ölçülen bir değişikliğin fikirden
üretime giden yoludur.

#### Haritanın Kurulması

Örnek yine kurgu **bölgesel ölçüm ağı**dır; ağ da akış da kurgudur. **KA13:** yol dokuz adımdır —
talep sıraya alma, çözümleme, yazma, gözden geçirme, tümleşik sınama, kabul onayı, yayın penceresi,
üretim kurulumu, üretim doğrulaması. **KA14:** her adımın eş zamanlı yürütücü sayısı, işlem süresi
ve ilk seferde doğru oranı vardır; ilk seferde doğru çıkmayan kalem adımın dönüş hedefine geri
gider ve o adımdan itibaren yeniden yürür. **KA15:** yirmi iş kalemi on ikişer adım arayla akışa
girer. **Bekleme bir girdi değildir, ölçülür:** yürütücü doluysa kuyrukta, yayın penceresi
kapalıysa pencerede birikir. **KA16:** yayın penceresi yirmi adımda bir açılır. **KA17:**
rastgelelik üreteçle yazılır, tohum 20260801'dir; her kaleme kendi zar dizisi verilir, böylece bir
adımın süresi değiştiğinde kalemin şansı değişmez ve koşumlar karşılaştırılabilir kalır. **KA18:**
öncü süre akışa girişten üretim doğrulamasının bitişine kadar geçen adımdır; katma değerli süre
kalemin adımlarda geçirdiği işlem süresinin toplamıdır.

Harita ve akış süreç içi bir **modeldir**; gerçek bir akış kaydı ya da yayın çizelgesi yoktur.

```js
// akis/harita.mjs — fikirden uretime deger akisi haritasi (model): gercek bir akis kaydi yok,
// adimlar veri yapisidir. Rastgelelik uretecle yazilir, tohum gorunur.

export const N = 20, VARIS = 12, LIMIT = 4000, PENCERE = 20, TOHUM = 20260801;

// adim: ad, es zamanli yurutucu, islem suresi, ilk seferde dogru orani, donus hedefi
export const ADIM = [
  ["talep-siraya-alma", 1, 1, 1.00, 0], ["cozumleme", 1, 4, 0.85, 0],
  ["yazma", 2, 10, 0.80, 1], ["gozden-gecirme", 1, 3, 0.75, 2],
  ["tumlesik-sinama", 1, 8, 0.70, 2], ["kabul-onayi", 1, 2, 0.90, 1],
  ["yayin-penceresi", 1, 1, 1.00, 0], ["uretim-kurulumu", 1, 3, 0.95, 2],
  ["uretim-dogrulama", 1, 2, 0.90, 2],
].map(([ad, kap, islem, isd, donus], i) => ({ ad, kap, islem, isd, donus, i }));

// dogrusal eslesmeli uretec: her kaleme kendi zar dizisi verilir, boylece bir adimin suresi
// degistiginde kalemin sansi degismez ve kosumlar karsilastirilabilir kalir.
export function uretec(tohum) {
  let x = tohum >>> 0;
  return () => ((x = (x * 1664525 + 1013904223) >>> 0) / 2 ** 32);
}

export function kos({ islem = {}, pencere = PENCERE } = {}) {
  const adim = ADIM.map((a) => ({ ...a, islem: islem[a.ad] ?? a.islem }));
  const zar = uretec(TOHUM);
  const K = Array.from({ length: N }, (_, i) => ({ i, varis: i * VARIS, adim: 0,
    hazir: i * VARIS, kosuyor: false, kalan: 0, bitti: false, bitis: null, isToplam: 0,
    bekleme: 0, yenidenIs: 0, hata: false, hataAt: null, kurtarma: null,
    zar: Array.from({ length: 80 }, zar), zarNo: 0 }));
  const mesgul = adim.map(() => 0);
  const S = { bekleme: adim.map(() => 0), islem: adim.map(() => 0), ziyaret: adim.map(() => 0),
    donus: adim.map(() => 0), dagitim: 0 };

  const bitir = (d, t) => {
    const a = adim[d.adim];
    mesgul[a.i]--; d.kosuyor = false;
    if (a.isd < 1 && d.zar[d.zarNo++] >= a.isd) {        // ilk seferde dogru degil
      S.donus[a.i]++; d.yenidenIs++;
      if (a.ad === "uretim-dogrulama" && !d.hata) { d.hata = true; d.hataAt = t; }
      d.adim = a.donus; d.hazir = t; return;
    }
    if (a.ad === "uretim-kurulumu") S.dagitim++;
    if (a.i === adim.length - 1) {
      d.bitti = true; d.bitis = t;
      if (d.hata) d.kurtarma = t - d.hataAt;
      return;
    }
    d.adim = a.i + 1; d.hazir = t;
  };

  for (let t = 0; t < LIMIT; t++) {
    for (const a of adim) {
      if (a.ad === "yayin-penceresi" && t % pencere !== 0) continue;   // toplu yayin penceresi
      const kuyruk = K.filter((d) => !d.bitti && !d.kosuyor && d.adim === a.i && d.hazir <= t)
        .sort((x, y) => x.hazir - y.hazir || x.i - y.i);
      for (const d of kuyruk) {
        if (mesgul[a.i] >= a.kap) break;
        S.bekleme[a.i] += t - d.hazir; d.bekleme += t - d.hazir;
        S.islem[a.i] += a.islem; S.ziyaret[a.i]++; d.isToplam += a.islem;
        d.kosuyor = true; d.kalan = a.islem; mesgul[a.i]++;
      }
    }
    for (const d of K) if (d.kosuyor && --d.kalan === 0) bitir(d, t + 1);
  }
  return { K, S, adim };
}

export const ort = (a) => (a.length ? (a.reduce((s, v) => s + v, 0) / a.length).toFixed(1) : "-");

export function olc(ayar) {
  const { K, S, adim } = kos(ayar);
  const oncu = K.map((d) => d.bitis - d.varis);
  const pencere = Math.max(...K.map((d) => d.bitis));
  const kd = K.reduce((s, d) => s + d.isToplam, 0), top = oncu.reduce((s, v) => s + v, 0);
  return { K, S, adim,
    onculSure: ort(oncu), katmaDeger: (100 * kd / top).toFixed(1) + "%",
    enUzunBekleme: adim[S.bekleme.indexOf(Math.max(...S.bekleme))].ad,
    ilkSefer: (100 * K.filter((d) => d.yenidenIs === 0).length / N).toFixed(0) + "%",
    yenidenIs: K.reduce((s, d) => s + d.yenidenIs, 0),
    dagitimSikligi: (100 * S.dagitim / pencere).toFixed(1),
    geriDonusOrani: (100 * K.filter((d) => d.hata).length / N).toFixed(0) + "%",
    kurtarma: ort(K.filter((d) => d.hata).map((d) => d.kurtarma)),
    bitmeyen: K.filter((d) => !d.bitti).length };
}
```

```js
// akis/olc.mjs — haritanin okunmasi: katma deger payi, en uzun bekleme, tek adim iyilestirmesi.
import { ADIM, N, PENCERE, TOHUM, olc, ort } from "./harita.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const T = olc({}), P = olc({ pencere: 5 });

console.log(`${N} is kalemi, ${ADIM.length} adim, yayin penceresi ${PENCERE} adim, ` +
  `tohum ${TOHUM}; bitmeyen ${T.bitmeyen}`);

const A = [-19, 6, 7, 14, 9, 11, 7, 10];
console.log("\n1. deger akisi haritasi (olculen)");
yaz(A, "adim", "yurutucu", "islem", "ort. bekleme", "ziyaret", "ilk sefer", "donus",
  "bekleme");
for (const a of T.adim) {
  const z = T.S.ziyaret[a.i];
  yaz(A, a.ad, a.kap, a.islem, (T.S.bekleme[a.i] / z).toFixed(1), z,
    a.isd < 1 ? `${(100 * (1 - T.S.donus[a.i] / z)).toFixed(0)}%` : "-", T.S.donus[a.i],
    T.S.bekleme[a.i]);
}

const B = [-34, 16];
console.log("\n2. haritanin toplami (taban)");
for (const [ad, v] of [["ort. oncu sure (adim)", T.onculSure],
  ["kalem basina islem (adim)", ort(T.K.map((d) => d.isToplam))],
  ["kalem basina bekleme (adim)", ort(T.K.map((d) => d.bekleme))],
  ["katma degerli payi", T.katmaDeger], ["en uzun beklemenin durdugu adim", T.enUzunBekleme],
  ["hic yeniden ise donmeyen kalem", T.ilkSefer], ["toplam yeniden is (donus)", T.yenidenIs]])
  yaz(B, ad, v);

const C = [-19, 11, 12, 10, 12, 10];
console.log("\n3. tek adimin islem suresi yariya inerse (iki pencere ayarinda)");
yaz(C, "iyilestirilen", "islem", "pencere 20", "degisim", "pencere 5", "degisim");
yaz(C, "(taban)", "-", T.onculSure, "-", P.onculSure, "-");
for (const a of ADIM.filter((a) => a.islem >= 2)) {
  const y = Math.floor(a.islem / 2), i = { [a.ad]: y };
  const R = olc({ islem: i }), Q = olc({ islem: i, pencere: 5 });
  yaz(C, a.ad, `${a.islem} -> ${y}`, R.onculSure, (R.onculSure - T.onculSure).toFixed(1),
    Q.onculSure, (Q.onculSure - P.onculSure).toFixed(1));
}

const D = [-30, 10, 9, 11, 10, 12];
const K = { "taban (pencere 20)": T, "darbogaz: yazma 10->5": olc({ islem: { yazma: 5 } }),
  "darbogaz disi: cozumleme 4->2": olc({ islem: { cozumleme: 2 } }),
  "pencere 20->5": P,
  "pencere 5 + yazma 10->5": olc({ pencere: 5, islem: { yazma: 5 } }) };
console.log("\n4. dort teslimat olcutu ve katma deger payi");
yaz(D, "kosum", "oncu sure", "dagitim", "geri donus", "kurtarma", "katma deger");
for (const [ad, R] of Object.entries(K))
  yaz(D, ad, R.onculSure, R.dagitimSikligi, R.geriDonusOrani, R.kurtarma, R.katmaDeger);

const E = [-30, 16, 16];
console.log("\n5. beklemenin nerede durdugu");
yaz(E, "kosum", "en uzun bekleme", "toplam bekleme");
for (const [ad, R] of Object.entries(K))
  yaz(E, ad, R.enUzunBekleme, R.S.bekleme.reduce((s, v) => s + v, 0));
```

```
20 is kalemi, 9 adim, yayin penceresi 20 adim, tohum 20260801; bitmeyen 0

1. deger akisi haritasi (olculen)
adim               yurutucu  islem  ort. bekleme  ziyaret  ilk sefer  donus   bekleme
talep-siraya-alma       1      1           0.0       28          -      0         0
cozumleme               1      4           1.0       48        83%      8        50
yazma                   2     10           8.6       61        70%     18       524
gozden-gecirme          1      3           0.0       43        74%     11         0
tumlesik-sinama         1      8           5.6       32        78%      7       178
kabul-onayi             1      2           0.0       25        92%      2         0
yayin-penceresi         1      1          64.6       23          -      0      1485
uretim-kurulumu         1      3           0.0       23       100%      0         0
uretim-dogrulama        1      2           0.0       23        87%      3         0

2. haritanin toplami (taban)
ort. oncu sure (adim)                        182.0
kalem basina islem (adim)                     70.2
kalem basina bekleme (adim)                  111.8
katma degerli payi                           38.5%
en uzun beklemenin durdugu adim    yayin-penceresi
hic yeniden ise donmeyen kalem                 20%
toplam yeniden is (donus)                       49

3. tek adimin islem suresi yariya inerse (iki pencere ayarinda)
iyilestirilen            islem  pencere 20   degisim   pencere 5   degisim
(taban)                      -       182.0         -       118.0         -
cozumleme               4 -> 2       182.0       0.0       114.0      -4.0
yazma                  10 -> 5       180.0      -2.0        86.0     -32.0
gozden-gecirme          3 -> 1       182.0       0.0       115.5      -2.5
tumlesik-sinama         8 -> 4       180.0      -2.0       106.0     -12.0
kabul-onayi             2 -> 1       182.0       0.0       122.0       4.0
uretim-kurulumu         3 -> 1       180.0      -2.0       117.0      -1.0
uretim-dogrulama        2 -> 1       181.0      -1.0       118.0       0.0

4. dort teslimat olcutu ve katma deger payi
kosum                          oncu sure  dagitim geri donus  kurtarma katma deger
taban (pencere 20)                 182.0      4.5        15%     213.3       38.5%
darbogaz: yazma 10->5              180.0      4.5        15%     213.3       30.5%
darbogaz disi: cozumleme 4->2      182.0      4.5        15%     220.0       35.9%
pencere 20->5                      118.0      6.0        15%     130.0       59.4%
pencere 5 + yazma 10->5             86.0      6.7        15%      73.3       63.8%

5. beklemenin nerede durdugu
kosum                          en uzun bekleme  toplam bekleme
taban (pencere 20)             yayin-penceresi            2237
darbogaz: yazma 10->5          yayin-penceresi            2502
darbogaz disi: cozumleme 4->2  yayin-penceresi            2333
pencere 20->5                            yazma             957
pencere 5 + yazma 10->5        tumlesik-sinama             622
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır. Model katma değerliyi
"işlem" olarak tanımlar ve yeniden iş de işlem sayılır; bu yüzden %38,5 bir tavan değeridir.

#### Öncü Sürenin İçinde Ne Var

Ortalama öncü süre 182,0 adımdır: 70,2 adım işlem, 111,8 adım bekleme. Katma değerli pay %38,5'tir
— bir kalem yolun üçte ikisini durarak geçirir. Yığılmış ilk seferde doğru oranı daha çarpıcıdır:
yirmi kalemin yalnız dördü, yani **%20'si**, hiç geri dönmeden akışı geçer. Kalan on altı kalem
toplam 49 dönüş üretir.

Birinci tablo bu 49 dönüşü adıma dağıtır: yazma 18, gözden geçirme 11, çözümleme 8, tümleşik sınama
7, üretim doğrulaması 3, kabul onayı 2. Ziyaret sayıları bunun sonucudur — yirmi kalem yazma
adımını 61 kez ziyaret eder.

Beklemenin dağılımı ise düz değildir. Dokuz adımın beşinde bekleme sıfırdır. Toplam 2237 adım
beklemenin **1485'i tek bir adımda durur: yayın penceresi.** Ziyaret başına 64,6 adım. İkinci en
büyük yığılma yazma adımındadır (524 adım, ziyaret başına 8,6). **Beklemenin durduğu yer ile işin
yapıldığı yer aynı değildir.**

#### Bir Adımı İyileştirmek Neden Görünmüyor

Üçüncü tablo her adımın işlem süresini yarıya indirip toplam öncü süredeki değişimi ölçer. Yayın
penceresi 20 adımken sonuç tektir: **hiçbir iyileştirme 2 adımdan fazla kazandırmaz.** Çözümlemeyi
4'ten 2'ye indirmek 0,0 adım, yazmayı 10'dan 5'e indirmek 2,0 adım kazandırır. On adımlık bir işi
yarıya bölmek 182 adımlık öncü sürenin yüzde birini bile değiştirmez, çünkü kazanılan süre yayın
penceresinde geri beklenir.

Pencere 5 adıma indirildiğinde aynı iyileştirmeler ayrışır. Yazma 10'dan 5'e inince öncü süre 32,0
adım kısalır; tümleşik sınama 8'den 4'e inince 12,0; çözümleme 4'ten 2'ye inince yalnız 4,0. Kabul
onayını 2'den 1'e indirmek ise öncü süreyi **4,0 adım uzatır** — kalemler darboğaza daha sık ve
daha kümelenmiş varır. **Darboğaz dışındaki iyileştirme yalnız görünmez değildir; işaret bile
değiştirebilir.**

#### Darboğaz Kayar

Beşinci tablo en uzun beklemenin nerede durduğunu koşum koşum izler. Tabanda yayın penceresidir.
Pencere 5'e indirilince yazmaya geçer (toplam bekleme 2237'den 957'ye iner). Yazma da yarıya
indirilince tümleşik sınamaya geçer (622). Üç koşumda üç ayrı adım.

Dördüncü tablo bunun teslimat karşılığını verir. Geri dönüş oranı beş koşumun beşinde de %15'tir;
ilk seferde doğru oranları değişmediği için bu ölçüt hiç oynamaz. Dağıtım sıklığı 4,5'ten 6,0'a,
oradan 6,7'ye çıkar; kurtarma süresi 213,3'ten 130,0'a, oradan 73,3 adıma iner; katma değerli pay
%38,5'ten %59,4'e, oradan %63,8'e yükselir. Buna karşılık **yalnız darboğazı iyileştiren koşumda
katma değerli pay %38,5'ten %30,5'e düşer:** işlem süresi kısalmış, bekleme yerinde kalmıştır.

#### Farkın Saklandığı Yer

Bu derste fark **beklemenin dağılımında** saklıdır ve sayısı şudur: dokuz adımın beşinde bekleme
sıfır, birinde toplamın %66'sı. Bildirilmiş kısım işlem süreleridir — haritaya bakan herkes yazmanın
10, tümleşik sınamanın 8 adım sürdüğünü okur. Bildirilmemiş kısım beklemedir; girdi değildir,
ancak koşumda doğar ve iyileştirme kararını o belirler.

Sinyalin kime kaç adımda ulaştığı da dönüş hedeflerinden okunur. Tümleşik sınamada bulunan sapma
yazma adımına iki adım geriden döner ve 7 dönüş buradan gelir. Aynı sınıftan bir sapma üretim
doğrulamasında bulunursa yazmaya altı adım geriden döner; bu 3 kalemin kurtarma süresi 213,3
adımdır. **Sinyal aynıdır; pahalı olan, geri dönüş yolunun uzunluğudur.**

#### Özet

- Dokuz adımlık akışta ortalama öncü süre 182,0 adımdır: 70,2 adım işlem, 111,8 adım bekleme; katma
  değerli pay %38,5 (yeniden iş de işlem sayıldığı için bu bir tavan değeridir).
- Yirmi kalemin yalnız %20'si hiç geri dönmeden geçer; 49 dönüşün 18'i yazma, 11'i gözden geçirme,
  8'i çözümleme adımından çıkar.
- Toplam 2237 adım beklemenin 1485'i tek bir adımda durur (yayın penceresi, ziyaret başına 64,6);
  dokuz adımın beşinde bekleme sıfırdır.
- Yayın penceresi 20 adımken hiçbir tek adım iyileştirmesi öncü süreyi 2 adımdan fazla kısaltmaz;
  pencere 5'e indirildiğinde yazma 32,0 adım kazandırır, kabul onayı ise 4,0 adım kaybettirir.
- Darboğaz üç koşumda üç ayrı adıma kayar; dağıtım sıklığı 4,5 → 6,0 → 6,7 ve kurtarma süresi
  213,3 → 130,0 → 73,3 adım olurken geri dönüş oranı beş koşumda da %15'te kalır.

#### Sonraki Adım

Bu ders dört ölçütü birer sonuç olarak okudu: harita değişti, ölçütler onu izledi. Oysa ölçütlerin
kendisi bir kümedir ve birbirini oynatır. Sonraki ders dört teslimat ölçütünü — dağıtım sıklığı,
öncü süre, geri dönüş oranı, kurtarma süresi — **bağlı bir küme** olarak koşturur: parti
büyüklüğünü küçültmenin, kapı eklemenin ve otomatik geri almanın her dördünde ölçülen değişimi
yazılır ve bir ölçütü iyileştirip ötekini bozan kararlar adıyla gösterilir.

### Teslimat Ölçütleri

Source: https://academia.sh/tr/kurslar/devops-temelleri/teslimat-olcutleri

Dağıtım sıklığı, öncü süre, geri dönüş oranı ve kurtarma süresi bağlı bir küme olarak: 60 değişikliğin 12'si kusurluyken parti 8'den 2'ye inince dağıtım sıklığının 3,2'den 13,5'e, öncü sürenin 34,6'dan 14,9 adıma inmesi ve yayın başına geri dönüş oranının %80'den %31'e düşmesine karşın üretimde çıkan hatanın 12'de sabit kalması, partiyi 1'e indirmenin dağıtım sıklığını 20,0'a çıkarıp öncü süreyi 69,7 adıma taşıması, kapının kusurun 8'ini tutup geri dönüşü %20'den %7'ye indirirken kurtarma süresini 45,4'ten 54,8 adıma çıkarması, otomatik geri almanın kurtarmayı 7,0 adıma indirip 48 masum değişikliği geri alması ve üç kararın birlikte öncü süreyi 109,3 adıma çıkarması.

Önceki ders dört ölçütü haritanın sonucu olarak okudu: harita değişti, ölçütler onu izledi. Ama
ölçütler bağımsız birer sonuç değildir; **bir küme** oluştururlar ve aynı karar hepsini birden
oynatır. Bu ders o kümeyi tek koşumdan okur.

Dört ölçüt şunlardır. **Dağıtım sıklığı:** birim zamanda üretime çıkan yayın sayısı. **Öncü süre:**
bir değişikliğin akışa girişinden üretimde kalıcı olarak yer almasına kadar geçen süre. **Geri
dönüş oranı:** üretimde hata çıkaran, yani başarısız değişikliğin payı. **Kurtarma süresi:** hatanın
üretime çıkışından servisin düzelmesine kadar geçen süre. M20/K05'te `teslim süresi` bir iş
kaleminin ekip akışında başlangıçtan bitişe geçirdiği süreydi; buradaki **öncü süre** değişikliğin
üretimde *kalıcı* yer almasını bekler — geri alınan değişiklikte sayaç durmaz.

#### Kümenin Kurulması

Örnek yine kurgu **bölgesel ölçüm ağı**dır; ağ da yayın düzeni de kurgudur. **KA19:** altmış
değişiklik dörder adım arayla akışa girer. **KA20:** her değişiklik için iki zar koşulsuz atılır —
kusurlu olup olmadığı (oran 0,20) ve kusurun kapıda yakalanıp yakalanmayacağı (oran 0,60); tohum
20260804'tür ve zar sırası koşumdan koşuma değişmez. **KA21:** değişiklikler bir partide toplanır;
parti dolunca ya da ilk kalem 30 adım bekleyince hazırlık başlar. Aynı anda tek yayın hazırlanır ve
hazırlık 4 artı parti büyüklüğü kadar adım tutar. **KA22:** kapı varsa hazırlığa 5 adım ekler ve
yayından önce çalışır; tuttuğu kusur partiden çıkarılır, 6 adımda düzeltilip kuyruğa geri girer.
**KA23:** yayında yakalanmamış kusur varsa üretimde hata olur; otomatik geri alma yokken sağlam
değişiklikler üretimde kalır, kusurlu olan 12 adım tespit ve 6 adım düzeltmeden sonra kuyruğa
döner ve kurtarma süresi düzeltme yayınlanana kadar sayılır. **KA24:** otomatik geri alma varsa
yayının tamamı 3 adım tespit ve 4 adım geri alma ile geri alınır; kurtarma süresi 7 adımdır ama
partideki bütün değişiklikler kuyruğa döner. **KA25:** düzeltilen değişiklik yeniden kusurlu olmaz.

Yayın düzeni ve kararlar süreç içi bir **modeldir**; gerçek bir yayın kaydı yoktur.

```js
// olcut/kume.mjs — dort teslimat olcutunun bagli kume olarak modeli: gercek bir yayin kaydi yok,
// adimlar veri yapisidir. Rastgelelik uretecle yazilir, tohum gorunur.

export const N = 60, VARIS = 4, LIMIT = 4000, TOHUM = 20260804;
export const KUSUR = 0.20, KAPI_YAKALAMA = 0.60;   // kusur orani ve kapinin yakalama orani
export const H0 = 4, H1 = 1, KAPI = 5;             // hazirlik = H0 + H1 * parti (+ kapi)
export const TESPIT = 12, DUZELT = 6;              // elle tespit ve duzeltme
export const TESPIT_OTO = 3, GERI = 4;             // otomatik tespit ve geri alma
export const MAKS_BEKLEME = 30;                    // yarim parti bu kadar bekleyince yayina cikar

export function uretec(tohum) {                    // dogrusal eslesmeli uretec
  let x = tohum >>> 0;
  return () => ((x = (x * 1664525 + 1013904223) >>> 0) / 2 ** 32);
}

export function kos({ parti = 8, kapi = false, otomatik = false } = {}) {
  const zar = uretec(TOHUM);
  const D = Array.from({ length: N }, (_, i) => ({ i, varis: i * VARIS, hazir: i * VARIS,
    durum: "yolda", kusur: zar() < KUSUR, yakalanir: zar() < KAPI_YAKALAMA,
    bitis: null, hataAt: null, kurtarma: null, geriAlindi: 0, kuyrukAt: 0 }));
  const S = { yayin: 0, bozukYayin: 0, kapidaYakalanan: 0, geriAlma: 0, uretimHatasi: 0,
    partiToplam: 0, geriKusurlu: 0, geriMasum: 0 };
  let aktif = null;

  const yayinBitir = (a, t) => {
    let grup = a.grup;
    if (kapi) {                                    // kapi kusurun bir bolumunu yayindan once tutar
      const tutulan = grup.filter((d) => d.kusur && d.yakalanir);
      S.kapidaYakalanan += tutulan.length;
      for (const d of tutulan) { d.durum = "yolda"; d.hazir = t + DUZELT; d.kusur = false; }
      grup = grup.filter((d) => !tutulan.includes(d));
    }
    S.yayin++; S.partiToplam += grup.length;
    const bozuk = grup.filter((d) => d.kusur);
    if (!bozuk.length) { for (const d of grup) { d.durum = "bitti"; d.bitis = t; } return; }
    S.bozukYayin++; S.uretimHatasi += bozuk.length;
    if (!otomatik) {                               // saglam degisiklik uretimde kalir
      for (const d of grup) {
        if (!d.kusur) { d.durum = "bitti"; d.bitis = t; continue; }
        d.hataAt = t; d.kusur = false; d.durum = "yolda"; d.hazir = t + TESPIT + DUZELT;
      }
      return;
    }
    S.geriAlma++;                                  // butun yayin geri alinir, masumlar da doner
    for (const d of grup) {
      const bu = d.kusur;
      if (bu) { d.hataAt = t; d.kusur = false; d.kurtarma = TESPIT_OTO + GERI; S.geriKusurlu++; }
      else S.geriMasum++;
      d.geriAlindi++; d.durum = "yolda";
      d.hazir = t + TESPIT_OTO + GERI + (bu ? DUZELT : 0);
    }
  };

  for (let t = 0; t <= LIMIT; t++) {
    for (const d of D) if (d.durum === "yolda" && d.hazir <= t) { d.durum = "kuyrukta"; d.kuyrukAt = t; }
    if (aktif && aktif.bitis === t) { yayinBitir(aktif, t); aktif = null; }
    if (aktif) continue;                           // ayni anda tek yayin hazirlanir
    const K = D.filter((d) => d.durum === "kuyrukta").sort((a, b) => a.kuyrukAt - b.kuyrukAt || a.i - b.i);
    if (!K.length) continue;
    if (K.length < parti && t - K[0].kuyrukAt < MAKS_BEKLEME) continue;
    const grup = K.slice(0, parti);
    for (const d of grup) d.durum = "yayinda";
    aktif = { grup, bitis: t + H0 + H1 * grup.length + (kapi ? KAPI : 0) };
  }
  for (const d of D) if (d.hataAt !== null && d.kurtarma === null && d.bitis !== null)
    d.kurtarma = d.bitis - d.hataAt;               // elle kurtarma: duzeltme yayinlanana kadar
  return { D, S };
}

export const ort = (a) => (a.length ? (a.reduce((s, v) => s + v, 0) / a.length).toFixed(1) : "-");

export function olc(ayar) {
  const { D, S } = kos(ayar);
  const pencere = Math.max(...D.map((d) => d.bitis ?? 0));
  const kurtarmalar = D.filter((d) => d.kurtarma !== null).map((d) => d.kurtarma);
  return { D, S, pencere,
    dagitimSikligi: (100 * S.yayin / pencere).toFixed(1), yayin: S.yayin,
    ortParti: (S.partiToplam / S.yayin).toFixed(1),
    onculSure: ort(D.map((d) => d.bitis - d.varis)),
    geriDonusYayin: (100 * S.bozukYayin / S.yayin).toFixed(0) + "%",
    geriDonusDegisiklik: (100 * S.uretimHatasi / N).toFixed(0) + "%",
    kurtarma: ort(kurtarmalar), uretimHatasi: S.uretimHatasi,
    kapidaYakalanan: S.kapidaYakalanan, geriAlinan: D.reduce((s, d) => s + d.geriAlindi, 0),
    geriKusurlu: S.geriKusurlu, geriMasum: S.geriMasum, geriAlma: S.geriAlma,
    bitmeyen: D.filter((d) => d.bitis === null).length };
}
```

```js
// olcut/olc.mjs — bir kararin dort olcutte olculen degisimi; tek olcutu iyilestirip otekini bozan.
import { N, TOHUM, KUSUR, olc, ort } from "./kume.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const K = {
  "taban (parti 8)": {}, "parti 8 -> 2": { parti: 2 }, "parti 8 -> 1": { parti: 1 },
  "kapi eklendi": { kapi: true }, "otomatik geri alma": { otomatik: true },
  "parti 2 + otomatik": { parti: 2, otomatik: true },
  "parti 2 + kapi + otomatik": { parti: 2, kapi: true, otomatik: true },
};
const R = Object.fromEntries(Object.entries(K).map(([ad, a]) => [ad, olc(a)]));
const T = R["taban (parti 8)"];

console.log(`${N} degisiklik, kusur orani ${KUSUR}, tohum ${TOHUM}; ` +
  `kusurlu ${T.D.filter((d) => d.hataAt !== null).length}, ` +
  `bitmeyen ${Object.values(R).reduce((s, r) => s + r.bitmeyen, 0)}`);

const A = [-27, 11, 11, 12, 13, 11];
console.log("\n1. dort olcut bagli bir kume olarak");
yaz(A, "kosum", "dagitim", "oncu sure", "geri donus", "geri donus", "kurtarma");
yaz(A, "", "(100 adim)", "(adim)", "(yayin)", "(degisiklik)", "(adim)");
for (const [ad, r] of Object.entries(R))
  yaz(A, ad, r.dagitimSikligi, r.onculSure, r.geriDonusYayin, r.geriDonusDegisiklik, r.kurtarma);

const B = [-27, 8, 12, 15, 16, 13];
console.log("\n2. ayni kosumlarda kararin mekanigi");
yaz(B, "kosum", "yayin", "ort. parti", "uretim hatasi", "kapida tutulan", "geri alinan");
for (const [ad, r] of Object.entries(R))
  yaz(B, ad, r.yayin, r.ortParti, r.uretimHatasi, r.kapidaYakalanan, r.geriAlinan);

const C = [-27, 11, 12, 18, 12];
console.log("\n3. tabana gore ham fark (yonu her olcutte ayri okunur)");
yaz(C, "karar", "dagitim", "oncu sure", "geri donus/yayin", "kurtarma");
const sap = (r, k) => {
  const d = +r[k].replace("%", "") - +T[k].replace("%", "");
  return (d > 0 ? "+" : "") + d.toFixed(1);
};
for (const ad of Object.keys(R).slice(1))
  yaz(C, ad, sap(R[ad], "dagitimSikligi"), sap(R[ad], "onculSure"),
    sap(R[ad], "geriDonusYayin") + " puan", sap(R[ad], "kurtarma"));

const E = [-27, 11, 16, 10, 8, 22];
console.log("\n4. geri alinan yayinda masum degisiklik");
yaz(E, "kosum", "geri alma", "degisiklik-kez", "kusurlu", "masum", "masumun oncu suresi");
for (const ad of ["otomatik geri alma", "parti 2 + otomatik", "parti 2 + kapi + otomatik"]) {
  const r = R[ad], g = r.D.filter((d) => d.geriAlindi > 0 && d.hataAt === null);
  yaz(E, ad, r.geriAlma, r.geriAlinan, r.geriKusurlu, r.geriMasum,
    `${ort(g.map((d) => d.bitis - d.varis))} (taban ${T.onculSure})`);
}
```

```
60 degisiklik, kusur orani 0.2, tohum 20260804; kusurlu 12, bitmeyen 0

1. dort olcut bagli bir kume olarak
kosum                          dagitim  oncu sure  geri donus   geri donus   kurtarma
                            (100 adim)     (adim)     (yayin) (degisiklik)     (adim)
taban (parti 8)                    3.2       34.6         80%          20%       45.4
parti 8 -> 2                      13.5       14.9         31%          20%       26.3
parti 8 -> 1                      20.0       69.7         17%          20%       65.8
kapi eklendi                       3.1       36.8         40%           7%       54.8
otomatik geri alma                 5.1       50.6         50%          20%        7.0
parti 2 + otomatik                15.4       24.1         27%          20%        7.0
parti 2 + kapi + otomatik          9.0      109.3         11%           7%        7.0

2. ayni kosumlarda kararin mekanigi
kosum                         yayin  ort. parti  uretim hatasi  kapida tutulan  geri alinan
taban (parti 8)                  10         7.2             12               0            0
parti 8 -> 2                     36         2.0             12               0            0
parti 8 -> 1                     72         1.0             12               0            0
kapi eklendi                     10         6.4              4               8            0
otomatik geri alma               16         7.5             12               0           60
parti 2 + otomatik               41         2.0             12               0           22
parti 2 + kapi + otomatik        38         1.8              4               8            8

3. tabana gore ham fark (yonu her olcutte ayri okunur)
karar                          dagitim   oncu sure  geri donus/yayin    kurtarma
parti 8 -> 2                     +10.3       -19.7        -49.0 puan       -19.1
parti 8 -> 1                     +16.8       +35.1        -63.0 puan       +20.4
kapi eklendi                      -0.1        +2.2        -40.0 puan        +9.4
otomatik geri alma                +1.9       +16.0        -30.0 puan       -38.4
parti 2 + otomatik               +12.2       -10.5        -53.0 puan       -38.4
parti 2 + kapi + otomatik         +5.8       +74.7        -69.0 puan       -38.4

4. geri alinan yayinda masum degisiklik
kosum                        geri alma  degisiklik-kez   kusurlu   masum   masumun oncu suresi
otomatik geri alma                   8              60        12      48     64.5 (taban 34.6)
parti 2 + otomatik                  11              22        12      10     35.8 (taban 34.6)
parti 2 + kapi + otomatik            4               8         4       4    163.3 (taban 34.6)
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır.

#### Parti Küçültme: Oynayan Ölçüt, Oynamayan Alan

Tabanda parti sekizdir: on yayın, ortalama 7,2 değişiklik, dağıtım sıklığı 3,2, öncü süre 34,6
adım, kurtarma 45,4 adım. Yayın başına geri dönüş oranı **%80**'dir — on yayının sekizi içinde
kusur taşır.

Parti ikiye indirilince dört ölçüt de tabana göre iyileşir: dağıtım sıklığı 13,5'e, öncü süre 14,9
adıma, kurtarma 26,3 adıma, yayın başına geri dönüş oranı %31'e gider. İkinci tablo bu tablonun
altını çizer: **üretimde çıkan hata sayısı 12'de kalır.** Değişiklik başına geri dönüş oranı da
%20'dir; tabanla aynı. Yayın başına oranın %80'den %31'e inmesi bir kalite kazanımı değil, aynı on
iki hatanın daha çok yayına bölünmesidir. **Bir ölçüt kırk dokuz puan iyileşirken alanda hiçbir şey
değişmemiştir.**

Partiyi bire indirmek bu sınırı gösterir. Dağıtım sıklığı 20,0'a, yayın sayısı 72'ye çıkar ve yayın
başına geri dönüş %17'ye iner — üç ölçütün en iyi değerleri. Ama öncü süre 34,6'dan **69,7 adıma**
ve kurtarma süresi 45,4'ten 65,8 adıma çıkar. Nedeni hazırlığın sabit payıdır: yayın başına 4 adım
sabit maliyet, parti birde değişiklik başına 5 adıma çıkar ve geliş aralığı 4 adımdır. Akış doyar.
**Parti küçültmenin kazancı sabit yayın maliyetinin bittiği yerde biter.**

#### Kapı Eklemek

Kapı, üretimde çıkan hatayı gerçekten azaltan tek karardır: on iki kusurun sekizi yayından önce
tutulur, dördü geçer ve değişiklik başına geri dönüş oranı %20'den **%7'ye** iner. Bu, ölçüt
tanımından gelmeyen tek iyileşmedir.

Faturası ötekilerdedir. Her yayına 5 adım eklendiği için öncü süre 34,6'dan 36,8 adıma, dağıtım
sıklığı 3,2'den 3,1'e gider. Kurtarma süresi de bozulur: 45,4'ten **54,8 adıma**. Kapıdan geçen dört
kusurun düzeltmesi de aynı kapıdan geçmek zorundadır. **Yayına konan her kapı, düzeltmenin de
kapısıdır.**

#### Otomatik Geri Alma ve Masum Değişiklik

Otomatik geri alma kurtarma süresini 45,4 adımdan **7,0 adıma** indirir — dört ölçütteki en büyük
tek kazanç (−38,4). Bedeli dördüncü tablodadır: sekiz geri alma olayında altmış değişiklik-kez geri
alınır ve bunun **kırk sekizi masumdur**. Masum değişikliklerin öncü süresi 64,5 adımdır; taban
34,6'dır. Toplam öncü süre 34,6'dan 50,6 adıma çıkar.

Bedel parti büyüklüğüne bağlıdır. Parti ikiye indirilip otomatik geri alma açıldığında geri alınan
kırk sekiz masum değişiklik ona iner, masumların öncü süresi 35,8 adıma çekilir ve küme dengelenir:
dağıtım 15,4, öncü süre 24,1, kurtarma 7,0. **Geri alma biriminin büyüklüğü, geri almanın
maliyetidir.**

Üç kararı birden uygulamak bunu bozar. Parti iki, kapı ve otomatik geri alma birlikte, yayın başına
geri dönüşü %11'e ve kurtarmayı 7,0 adıma indirir, ama öncü süreyi **109,3 adıma** çıkarır: iki
değişiklik için 4 artı 2 artı 5, yani 11 adım hazırlık, değişiklik başına 5,5 adım eder ve geliş
aralığı 4 adımdır. **Üç ayrı ölçütü iyileştiren üç kararın toplamı, kümenin en kötü öncü süresini
verir.**

#### Farkın Saklandığı Yer

Bu derste fark **ölçütün tanımında** saklıdır ve sayısı şudur: aynı yedi koşumda geri dönüş oranı
yayın başına %11 ile %80 arasında oynar, değişiklik başına yalnız iki değer alır (%20 ve %7) ve
üretimde çıkan hata yedi koşumun beşinde 12'dir. Bildirilmiş kısım oranın kendisidir; bildirilmemiş
kısım paydadır. Yedi koşum ve dört ölçüt yirmi sekiz ölçüm verir: altı kararın dördünde en az bir
ölçüt bozulur, ikisinde (parti 2 ve parti 2 artı otomatik) dördü birden iyileşir — ve o ikisinde de
alandaki hata sayısı 12'de sabit kalır.

Sinyalin kime kaç adımda ulaştığı da bu kararlarla değişir: kusur otomatik geri almada 3 adımda
tespit edilir ve 7 adımda kapanır, elle 12 adımda tespit edilir ve düzeltme yayınlanana kadar
ortalama 45,4 adım sürer. M21/K05'in kalite göstergeleri bir değişikliğin içeriğini ölçüyordu;
buradaki dört ölçüt teslimatın kendisini ölçer ve ikisi ancak kusur oranı üzerinden bağlanır.

#### Özet

- Dört ölçüt tek koşumdan okunur ve bağlıdır: yedi koşumun hiçbirinde bir karar tek başına kalmaz.
- Parti 8'den 2'ye inince dağıtım sıklığı 3,2 → 13,5, öncü süre 34,6 → 14,9, kurtarma 45,4 → 26,3
  adım ve yayın başına geri dönüş %80 → %31 olur; üretimde çıkan hata 12'de kalır ve değişiklik
  başına oran %20'de sabittir.
- Partiyi 1'e indirmek dağıtım sıklığını 20,0'a çıkarır ama sabit yayın maliyeti akışı doyurur:
  öncü süre 69,7, kurtarma 65,8 adım.
- Kapı üretimdeki hatayı 12'den 4'e indiren tek karardır (geri dönüş %20 → %7) ve karşılığında öncü
  süreyi 36,8, kurtarma süresini 54,8 adıma çıkarır — düzeltme de aynı kapıdan geçer.
- Otomatik geri alma kurtarmayı 7,0 adıma indirir; parti 8'de 48 masum değişikliği geri alır ve
  onların öncü süresini 64,5 adıma taşır, parti 2'de aynı sayı 10'a ve 35,8 adıma iner.
- Üç kararın toplamı (parti 2, kapı, otomatik geri alma) yayın başına geri dönüşü %11'e indirirken
  öncü süreyi 109,3 adıma çıkarır.

#### Sonraki Adım

Kararların hepsi bir eşiğe göre verildi ama eşiğin kendisi hiç yazılmadı: ne kadar hata kabul
edilebilir, kabul edilemez olduğunda ne durur. Sonraki ders bu eşiği bir sayıya bağlar — hedef
erişilebilirlik verildiğinde dönemde kalan **hata bütçesi** dakikası, her olayın bütçeden
düşürdüğü ve bütçe tükendiğinde dağıtım sıklığına konan kısıt ölçülür; bütçe kuralının bu dört
ölçütte ölçülen etkisi sayılır.

### Site Güvenilirliği Mühendisliği

Source: https://academia.sh/tr/kurslar/devops-temelleri/site-guvenilirligi-muhendisligi

Hata bütçesinin bir sayıya bağlanması: 30 günlük dönemde %99,9 hedefin 43,2 dakika bütçe bırakması ve tek bir ağır olayın bunun %208'ini götürmesi, bütçe kuralı olmadan 12 dönemde 630 dakika kesinti ve %99,878 erişilebilirlik ölçülürken kural açıldığında 12 dönemin 8'inde bütçenin tükenip 166 gün dondurmaya karşılık kesintinin yalnız 620 dakikaya inmesi ama öncü sürenin 3,0 günden 12,6 güne çıkması, hedef %99,95'e çekildiğinde 236 donuk gün ve 60 çıkmayan değişiklikle öncü sürenin 49,9 güne taşınması, kesinti süresi yarıya inince kuralın 4 dönemde tükenip erişilebilirliğin %99,939'a çıkması ve öncü sürenin 5,4 günde kalması.

Önceki ders üç kararın dört ölçütte ölçülen bedelini saydı, ama her karar örtük bir eşiğe göre
verildi: ne kadar hata kabul edilebilir, kabul edilemez olduğunda ne durur. O eşik hiçbir yerde
yazılı değildi.

**Site güvenilirliği mühendisliği**, işletme sorumluluğunu bir mühendislik problemi olarak ele alan
ve güvenilirlik hedefini önce bir sayıya bağlayan disiplindir. DevOps ile örtüştüğü alan sorumluluk
paylaşımıdır — iki yaklaşım da yazan ile işletenin aynı sonuçtan sorumlu olmasını ister. Ayrıştığı
yer ölçüttür: hedef önce yazılır, sonra o hedeften bir **hata bütçesi** türetilir ve teslimat
kararları o bütçeye bağlanır. Bu ders bütçeyi bir dakika sayısına bağlar ve kuralın dört ölçütte
ölçülen etkisini sayar. Kurtarma mekaniği M19/K05'te ölçüldü; burada kurtarma süresi bir **girdi**
olarak alınır.

#### Bütçenin Kurulması

Örnek yine kurgu **bölgesel ölçüm ağı**dır; ağ da dönemler de kurgudur. **KA26:** dönem 30 gün,
yani 43200 dakikadır ve on iki dönem koşulur. **KA27:** her dönemde yirmi değişiklik eşit
aralıklarla akışa girer; parti dörttür ve hazırlık bir gün tutar. **KA28:** her değişiklik için iki
zar koşulsuz atılır — kusurlu olup olmadığı (oran 0,10) ve olay sınıfı (hafif 10 dakika, pay 0,60;
orta 30 dakika, pay 0,30; ağır 90 dakika, pay 0,10); tohum 20260805'tir. **KA29:** kusurlu bir
değişiklik yayına çıkarsa üretimde bir olay olur ve olayın kesinti dakikası dönemin bütçesinden
düşer. Bütçe dönem başında hedef erişilebilirlikten türetilir: dönem dakikası çarpı bir eksi hedef.
**KA30:** bütçe kuralı açıksa kalan bütçe sıfırın altına düştüğü anda dönem sonuna kadar yeni yayın
çıkmaz; kuyruktaki değişiklikler bekler ve bütçe yalnız yeni dönemde yenilenir. **KA31:** öncü süre
değişikliğin akışa girişinden yayınlanmasına kadar geçen gündür, kurtarma süresi olayın kesinti
dakikasıdır, erişilebilirlik bir eksi toplam kesintinin toplam döneme oranıdır.

Dönemler, olaylar ve bütçe kuralı süreç içi bir **modeldir**; gerçek bir kesinti kaydı yoktur.

```js
// butce/donem.mjs — hata butcesinin donem modeli: gercek bir kesinti kaydi yok, gunler ve
// dakikalar veri yapisidir. Rastgelelik uretecle yazilir, tohum gorunur.

export const DONEM_GUN = 30, DONEM = 12, GUN_DK = 1440, DEG = 20, PARTI = 4, HAZIRLIK = 1;
export const KUSUR = 0.10, TOHUM = 20260805;
// olay sinifi: kesinti dakikasi ve payi
export const SINIF = [["hafif", 10, 0.60], ["orta", 30, 0.30], ["agir", 90, 0.10]];

export function uretec(tohum) {                    // dogrusal eslesmeli uretec
  let x = tohum >>> 0;
  return () => ((x = (x * 1664525 + 1013904223) >>> 0) / 2 ** 32);
}

export const butceDk = (hedef) => DONEM_GUN * GUN_DK * (1 - hedef);

export function kos({ hedef = 0.999, kural = true, kesintiCarpani = 1 } = {}) {
  const zar = uretec(TOHUM), butce = butceDk(hedef);
  const D = Array.from({ length: DONEM * DEG }, (_, i) => {
    const d = Math.floor(i / DEG), k = i % DEG;
    const kusur = zar() < KUSUR, p = zar();
    let esik = 0, dk = 0;
    for (const [, sure, pay] of SINIF) { esik += pay; if (dk === 0 && p < esik) dk = sure; }
    return { i, varis: d * DONEM_GUN + Math.floor(k * DONEM_GUN / DEG), kusur,
      kesinti: dk * kesintiCarpani, durum: "yolda", yayinGun: null };
  });
  const S = { yayin: 0, bozukYayin: 0, kesinti: 0, olay: 0, donukGun: 0, tukenen: 0,
    kalanlar: [], kesintiler: [], donemYayin: Array(DONEM).fill(0) };
  let aktif = null, kalan = butce, donem = -1, donuk = false;

  for (let t = 0; t < DONEM * DONEM_GUN; t++) {
    const d = Math.floor(t / DONEM_GUN);
    if (d !== donem) {                             // donem basinda butce yenilenir
      if (donem >= 0) S.kalanlar.push(kalan);
      donem = d; kalan = butce; donuk = false;
    }
    for (const x of D) if (x.durum === "yolda" && x.varis <= t) x.durum = "kuyrukta";
    if (aktif && aktif.bitis === t) {              // yayin uretime cikar
      S.yayin++; S.donemYayin[d]++;
      const bozuk = aktif.grup.filter((x) => x.kusur);
      if (bozuk.length) {
        S.bozukYayin++;
        for (const x of bozuk) {
          S.olay++; S.kesinti += x.kesinti; S.kesintiler.push(x.kesinti);
          kalan -= x.kesinti;
        }
        if (kural && kalan < 0 && !donuk) { donuk = true; S.tukenen++; }
      }
      for (const x of aktif.grup) { x.durum = "bitti"; x.yayinGun = t; }
      aktif = null;
    }
    if (donuk) { S.donukGun++; continue; }         // butce bitti: yeni yayin cikmaz
    if (aktif) continue;
    const K = D.filter((x) => x.durum === "kuyrukta");
    if (K.length < PARTI) continue;
    const grup = K.slice(0, PARTI);
    for (const x of grup) x.durum = "yayinda";
    aktif = { grup, bitis: t + HAZIRLIK };
  }
  S.kalanlar.push(kalan);
  return { D, S, butce };
}

export const ort = (a) => (a.length ? (a.reduce((s, v) => s + v, 0) / a.length).toFixed(1) : "-");

export function olc(ayar) {
  const { D, S, butce } = kos(ayar);
  const cikan = D.filter((x) => x.yayinGun !== null);
  const toplamDk = DONEM * DONEM_GUN * GUN_DK;
  return { D, S, butce,
    dagitimSikligi: (S.yayin / DONEM).toFixed(1),
    onculSure: ort(cikan.map((x) => x.yayinGun - x.varis)),
    geriDonusOrani: (100 * S.bozukYayin / S.yayin).toFixed(0) + "%",
    kurtarma: ort(S.kesintiler),
    erisilebilirlik: (100 * (1 - S.kesinti / toplamDk)).toFixed(3) + "%",
    kesinti: S.kesinti, olay: S.olay, yayin: S.yayin,
    tukenen: S.tukenen, donukGun: S.donukGun,
    kalanOrt: ort(S.kalanlar), cikmayan: D.length - cikan.length };
}
```

```js
// butce/olc.mjs — hata butcesi bir sayiya baglanir; butce kuralinin dort olcutte etkisi.
import { DONEM, DONEM_GUN, GUN_DK, SINIF, TOHUM, KUSUR, butceDk, olc } from "./donem.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));

console.log(`${DONEM} donem x ${DONEM_GUN} gun = ${DONEM * DONEM_GUN * GUN_DK} dakika; ` +
  `kusur orani ${KUSUR}, tohum ${TOHUM}`);

const H = [0.995, 0.999, 0.9995];
const A = [-14, 16, 14, 12, 12];
console.log("\n1. hedef erisilebilirlik donemde kac dakika butce birakir");
yaz(A, "hedef", "butce (dakika)", "hafif olay", "orta olay", "agir olay");
for (const h of H) {
  const b = butceDk(h);
  yaz(A, (100 * h).toFixed(2) + "%", b.toFixed(1),
    ...SINIF.map(([, dk]) => `${(100 * dk / b).toFixed(0)}%`));
}
console.log("  (son uc sutun: tek bir olayin butceden dusurdugu pay)");
console.log("  olay siniflari: " +
  SINIF.map(([ad, dk, p]) => `${ad} ${dk} dk (pay ${p})`).join(", "));

const K = {
  "%99,9 kural yok": { hedef: 0.999, kural: false },
  "%99,9 kural var": { hedef: 0.999, kural: true },
  "%99,5 kural var": { hedef: 0.995, kural: true },
  "%99,95 kural var": { hedef: 0.9995, kural: true },
  "%99,9 kesinti yariya": { hedef: 0.999, kural: true, kesintiCarpani: 0.5 },
};
const R = Object.fromEntries(Object.entries(K).map(([ad, a]) => [ad, olc(a)]));

const B = [-22, 12, 12, 12, 12];
console.log("\n2. butce kuralinin dort teslimat olcutunde olculen etkisi");
yaz(B, "kosum", "dagitim", "oncu sure", "geri donus", "kurtarma");
yaz(B, "", "(donem/yayin)", "(gun)", "(yayin)", "(dakika)");
for (const [ad, r] of Object.entries(R))
  yaz(B, ad, r.dagitimSikligi, r.onculSure, r.geriDonusOrani, r.kurtarma);

const C = [-22, 10, 8, 17, 16, 12];
console.log("\n3. ayni kosumlarda butcenin durumu");
yaz(C, "kosum", "kesinti", "olay", "erisilebilirlik", "tukenen donem", "donuk gun");
for (const [ad, r] of Object.entries(R))
  yaz(C, ad, r.kesinti, r.olay, r.erisilebilirlik, `${r.tukenen}/${DONEM}`, r.donukGun);

const E = [-22, 8, 18, 21, 13];
console.log("\n4. yayin ve kuyruk");
yaz(E, "kosum", "yayin", "ort. kalan butce", "cikmayan degisiklik", "hedef tuttu");
for (const [ad, r] of Object.entries(R)) {
  const h = K[ad].hedef;
  yaz(E, ad, r.yayin, r.kalanOrt, r.cikmayan,
    +r.erisilebilirlik.replace("%", "") >= 100 * h ? "evet" : "hayir");
}
```

```
12 donem x 30 gun = 518400 dakika; kusur orani 0.1, tohum 20260805

1. hedef erisilebilirlik donemde kac dakika butce birakir
hedef           butce (dakika)    hafif olay   orta olay   agir olay
99.50%                   216.0            5%         14%         42%
99.90%                    43.2           23%         69%        208%
99.95%                    21.6           46%        139%        417%
  (son uc sutun: tek bir olayin butceden dusurdugu pay)
  olay siniflari: hafif 10 dk (pay 0.6), orta 30 dk (pay 0.3), agir 90 dk (pay 0.1)

2. butce kuralinin dort teslimat olcutunde olculen etkisi
kosum                      dagitim   oncu sure  geri donus    kurtarma
                      (donem/yayin)       (gun)     (yayin)    (dakika)
%99,9 kural yok                5.0         3.0         35%        23.3
%99,9 kural var                4.8        12.6         34%        23.8
%99,5 kural var                5.0         3.0         35%        23.3
%99,95 kural var               3.8        49.9         29%        27.5
%99,9 kesinti yariya           5.0         5.4         35%        11.7

3. ayni kosumlarda butcenin durumu
kosum                    kesinti    olay  erisilebilirlik   tukenen donem   donuk gun
%99,9 kural yok              630      27          99.878%            0/12           0
%99,9 kural var              620      26          99.880%            8/12         166
%99,5 kural var              630      27          99.878%            0/12           0
%99,95 kural var             440      16          99.915%            9/12         236
%99,9 kesinti yariya         315      27          99.939%            4/12          65

4. yayin ve kuyruk
kosum                    yayin  ort. kalan butce  cikmayan degisiklik  hedef tuttu
%99,9 kural yok             60              -9.3                    0        hayir
%99,9 kural var             58              -8.5                    8        hayir
%99,5 kural var             60             163.5                    0         evet
%99,95 kural var            45             -15.1                   60        hayir
%99,9 kesinti yariya        60              17.0                    0         evet
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır.

#### Bir Olay Bütçenin Ne Kadarını Götürür

Birinci tablo hedefi doğrudan dakikaya çevirir. Otuz günlük dönemde %99,5 hedef 216,0 dakika, %99,9
hedef 43,2 dakika, %99,95 hedef 21,6 dakika bırakır. Sağdaki üç sütun tek bir olayın bu bütçeden
düşürdüğü paydır ve karar burada başlar: %99,5 hedefte ağır bir olay bütçenin %42'sini götürür,
%99,9 hedefte **%208'ini**, %99,95 hedefte %417'sini. **Bir hedef, dönemde kaç ağır olaya
dayanabildiğiyle okunur:** %99,5 hedef ikiye dayanır, %99,9 hedef birine bile dayanmaz.

Aynı ilişki ters yönden de geçerlidir. Ölçülen ortalama kesinti 23,3 dakikadır; %99,9 bütçesi 43,2
dakikadır. Yani bütçe **iki olaydan sonra biter** ve dönemde ortalama 2,3 olay çıkmaktadır. Hata
bütçesi, kurtarma süresinin dönem toplamı için konmuş bir tavandır.

#### Kural Neyi Durdurur

İkinci ve üçüncü tablolar aynı olay dizisini kural kapalı ve açıkken karşılaştırır. Kural
kapalıyken on iki dönemde 27 olay, 630 dakika kesinti ve %99,878 erişilebilirlik ölçülür — hedefin
altı. Kural açıldığında bütçe on iki dönemin sekizinde tükenir ve **166 gün** dondurma uygulanır.
Karşılığı şudur: kesinti 630'dan 620 dakikaya, olay 27'den 26'ya iner ve erişilebilirlik %99,878'den
**%99,880**'e çıkar. Hedef yine tutmaz.

Neden bu kadar az? Dördüncü tablo söyler: yayın sayısı 60'tan yalnız 58'e iner. Dondurma değişikliği
yok etmez, **erteler**; donmuş dönem bitince kuyruk boşalır ve aynı kusurlar aynı sırayla üretime
çıkar. Bedel öncü süredir: 3,0 günden **12,6 güne** çıkar, dağıtım sıklığı 5,0'dan 4,8'e iner ve
sekiz değişiklik on iki dönem içinde hiç çıkamaz. **Bütçe kuralı bir önleme aracı değil, bir
durdurma aracıdır; olaydan önce değil, olaydan sonra çalışır.**

Zamanlama da bunu doğrular. Bütçe ortalama olarak iki olaydan sonra tükenir; o ana kadar dönemin
beş yayınının çoğu çıkmıştır. Dondurmanın engellediği yayınlar dönemin son günlerine ait olanlardır
ve onlar da bir sonraki dönemin ilk günlerinde çıkar. On iki dönemin toplamında engellenen yayın
sayısı ikidir — 166 gün dondurmaya karşılık. Geri dönüş oranının %35'ten %34'e inmesi de aynı
nedenledir: kural yayının **içeriğine** dokunmaz, yalnız **zamanına** dokunur. Aynı şey kurtarma
süresi için de geçerlidir; 23,3 dakikadan 23,8 dakikaya çıkması, ertelenen yayınların sınıf
dağılımının biraz kaymasından başka bir şey değildir.

#### Hedefin Sıkılığı ve Bütçenin Kaynağı

%99,5 hedefte kural hiç çalışmaz: bütçe on iki dönemin hiçbirinde tükenmez, dönem sonu ortalama
kalan 163,5 dakikadır ve ölçülen bütün sayılar kural yokmuş gibidir. **Gevşek hedefe bağlanan kural
ölçülemez;** yazılı olması davranışı değiştirmez.

%99,95 hedefte tersi olur. Bütçe on iki dönemin dokuzunda tükenir, 236 gün donar, yayın 60'tan 45'e
iner ve **altmış değişiklik hiç çıkamaz**. Öncü süre 3,0 günden 49,9 güne fırlar. Kesinti 630'dan
440 dakikaya iner ve erişilebilirlik %99,915 olur — yine hedefin altı. Sıkı hedef akışı durdurur ve
yine de hedefi tutturmaz.

Beşinci koşum bütçenin gerçek kaynağını gösterir. Hedef %99,9'da bırakılıp kesinti süresi yarıya
indirildiğinde bütçe yalnız dört dönemde tükenir, dondurma 65 güne iner, yayın 60'ta ve öncü süre
5,4 günde kalır; erişilebilirlik **%99,939**'a çıkar ve hedef tutar. Kurtarma süresi 23,3 dakikadan
11,7 dakikaya inmiştir. **Bütçeyi dondurma değil, kurtarma süresi belirler.**

#### Farkın Saklandığı Yer

Bu derste fark **hedef ile kesinti dağılımı arasında** saklıdır ve sayısı şudur: aynı kural üç
hedefte üç ayrı bütçe tüketimi verir — 216,0 dakikada 27 olayla hiç tükenmeyen, 43,2 dakikada 26
olayla sekiz dönemde tükenen, 21,6 dakikada 16 olayla dokuz dönemde tükenen. Bildirilmiş kısım
hedefin kendisidir; bildirilmemiş kısım olay sınıflarının dağılımıdır. Ağır olayın payı yalnız
0,10'dur ama toplam 630 dakikanın büyük bölümünü o taşır ve bütçeyi tüketen odur.

Sinyalin kime kaç adımda ulaştığı da bu kuralla değişir. Bütçe kuralı yokken kalan bütçe hiç
okunmaz; kuralla birlikte her olay aynı gün bütçeden düşer ve tükenme anı yayın kararını **aynı
gün** durdurur. Dört ölçütte ölçülen etki de bir arada okunur: kural açıldığında dağıtım sıklığı
5,0'dan 4,8'e, öncü süre 3,0'dan 12,6 güne gider; geri dönüş oranı %35'ten %34'e, kurtarma süresi
23,3'ten 23,8 dakikaya — yani ikisi neredeyse hiç oynamaz.

#### Özet

- Hata bütçesi hedeften türetilir: 30 günlük dönemde %99,5 hedef 216,0, %99,9 hedef 43,2, %99,95
  hedef 21,6 dakika bırakır; tek bir ağır olay (90 dakika) bunların sırasıyla %42'sini, %208'ini ve
  %417'sini götürür.
- Kural kapalıyken 12 dönemde 27 olay, 630 dakika kesinti ve %99,878 erişilebilirlik ölçülür.
- Kural açıldığında bütçe 8 dönemde tükenir ve 166 gün dondurulur, ama yayın 60'tan 58'e indiği için
  kesinti yalnız 620 dakikaya iner; bedel öncü süredir (3,0 → 12,6 gün) ve 8 değişiklik hiç çıkamaz.
- Hedef %99,5'e gevşetilirse kural hiç çalışmaz (0/12 tükenme, ortalama kalan 163,5 dakika);
  %99,95'e sıkılırsa 9/12 dönem tükenir, 236 gün donar, 60 değişiklik çıkamaz ve öncü süre 49,9
  güne çıkar — hedef yine tutmaz.
- Kesinti süresi yarıya inince bütçe yalnız 4 dönemde tükenir, öncü süre 5,4 günde kalır ve
  erişilebilirlik %99,939 ile hedefi tutar: bütçeyi kurtarma süresi belirler.

#### Sonraki Adım

Bütçe kuralı olayı olduktan sonra gördü ve ondan sonra durdurdu; ölçülen etkinin küçük olmasının
nedeni buydu. Sinyalin ne kadar geç geldiği her derste bir yerde çıktı ama hiç doğrudan sayılmadı.
Sonraki ders döngünün kendisini ele alır: kaç ayrı geri bildirim döngüsü var, her birinin uzunluğu
ne, hangi hata sınıfını kapsıyor ve bir hata sınıfını daha erken bir döngüye taşımanın maliyeti ile
kaçırdığı nedir.

### Geri Bildirim Döngüleri

Source: https://academia.sh/tr/kurslar/devops-temelleri/geri-bildirim-donguleri

Dört geri bildirim döngüsünün uzunluğu ve kapsadığı hata sınıfı: 2, 30, 240 ve 4320 dakikalık kümülatif uzunluklarda 120 hatanın 42'sinin yazarken, 21'inin tümleştirmede, 25'inin hazırlıkta yakalanması ve 32'sinin hiçbirine düşmeyip üretime kaçması, sınıf başına ortalama gecikmenin 2,0 dakikadan 3810,0 dakikaya kadar açılması, veri biçimi sınıfını tümleştirme döngüsüne taşımanın 12 dakika ekleyip toplam gecikmeyi 144954'ten 128520 dakikaya indirmesine karşılık sınıfın 12 hatasının yalnız 5'ini erken yakalaması, zamanlama sınıfını taşımanın 20 dakikaya 10 hatadan 1'ini kazandırması ve üç taşımanın birlikte geri dönüş oranını %53'ten %42'ye indirirken öncü süreyi 351,9'dan 420,2 dakikaya çıkarması.

Önceki ders bütçe kuralının olayı olduktan sonra gördüğünü ve ölçülen etkinin bu yüzden küçük
kaldığını saydı. Sinyalin ne kadar geç geldiği bu konunun her dersinde bir yerde çıktı: gözlem alanı
bölünmüşken 7,0 adım, sınırda düşen bağlamda 61,0 adım, üretim doğrulamasında bulunan sapmada altı
adım geriye dönüş. Ama gecikmenin kaynağı — **döngünün kendisi** — hiç doğrudan sayılmadı.

**Geri bildirim döngüsü**, bir hatanın doğduğu andan onu düzeltebilecek role ulaştığı ana kadar
geçen yoldur. Bir akışta tek bir döngü yoktur; birkaç tane vardır, her birinin ayrı bir uzunluğu ve
ayrı bir **kapsamı** vardır. Hata bulma gecikmesi M20/K05'te ve M21/K05'te ölçüldü; burada ölçülen
o gecikme değil, döngünün kendisidir: kaç tane var, her biri ne kadar sürüyor, hangi hata sınıfını
kapsıyor ve bir sınıfı daha erken bir döngüye taşımanın bedeli ne.

#### Döngülerin Kurulması

Örnek yine kurgu **bölgesel ölçüm ağı**dır; ağ da döngüler de kurgudur. **KA32:** dört döngü
vardır — yazarken, tümleştirmede, hazırlıkta, üretimde; her birinin bir uzunluğu vardır ve
uzunluklar kümülatiftir, çünkü sinyal yazan role ancak zincirin o halkasında döner. **KA33:** sekiz
hata sınıfı vardır ve dönemde 120 hata doğar; sınıf başına sayılar sabittir. **KA34:** her döngünün
kapsadığı sınıflar ve o sınıf için bir yakalama oranı vardır; üretim döngüsü her sınıfı yakalar,
çünkü orada hatayı kullanan bulur. **KA35:** üreteç yazılır, tohum 20260806'dır; her hata için
döngü başına bir zar önceden atılır, böylece taşıma koşumlarında hatanın şansı değişmez. **KA36:**
120 hata 60 değişikliğe sırayla dağıtılır; bir değişikliğin öncü süresi hazırlık kümülatifi artı
üretimden önce yakalanan her hatasının döngü kümülatifidir. **KA37:** bir hata sınıfını daha erken
bir döngüye taşımak o döngüye bir denetim ekler: döngünün uzunluğu artar, sonraki döngülerin
kümülatifi de kayar ve sınıf o döngüde daha düşük bir oranla yakalanır.

Döngüler, sınıflar ve taşıma süreç içi bir **modeldir**; gerçek bir hat ya da hata kaydı yoktur.

```js
// dongu/dongu.mjs — geri bildirim dongulerinin modeli: gercek bir hat ya da hata kaydi yok,
// dakikalar veri yapisidir. Rastgelelik uretecle yazilir, tohum gorunur.

export const N_DEG = 60, TOHUM = 20260806;
export const DONGU = [["yazarken", 2], ["tumlestirmede", 28], ["hazirlikta", 210],
  ["uretimde", 4080]];                             // ad ve kendinden onceki dongudeki artis

// hata sinifi: donemde kac tane dogar
export const SINIF = { sozdizimi: 24, tip: 18, "birim-mantigi": 22, tumlesim: 14,
  "veri-bicimi": 12, yapilandirma: 12, zamanlama: 10, kaynak: 8 };

// kapsam: dongu -> sinif -> yakalama orani. Uretim dongusu her sinifi yakalar.
export const KAPSAM = {
  yazarken: { sozdizimi: 1.00, tip: 0.90, "birim-mantigi": 0.20 },
  tumlestirmede: { tip: 1.00, "birim-mantigi": 0.85, tumlesim: 0.35 },
  hazirlikta: { "birim-mantigi": 0.60, tumlesim: 0.85, "veri-bicimi": 0.55,
    yapilandirma: 0.35, zamanlama: 0.20, kaynak: 0.15 },
  uretimde: Object.fromEntries(Object.keys(SINIF).map((s) => [s, 1.00])),
};

export function uretec(tohum) {                    // dogrusal eslesmeli uretec
  let x = tohum >>> 0;
  return () => ((x = (x * 1664525 + 1013904223) >>> 0) / 2 ** 32);
}

// tasima: bir hata sinifini daha erken bir donguye tasir; o dongunun uzunlugu ek kadar buyur.
export function kos(tasima = []) {
  const artis = DONGU.map(([, a]) => a);
  const kapsam = Object.fromEntries(DONGU.map(([ad]) => [ad, { ...KAPSAM[ad] }]));
  for (const { sinif, dongu, oran, ek } of tasima) {
    kapsam[dongu][sinif] = oran;
    artis[DONGU.findIndex(([ad]) => ad === dongu)] += ek;
  }
  const kum = artis.map((_, i) => artis.slice(0, i + 1).reduce((s, v) => s + v, 0));
  const zar = uretec(TOHUM);
  const H = Object.entries(SINIF).flatMap(([sinif, n]) =>
    Array.from({ length: n }, () => ({ sinif, zarlar: DONGU.map(() => zar()) })));
  H.forEach((h, i) => { h.deg = i % N_DEG; });     // hatalar degisikliklere sirayla dagitilir

  for (const h of H) {                             // hata hangi dongude yakalanir
    h.dongu = null;
    for (let i = 0; i < DONGU.length; i++) {
      const o = kapsam[DONGU[i][0]][h.sinif] ?? 0;
      if (h.zarlar[i] < o) { h.dongu = i; h.gecikme = kum[i]; break; }
    }
  }
  const D = Array.from({ length: N_DEG }, (_, i) => {
    const hatalar = H.filter((h) => h.deg === i);
    const erken = hatalar.filter((h) => h.dongu < DONGU.length - 1);
    return { i, hatalar, kacan: hatalar.filter((h) => h.dongu === DONGU.length - 1).length,
      oncu: kum[DONGU.length - 2] + erken.reduce((s, h) => s + kum[h.dongu], 0) };
  });
  return { H, D, kum, artis, kapsam };
}

export const ort = (a) => (a.length ? (a.reduce((s, v) => s + v, 0) / a.length).toFixed(1) : "-");

export function olc(tasima = []) {
  const { H, D, kum, artis, kapsam } = kos(tasima);
  const kacan = H.filter((h) => h.dongu === DONGU.length - 1);
  const onculer = D.map((d) => d.oncu);
  return { H, D, kum, artis, kapsam,
    toplamGecikme: H.reduce((s, h) => s + h.gecikme, 0),
    ortGecikme: ort(H.map((h) => h.gecikme)), kacan: kacan.length,
    onculSure: ort(onculer),
    dagitimSikligi: (1440 / (onculer.reduce((s, v) => s + v, 0) / D.length)).toFixed(2),
    geriDonusOrani: (100 * D.filter((d) => d.kacan > 0).length / N_DEG).toFixed(0) + "%",
    kurtarma: kum[DONGU.length - 1] };
}
```

```js
// dongu/olc.mjs — kac dongu var, uzunluklari ne, hangi hata sinifini kapsiyor; tasimanin bedeli.
import { DONGU, SINIF, KAPSAM, TOHUM, olc, ort } from "./dongu.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const T = olc();
const toplam = Object.values(SINIF).reduce((s, v) => s + v, 0);

console.log(`${DONGU.length} geri bildirim dongusu, ${Object.keys(SINIF).length} hata sinifi, ` +
  `${toplam} hata, tohum ${TOHUM}`);

const A = [-15, 10, 12, 9, 11, 12];
console.log("\n1. donguler: uzunluk ve kapsam");
yaz(A, "dongu", "uzunluk", "kumulatif", "sinif", "yakalanan", "yakalanan %");
DONGU.forEach(([ad], i) => {
  const g = T.H.filter((h) => h.dongu === i);
  yaz(A, ad, T.artis[i], T.kum[i], Object.keys(KAPSAM[ad]).length, g.length,
    (100 * g.length / toplam).toFixed(0) + "%");
});

const B = [-14, 7, 16, 14, 15];
console.log("\n2. hata sinifi hangi donguye dusuyor");
yaz(B, "sinif", "hata", "ilk kapsayan", "ort. gecikme", "uretime kacan");
for (const [s, n] of Object.entries(SINIF)) {
  const g = T.H.filter((h) => h.sinif === s);
  const ilk = DONGU.findIndex(([ad]) => (KAPSAM[ad][s] ?? 0) > 0);
  yaz(B, s, n, DONGU[ilk][0], ort(g.map((h) => h.gecikme)),
    g.filter((h) => h.dongu === DONGU.length - 1).length);
}

const K = {
  "taban": [],
  "veri-bicimi tumlestirmeye": [{ sinif: "veri-bicimi", dongu: "tumlestirmede",
    oran: 0.45, ek: 12 }],
  "yapilandirma tumlestirmeye": [{ sinif: "yapilandirma", dongu: "tumlestirmede",
    oran: 0.30, ek: 8 }],
  "zamanlama tumlestirmeye": [{ sinif: "zamanlama", dongu: "tumlestirmede",
    oran: 0.10, ek: 20 }],
  "ucu birden": [{ sinif: "veri-bicimi", dongu: "tumlestirmede", oran: 0.45, ek: 12 },
    { sinif: "yapilandirma", dongu: "tumlestirmede", oran: 0.30, ek: 8 },
    { sinif: "zamanlama", dongu: "tumlestirmede", oran: 0.10, ek: 20 }],
};
const R = Object.fromEntries(Object.entries(K).map(([ad, t]) => [ad, olc(t)]));

const C = [-27, 13, 16, 14, 15];
console.log("\n3. bir hata sinifini erken donguye tasimanin bedeli");
yaz(C, "kosum", "tumlestirme", "toplam gecikme", "ort. gecikme", "uretime kacan");
for (const [ad, r] of Object.entries(R))
  yaz(C, ad, r.artis[1], r.toplamGecikme, r.ortGecikme, r.kacan);

const E = [-24, 17, 18, 13];
console.log("\n4. tasinan sinifin kendisinde ne oldu (taban degerleri parantezde)");
yaz(E, "sinif (eklenen sure)", "erken yakalanan", "ort. gecikme", "hala kacan");
for (const [ad, t] of Object.entries(K).slice(1, 4)) {
  const s = t[0].sinif, r = R[ad], g = r.H.filter((h) => h.sinif === s);
  const b = T.H.filter((h) => h.sinif === s), son = DONGU.length - 1;
  yaz(E, `${s} (+${t[0].ek} dk)`, `${g.filter((h) => h.dongu === 1).length}/${g.length}`,
    `${ort(g.map((h) => h.gecikme))} (${ort(b.map((h) => h.gecikme))})`,
    `${g.filter((h) => h.dongu === son).length} (${b.filter((h) => h.dongu === son).length})`);
}

const F = [-27, 12, 12, 14, 12];
console.log("\n5. dort teslimat olcutu");
yaz(F, "kosum", "dagitim", "oncu sure", "geri donus", "kurtarma");
yaz(F, "", "(deg./gun)", "(dakika)", "(degisiklik)", "(dakika)");
for (const [ad, r] of Object.entries(R))
  yaz(F, ad, r.dagitimSikligi, r.onculSure, r.geriDonusOrani, r.kurtarma);
```

```
4 geri bildirim dongusu, 8 hata sinifi, 120 hata, tohum 20260806

1. donguler: uzunluk ve kapsam
dongu             uzunluk   kumulatif    sinif  yakalanan yakalanan %
yazarken                2           2        3         42         35%
tumlestirmede          28          30        3         21         18%
hazirlikta            210         240        6         25         21%
uretimde             4080        4320        8         32         27%

2. hata sinifi hangi donguye dusuyor
sinif            hata    ilk kapsayan  ort. gecikme  uretime kacan
sozdizimi          24        yazarken           2.0              0
tip                18        yazarken           5.1              0
birim-mantigi      22        yazarken         241.5              1
tumlesim           14   tumlestirmede         792.9              2
veri-bicimi        12      hazirlikta        2280.0              6
yapilandirma       12      hazirlikta        3300.0              9
zamanlama          10      hazirlikta        3096.0              7
kaynak              8      hazirlikta        3810.0              7

3. bir hata sinifini erken donguye tasimanin bedeli
kosum                        tumlestirme  toplam gecikme  ort. gecikme  uretime kacan
taban                                 28          144954        1208.0             32
veri-bicimi tumlestirmeye             40          128520        1071.0             28
yapilandirma tumlestirmeye            36          136578        1138.2             30
zamanlama tumlestirmeye               48          142224        1185.2             31
ucu birden                            68          117414         978.5             25

4. tasinan sinifin kendisinde ne oldu (taban degerleri parantezde)
sinif (eklenen sure)      erken yakalanan      ort. gecikme   hala kacan
veri-bicimi (+12 dk)                 5/12    844.5 (2280.0)        2 (6)
yapilandirma (+8 dk)                 4/12   2558.0 (3300.0)        7 (9)
zamanlama (+20 dk)                   1/10   2687.0 (3096.0)        6 (7)

5. dort teslimat olcutu
kosum                           dagitim   oncu sure    geri donus    kurtarma
                             (deg./gun)    (dakika)  (degisiklik)    (dakika)
taban                              4.09       351.9           53%        4320
veri-bicimi tumlestirmeye          3.87       372.4           47%        4332
yapilandirma tumlestirmeye         4.00       360.3           50%        4328
zamanlama tumlestirmeye            3.71       388.1           52%        4340
ucu birden                         3.43       420.2           42%        4360
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır.

#### Dört Döngü, Dört Uzunluk

Birinci tablo döngüleri yan yana koyar. Uzunluklar 2, 28, 210 ve 4080 dakikadır; kümülatif olarak
2, 30, 240 ve 4320. İki uçtaki oran 2160'tır. Yakalama dağılımı ise düz değildir: 120 hatanın 42'si
yazarken (%35), 21'i tümleştirmede (%18), 25'i hazırlıkta (%21) yakalanır ve **32'si, yani dörtte
biri, ilk üç döngünün hiçbirine düşmez.**

Kapsam sütunu nedeni söyler. Yazarken döngüsü üç sınıfı, tümleştirme üç sınıfı, hazırlık altı sınıfı
kapsar; üretim döngüsü sekizini birden kapsar, çünkü orada eleyen bir oran yoktur. Bir hata sınıfı
hiçbir erken döngünün kapsamında değilse, döngü uzunluklarının hiçbir önemi kalmaz.

Toplam gecikme 144954 dakikadır ve bunun 138240'ı — otuz iki çarpı 4320 — yalnız üretime kaçan
hatalardan gelir. **Hataların dörtte biri, gecikmenin %95'ini taşır.**

#### Hangi Sınıf Nerede Bulunuyor

İkinci tablo aynı sayıyı sınıf sınıf açar ve ortalama gecikme 2,0 dakikadan 3810,0 dakikaya kadar
uzanır. Sözdizimi ve tip hataları ilk iki döngüde biter (2,0 ve 5,1 dakika) ve hiçbiri üretime
kaçmaz. Birim mantığı üç ayrı döngünün kapsamındadır, ortalaması 241,5 dakikadır ve 22 hatasının
yalnız biri kaçar.

Kaçan 32 hatanın 29'u ilk kez **hazırlıkta** kapsanan dört sınıftan gelir: yapılandırma 9, zamanlama
7, kaynak 7, veri biçimi 6. Bu dört sınıfın hazırlıktaki yakalama oranları 0,35, 0,20, 0,15 ve
0,55'tir; yani hazırlık bu sınıflar için bir döngü değil, bir elektir. **Bir hata sınıfı ne kadar
geç kapsanıyorsa, kapsandığı yerdeki yakalama oranı da o kadar düşüktür** — çünkü sınıf geç
kapsanıyorsa erken ortamda görünmeyen bir şeye bağlıdır.

#### Taşımanın Bedeli ve Kaçırdığı

Üçüncü tablo üç taşımayı ölçer. Veri biçimi sınıfını tümleştirme döngüsüne taşımak o döngüye 12
dakika ekler; toplam gecikme 144954'ten 128520 dakikaya (%11 azalma), üretime kaçan 32'den 28'e
iner. Dördüncü tablo bunun karşılığını sınıfın kendisinde gösterir: on iki hatanın yalnız **beşi**
erken yakalanır, sınıfın ortalama gecikmesi 2280,0'dan 844,5 dakikaya iner ve iki hata hâlâ kaçar
(tabanda altı).

Zamanlama sınıfı bu kararın sınırıdır. Tümleştirme döngüsüne taşımak 20 dakika ister — üç taşımanın
en pahalısı — ve on hatanın **birini** kazanır; kaçan 7'den 6'ya iner, toplam gecikme yalnız 2730
dakika azalır. Toplu iş penceresi tümleştirme ortamında yoktur, dolayısıyla oran 0,10'dur. **En
pahalı taşıma en az kazandırandır ve nedeni oranda yazılıdır.**

Beşinci tablo dört ölçütü verir. Üç taşımanın üçü de aynı işareti taşır: geri dönüş oranı iyileşir
(%53'ten %47, %50 ve %52'ye), öteki üçü bozulur. Üçü birden uygulandığında tümleştirme döngüsü 28
dakikadan 68 dakikaya çıkar; kaçan hata 32'den 25'e, geri dönüş oranı %42'ye iner, ama dağıtım
sıklığı 4,09'dan 3,43 değişiklik/güne, öncü süre 351,9'dan 420,2 dakikaya ve kurtarma süresi
4320'den 4360 dakikaya gider. **Döngüyü uzatmak, o döngüden geçen her değişikliğin faturasıdır.**

#### Farkın Saklandığı Yer

Bu derste fark **döngü kapsamında** saklıdır ve sayısı şudur: sekiz sınıfın dördü ilk iki döngünün
hiçbirinde kapsanmaz, biri hiçbir erken döngüde 0,20'nin üstünde bir oranla kapsanmaz. Bildirilmiş
kısım döngü uzunluklarıdır — 2, 30, 240, 4320 dakika; herkes okuyabilir. Bildirilmemiş kısım
kapsamdır: hangi döngünün hangi sınıfı hangi oranla yakaladığı ancak koşumda görünür.

Sinyalin kime kaç adımda ulaştığı da buradan okunur: sözdizimi hatası yazan role 2,0 dakikada,
kaynak hatası 3810,0 dakikada ulaşır. Aynı rol, aynı akış, aynı akıştaki aynı değişiklik — 1905
katlık fark yalnız hata sınıfından gelir.

#### Özet

- Dört döngünün uzunlukları kümülatif olarak 2, 30, 240 ve 4320 dakikadır; 120 hatanın 42'si
  yazarken, 21'i tümleştirmede, 25'i hazırlıkta yakalanır, 32'si hiçbirine düşmez.
- Kaçan 32 hatanın 29'u ilk kez hazırlıkta kapsanan dört sınıftandır (yapılandırma 9, zamanlama 7,
  kaynak 7, veri biçimi 6) ve o sınıfların hazırlıktaki yakalama oranları 0,15 ile 0,55 arasındadır.
- Sınıf başına ortalama gecikme 2,0 dakikadan 3810,0 dakikaya açılır; fark döngü uzunluğundan değil,
  sınıfın hangi döngüde kapsandığından gelir.
- Veri biçimini tümleştirmeye taşımak 12 dakikaya 12 hatanın 5'ini kazandırır ve toplam gecikmeyi
  %11 düşürür; zamanlamayı taşımak 20 dakikaya 10 hatanın 1'ini kazandırır.
- Üç taşıma birlikte kaçan hatayı 32'den 25'e ve geri dönüş oranını %53'ten %42'ye indirirken
  dağıtım sıklığını 4,09'dan 3,43'e, öncü süreyi 351,9'dan 420,2 dakikaya taşır.

#### Sonraki Adım

Döngüler kuruldu ve sinyalin kime kaç adımda ulaştığı sayıldı: gözlem alanında 7,0 adım, sınırda
düşen bağlamda 61,0 adım, döngü kapsamında 2,0 ile 3810,0 dakika arası. Altı dersin altısı da aynı
şeyi ölçtü — farkın nerede saklandığını.

Ama bütün bu ölçümler sessiz bir varsayımın üstünde durdu: **aynı yazılımın her ortamda aynı yazılım
olduğu.** Bir hatanın hazırlıkta yakalanmayıp üretimde çıkması, yukarıdaki modelde bir *oran*
olarak yazıldı — 0,35, 0,20, 0,15. O oranın neden bir olmadığı hiç sorulmadı. Geliştiricinin
makinesinde çalışan ile üretimde koşan aynı şey değildir; aralarında bir fark vardır ve bu konu
boyunca o farkın adı bile konmadı. Sonraki konu tam oradan başlar: ortamlar nedir, zincirin her
halkasında hangi fark saklanır ve halkayı atlamanın bedeli nedir.

## Temel Kavramlar

Farkın nerede saklandığının sayılması: geliştirme, sınama, hazırlık ve üretim ortamlarının ayrımı, bir kez üret her yere dağıt ilkesi ve yapı çıktısının değişmezliği, sürümlenmiş ikili ve paket saklama, ortama göre değişen değerlerin yapılandırma ile sırdan ayrılması, taşınabilir uygulama ilkeleri ve elle kurulumdan bildirimsel sağlamaya uzanan altyapı modelleri.

### Ortamlar

Source: https://academia.sh/tr/kurslar/devops-temelleri/ortamlar

Geliştirme, sınama, hazırlık ve üretim arasındaki farkın nerede saklandığı sayılır: on boyutun kaçı üretimden ayrılıyor, kaçı ortam künyesinde yazıyor, hangi fark hangi hata sınıfını gizliyor ve bir halkayı atlamak kaç hata sınıfını üretime taşıyor.

Önceki konu geri bildirim döngülerini kurdu ve bir olgunun hangi role kaç adımda ulaştığını
saydı. O ölçümlerin hepsi tek bir sessiz varsayım taşıyordu: geliştiricinin makinesinde koşan
yazılım ile gece yarısı üretimde koşan yazılım **aynı yazılımdır**. Varsayım doğru olsaydı,
üretimde ilk kez görülen bir hatanın geliştirme makinesinde de görülmesi gerekirdi.

Fark bir yerde saklıdır ve adı konmadıkça ölçülmez. Bu ders farkın saklandığı ilk yeri ele
alır: yazılımın koştuğu **ortam**. Ortam burada sınamanın yapıldığı yer değil, üretime giden
zincirin bir halkasıdır; sorulan soru da her halkanın neyi görebildiğidir.

Konu boyunca tek bir kurgu sürer: bir belediyenin **bölgesel ölçüm ağı**. Yazılım su
sayaçlarından okuma toplar, okumaları doğrular, faturaya çevirir ve saha ekiplerine iş emri
açar. Bir gecelik toplu iş bütün günün okumalarını işler. Kurgudur; aşağıdaki sayılar da bu
kurgunun modelinden gelir, ölçülmüş bir kurulumdan değil.

**DK1.** Ağı yazan ekip ile işleten ekip ayrıdır. Ağda üç ortam işletilir: geliştirme, sınama
ve üretim. Dördüncü halka olan hazırlık ortamı kurulu değildir; bu dersin ölçtüğü şey tam
olarak o halkanın ne kazandırdığıdır.

#### Zincirin Dört Halkası

Ortam, bir değişikliğin üretime giderken uğradığı duraktır. Dört durak birbirinden amaçla
ayrılır, adla değil.

**Geliştirme ortamı** yazanın makinesidir. Tek süreç koşar, dış bağımlılıkların hepsi
taklittir, veri elle üretilmiş birkaç yüz kayıttır. Amacı değişikliğin biçimini görmektir:
kod derleniyor mu, işlev beklenen değeri döndürüyor mu.

**Sınama ortamı** değişikliği yazandan bağımsız çalıştırır. Otomatik sınamalar burada koşar,
veri gerçek biçimlidir ama küçüktür, bağımlılıkların bir kısmı gerçektir. Amacı değişikliğin
kendi başına doğru olup olmadığını yazanın makinesinden bağımsız doğrulamaktır.

**Hazırlık ortamı** üretime en yakın halkadır. Dış bağımlılıklar gerçektir, kaynak sınırları
üretimin sınırlarıdır, sürümler üretimin sürümleridir. Amacı doğrulamak değil, **üretime özgü
hata sınıflarını üretime varmadan görmektir**.

**Üretim ortamı** gerçek sayaç okumalarının işlendiği, gerçek faturaların üretildiği ve gerçek
saha ekiplerine iş emri açılan yerdir. Buradaki bir hatanın bedeli yanlış faturadır.

Bu dört durağın hangisinin neyi görebildiği, o durağın üretime ne kadar benzediğine bağlıdır.
Benzerliğin ölçüsünün adı **ortam denkliği** (environment parity), ölçülemez hâline gelmesinin
adı ise **yapılandırma sapmasıdır** (configuration drift): halkalar zamanla birbirinden ayrılır
ve ayrıldıkları yer kayda geçmez.

#### Denklik Neyle Ölçülür

Denkliğin sayılabilmesi için boyutların adlandırılması gerekir. Kurgudaki ağın ortam belgesi
yedi boyut bildirir: iki paket sürümü, bir kaynak sınırı, bir eşzamanlılık ayarı, bir veri
hacmi ve iki dış bağımlılığın gerçek mi taklit mi olduğu.

**DK2.** Yedi boyut ortam künyesinde yazılıdır ve iki ekip de bu belgeyi okuyabilir.
**DK3.** Üç boyut daha vardır — saat dilimi, dosya sisteminin harf duyarlılığı, ağ gecikmesi —
ve bunlar hiçbir belgede yazmaz; yalnız süreç koşarken ölçülebilir.

```js
// olcum-agi/ortamlar.mjs — dort ortamin kunyesi ve kosum yoklamasi (model, kurgu veri)

// Ortam belgesinde yazan yedi boyut. Degerler bolgesel olcum agi kurgusuna aittir.
export const KUNYE = {
  gelistirme: { cozumleyiciSurumu: "3.2.1", kuralPaketiSurumu: "9.1.0", bellekMB: 512,
    esZamanliIsci: 1, sayacSayisi: 120, faturaKapisi: "taklit", isEmriKuyrugu: "taklit" },
  sinama: { cozumleyiciSurumu: "3.2.1", kuralPaketiSurumu: "9.1.0", bellekMB: 1024,
    esZamanliIsci: 2, sayacSayisi: 5000, faturaKapisi: "taklit", isEmriKuyrugu: "gercek" },
  hazirlik: { cozumleyiciSurumu: "3.4.0", kuralPaketiSurumu: "9.1.0", bellekMB: 4096,
    esZamanliIsci: 8, sayacSayisi: 180000, faturaKapisi: "gercek", isEmriKuyrugu: "gercek" },
  uretim: { cozumleyiciSurumu: "3.4.0", kuralPaketiSurumu: "9.1.0", bellekMB: 4096,
    esZamanliIsci: 8, sayacSayisi: 1240000, faturaKapisi: "gercek", isEmriKuyrugu: "gercek" },
};

// Kunyede yazmayan, yalniz surecin icinden olculebilen uc boyut.
export const YOKLAMA = {
  gelistirme: { saatDilimi: "+03:00", harfDuyarliDosyaSistemi: false, agGecikmeMs: 0 },
  sinama: { saatDilimi: "+03:00", harfDuyarliDosyaSistemi: true, agGecikmeMs: 2 },
  hazirlik: { saatDilimi: "+00:00", harfDuyarliDosyaSistemi: true, agGecikmeMs: 11 },
  uretim: { saatDilimi: "+00:00", harfDuyarliDosyaSistemi: true, agGecikmeMs: 34 },
};

// Her boyutun, uretimden farkli oldugunda gizledigi hata sinifi.
export const GIZLENEN = {
  cozumleyiciSurumu: "cozumleme sapmasi", kuralPaketiSurumu: "tutar hatasi",
  bellekMB: "bellek tukenmesi", esZamanliIsci: "yaris durumu",
  sayacSayisi: "olcek cokusu", faturaKapisi: "sozlesme sapmasi",
  isEmriKuyrugu: "sozlesme sapmasi", saatDilimi: "gun siniri kaymasi",
  harfDuyarliDosyaSistemi: "yol cozumleme hatasi", agGecikmeMs: "zaman asimi",
};

export const BILDIRILEN = Object.keys(KUNYE.uretim);
export const YOKLANAN = Object.keys(YOKLAMA.uretim);
export const BOYUTLAR = [...BILDIRILEN, ...YOKLANAN];
export const tam = (ortam) => ({ ...KUNYE[ortam], ...YOKLAMA[ortam] });
export const farklar = (ortam) =>
  BOYUTLAR.filter((b) => tam(ortam)[b] !== tam("uretim")[b]);
```

Ölçüm her ortamı üretimle karşılaştırır ve farkı boyut boyut yazar.

```js
// olcum-agi/denklik.mjs — ortam denkligini boyut boyut sayar
import { BOYUTLAR, YOKLANAN, GIZLENEN, tam, farklar } from "./ortamlar.mjs";

const HALKA = ["gelistirme", "sinama", "hazirlik"];
const yildiz = (b) => (YOKLANAN.includes(b) ? b + " *" : b);

console.log("uretime gore denklik (* = kunyede yazmaz, yalniz kosumda gorunur)");
console.log("boyut".padEnd(26) + HALKA.map((o) => o.padEnd(11)).join("") + "gizledigi hata sinifi");
for (const b of BOYUTLAR) {
  const hucre = HALKA.map((o) => (tam(o)[b] === tam("uretim")[b] ? "ayni" : "FARK").padEnd(11));
  console.log(yildiz(b).padEnd(26) + hucre.join("") + GIZLENEN[b]);
}

const sayim = HALKA.map((o) => farklar(o));
const toplam = sayim.flat().length;
const kosumda = sayim.flat().filter((b) => YOKLANAN.includes(b)).length;
console.log("\nfark sayisi: " + HALKA.map((o, i) => `${o} ${sayim[i].length}/${BOYUTLAR.length}`).join(", "));
console.log(`toplam ${toplam} fark; kunyede yazan ${toplam - kosumda}, yalniz kosumda goruneni ${kosumda}`);
console.log("hazirligin uretimden ayrildigi boyut: " + farklar("hazirlik").join(", "));
console.log("hicbir ortamda uretime denk olmayan boyut: " +
  BOYUTLAR.filter((b) => HALKA.every((o) => tam(o)[b] !== tam("uretim")[b])).join(", "));
```

```
uretime gore denklik (* = kunyede yazmaz, yalniz kosumda gorunur)
boyut                     gelistirme sinama     hazirlik   gizledigi hata sinifi
cozumleyiciSurumu         FARK       FARK       ayni       cozumleme sapmasi
kuralPaketiSurumu         ayni       ayni       ayni       tutar hatasi
bellekMB                  FARK       FARK       ayni       bellek tukenmesi
esZamanliIsci             FARK       FARK       ayni       yaris durumu
sayacSayisi               FARK       FARK       FARK       olcek cokusu
faturaKapisi              FARK       FARK       ayni       sozlesme sapmasi
isEmriKuyrugu             FARK       ayni       ayni       sozlesme sapmasi
saatDilimi *              FARK       FARK       ayni       gun siniri kaymasi
harfDuyarliDosyaSistemi * FARK       ayni       ayni       yol cozumleme hatasi
agGecikmeMs *             FARK       FARK       FARK       zaman asimi

fark sayisi: gelistirme 9/10, sinama 7/10, hazirlik 2/10
toplam 18 fark; kunyede yazan 12, yalniz kosumda goruneni 6
hazirligin uretimden ayrildigi boyut: sayacSayisi, agGecikmeMs
hicbir ortamda uretime denk olmayan boyut: sayacSayisi, agGecikmeMs
```

Üç ortam ile üretim arasında **18 fark** vardır. Bunların **12'si künyede yazar**: bir okuyan
için görünür durumdadır, tartışılabilir ve kapatılabilir. Kalan **6'sı hiçbir belgede
yazmaz**; ancak süreç o ortamda koşarken görülebilir. Bu ayrım dersin ölçü eksenidir:
bildirilmiş fark bir karar konusudur, yalnız koşumda görünen fark ise bir sürprizdir.

Bu 18 farkın hiçbiri bir kararla konmuş değildir. Ortamlar farklı tarihlerde kurulmuş, farklı
zamanlarda yükseltilmiş ve bakımları ayrı ayrı yapılmıştır: üretimin paket sürümü yükseltilince
geliştirme makinesi geride kalmış, sınamaya gerçek iş emri kuyruğu bağlanınca fatura kapısı
taklit bırakılmıştır. Yapılandırma sapmasının anlamı budur — fark, kimsenin karar vermediği
yerde birikir. Sapmanın ölçülebilir olması için de tek koşul vardır: boyutların adlandırılmış
ve künyenin okunabilir olması.

Gradyan da okunabilir: geliştirme üretimden on boyutun dokuzunda ayrılır, sınama yedisinde,
hazırlık ikisinde. Halkalar üretime yaklaştıkça fark sayısı düşer — zincirin sıralı olmasının
nedeni budur. Ayrıca iki boyut — veri hacmi ve ağ gecikmesi — **hiçbir ortamda** üretime denk
değildir. Bir buçuk milyon sayaç ile yüz yirmi sayaç arasındaki farkı taşımayan hiçbir halka
yoktur.

#### Farkın Gizlediği Hata Sınıfı

Fark sayısı tek başına karar taşımaz; farkın **neyi gizlediği** taşır. Aşağıdaki model her
boyuta bir kusur bağlar ve kusurun zincirin hangi halkasında ilk kez görüneceğini hesaplar.

**DK4.** Model kuralı tektir: bir kusur, bağlı olduğu boyutta ortam üretimle aynı değeri
taşıyorsa görünür, taşımıyorsa görünmez. **DK5.** Her boyut tek bir hata sınıfı taşır; on
boyut on kusur demektir. **DK6.** Zincir sırayla geçilir ve kusur ilk görüldüğü halkada durur.

```js
// olcum-agi/zincir.mjs — bir kusurun zincirin hangi halkasinda gorundugunu sayar
import { GIZLENEN, tam } from "./ortamlar.mjs";

// Model kurali: kusur, bagli oldugu boyutta ortam uretimle ayni degeri tasiyorsa gorunur.
const KUSURLAR = [
  ["bos okuma alani cozumlenemiyor", "cozumleyiciSurumu"],
  ["yeni tarife dilimi yanlis yuvarlaniyor", "kuralPaketiSurumu"],
  ["toplu is butun okumalari bellege aliyor", "bellekMB"],
  ["ayni sayac icin iki fatura satiri", "esZamanliIsci"],
  ["dogrulama sorgusu sayac sayisinin karesinde", "sayacSayisi"],
  ["fatura kapisinin ret kodu islenmiyor", "faturaKapisi"],
  ["is emri kuyruguna ayni emir iki kez", "isEmriKuyrugu"],
  ["gecelik is gun sinirini yerel saatle kesiyor", "saatDilimi"],
  ["tarife dosyasi buyuk harfle araniyor", "harfDuyarliDosyaSistemi"],
  ["toplayici yaniti zaman asimini asiyor", "agGecikmeMs"],
];

const DORT = ["gelistirme", "sinama", "hazirlik", "uretim"];
const UC = ["gelistirme", "sinama", "uretim"];
const ilkGoren = (zincir, boyut) =>
  zincir.find((o) => tam(o)[boyut] === tam("uretim")[boyut]);

console.log("kusur".padEnd(45) + "dort halka".padEnd(12) + "uc halka");
for (const [ad, boyut] of KUSURLAR) {
  console.log(ad.padEnd(45) + ilkGoren(DORT, boyut).padEnd(12) + ilkGoren(UC, boyut));
}

const say = (zincir) => {
  const d = Object.fromEntries(zincir.map((o) => [o, 0]));
  for (const [, boyut] of KUSURLAR) d[ilkGoren(zincir, boyut)] += 1;
  return zincir.map((o) => `${o} ${d[o]}`).join(", ");
};
console.log("\ndort halkali zincir: " + say(DORT));
console.log("uc halkali zincir  : " + say(UC));

const kacan = (zincir) => KUSURLAR.filter(([, b]) => ilkGoren(zincir, b) === "uretim");
const dortKacan = kacan(DORT).map(([, b]) => GIZLENEN[b]);
const ucKacan = kacan(UC).map(([, b]) => GIZLENEN[b]);
const ek = ucKacan.filter((s) => !dortKacan.includes(s));
console.log(`hazirlik dururken de uretime kacan ${dortKacan.length} sinif: ` + dortKacan.join(", "));
console.log(`hazirlik atlandiginda kacan ${ucKacan.length} sinif; eklenen ${ek.length}:`);
for (let i = 0; i < ek.length; i += 3) console.log("  " + ek.slice(i, i + 3).join(", "));

console.log("\nzincir uzunlugu tarandi (halkalar sirayla eklenir):");
let onceki = 0;
for (let n = 0; n <= 3; n++) {
  const z = [...DORT.slice(0, n), "uretim"];
  const yakalanan = KUSURLAR.filter(([, b]) => ilkGoren(z, b) !== "uretim").length;
  console.log(`${n} halka + uretim`.padEnd(20) + `uretimden once yakalanan ${yakalanan}` +
    `  (son halkanin katkisi ${yakalanan - onceki})`);
  onceki = yakalanan;
}
```

```
kusur                                        dort halka  uc halka
bos okuma alani cozumlenemiyor               hazirlik    uretim
yeni tarife dilimi yanlis yuvarlaniyor       gelistirme  gelistirme
toplu is butun okumalari bellege aliyor      hazirlik    uretim
ayni sayac icin iki fatura satiri            hazirlik    uretim
dogrulama sorgusu sayac sayisinin karesinde  uretim      uretim
fatura kapisinin ret kodu islenmiyor         hazirlik    uretim
is emri kuyruguna ayni emir iki kez          sinama      sinama
gecelik is gun sinirini yerel saatle kesiyor hazirlik    uretim
tarife dosyasi buyuk harfle araniyor         sinama      sinama
toplayici yaniti zaman asimini asiyor        uretim      uretim

dort halkali zincir: gelistirme 1, sinama 2, hazirlik 5, uretim 2
uc halkali zincir  : gelistirme 1, sinama 2, uretim 7
hazirlik dururken de uretime kacan 2 sinif: olcek cokusu, zaman asimi
hazirlik atlandiginda kacan 7 sinif; eklenen 5:
  cozumleme sapmasi, bellek tukenmesi, yaris durumu
  sozlesme sapmasi, gun siniri kaymasi

zincir uzunlugu tarandi (halkalar sirayla eklenir):
0 halka + uretim    uretimden once yakalanan 0  (son halkanin katkisi 0)
1 halka + uretim    uretimden once yakalanan 1  (son halkanin katkisi 1)
2 halka + uretim    uretimden once yakalanan 3  (son halkanin katkisi 2)
3 halka + uretim    uretimden once yakalanan 8  (son halkanin katkisi 5)
```

Tablo bir kuralı görünür kılar: **bir ortam, yalnız üretimle aynı olduğu boyutlardaki kusurları
görebilir.** Geliştirme ortamı on kusurdan yalnız birini yakalar, çünkü üretimle yalnız tek bir
boyutta — kural paketi sürümünde — aynıdır. Sınama iki kusur yakalar; ikisi de sınamanın
üretimle aynı olduğu boyutlara bağlıdır: gerçek iş emri kuyruğu ve harf duyarlı dosya sistemi.

Ters yönde okumak daha çok şey söyler: bir ortamın **yakalayamadığı** hata sınıflarının listesi,
o ortamın üretimden ayrıldığı boyutların listesidir. Hazırlık ortamı iki boyutta ayrılıyordu;
hazırlık dururken üretime kaçan iki hata sınıfı da tam olarak o iki boyuta bağlı olanlardır.
Bu, modelin bir çıkarımı değil, tanımının sonucudur — ama tanımı sayıya çevirdiği için ortam
tartışmasını fikirden çıkarır: "hazırlık ortamına gerek var mı" sorusunun yerine "hangi
boyutlarda denklik satın alıyoruz" sorusu geçer.

Çıktının son bölümü zincir uzunluğunu tarar: halkalar sırayla eklendiğinde üretimden önce
yakalanan sınıf sayısı 0, 1, 3 ve 8 olur. Halka başına katkı **eşit değildir** — birinci halka
bir sınıf, ikincisi iki, üçüncüsü beş sınıf ekler. Sıralama bunun nedenini de verir: her halka
bir öncekinin göremediği boyutları kapatır ve üretime en yakın halka en çok boyutu kapatan
halkadır. Zincirin başına yeni bir ortam eklemek katkının küçük olduğu yere yatırım yapmaktır;
kapatılan boyut sayısı, halkanın adından değil künyesinden okunur.

#### Halkayı Atlamanın Bedeli

Kurgudaki ağ hazırlık ortamını işletmiyordu. Modelin iki koşumu bu kararın bedelini sayar.

Dört halkalı zincirde üretime iki hata sınıfı kaçar: ölçek çöküşü ve zaman aşımı. Üç halkalı
zincirde yediye çıkar. Hazırlık halkası **beş hata sınıfını** üretimin önünde yakalar:
çözümleme sapması, bellek tükenmesi, yarış durumu, sözleşme sapması ve gün sınırı kayması. Bu
beşi, ağın hazırlığı kurmadığı sürece **ilk kez gerçek fatura üretilirken** görünen sınıflardır.

Atlamanın kazandırdığı da sayılabilir: zincir dört duraktan üçe iner, yani bir yayım daha az
bekleme ve bir devir daha az el değiştirme demektir. Bu kazanç öncü süreye yazılır; bedel ise
geri dönüş oranına ve kurtarma süresine yazılır, çünkü kaçan beş sınıfın her biri üretimde
görüldüğünde geri alınacak bir değişiklik ve onarılacak bir kesinti üretir. Tek ölçüte bakan
bir cümle burada karar taşımaz: hızlanma bir yerden alınıp başka bir yere konur.

Kaçan iki sınıf ise hazırlık kurulsa bile yerinde kalır, çünkü hiçbir halka bir buçuk milyon
sayaçlık veri hacmini ve otuz dört milisaniyelik ağ gecikmesini taşımaz. Bu iki boyutu
kapatmanın yolu vardır — üretim ölçeğinde biçimlendirilmiş veri kümesi ve yapay gecikme
eklenmesi — ve her ikisinin de bir bedeli vardır: ortamın kurulum maliyeti ve koşum süresi.
Ölçüm bu tartışmayı da somutlaştırır: kapatılacak boyut iki tanedir, ikisinin adı bellidir ve
kapatıldığında hangi hata sınıfının önünün alınacağı yazılıdır.

Son olarak künye ile koşum arasındaki altı farkın anlamı buradadır. Künyede yazan on iki fark
bir toplantıda gündeme gelebilir; yazmayan altısı gelemez. Saat diliminin geliştirme ile üretim
arasında ayrılması, gecelik toplu işin gün sınırını yanlış yerden kesmesi olarak ortaya çıkar
ve nedeninin ortam farkı olduğu, hata bulunana kadar kimsenin aklına gelmez. Ortam künyesinin
kapsamını genişletmek — koşumda ölçülen üç boyutu da bildirmek — bu altı farkın altısını da
tartışılabilir hâle getirir.

#### Özet

- Ortam, üretime giden zincirin bir halkasıdır; dört halka amaçla ayrılır ve her halka yalnız
  üretimle aynı olduğu boyutlardaki kusurları görebilir.
- Ortam denkliği boyut boyut sayılır. Kurgu modelinde on boyut vardır; üç ortam ile üretim
  arasında 18 fark ölçülmüştür: geliştirme 9, sınama 7, hazırlık 2.
- Bu 18 farkın 12'si ortam künyesinde bildirilmiştir, 6'sı yalnız süreç koşarken görünür;
  bildirilmemiş fark tartışılamadığı için karar konusu olamaz.
- Her farkın gizlediği bir hata sınıfı vardır ve bir ortamın yakalayamadığı sınıfların listesi,
  o ortamın üretimden ayrıldığı boyutların listesine eşittir.
- Hazırlık halkası beş hata sınıfını üretimin önünde yakalar; atlanması bu beşini üretime
  taşır. Veri hacmi ve ağ gecikmesi hiçbir halkada denk olmadığı için iki sınıf her koşulda
  üretime kalır.

#### Sonraki Adım

Bu dersin zinciri bir şeyi varsaydı: halkalar arasında yolculuk eden nesne hep aynı nesnedir.
Oysa ortam künyeleri bunu doğrulamıyor — her halkanın kendi paket sürümleri, kendi dosya
yolları ve kendi ortam değişkenleri var. Değişiklik her durakta kaynaktan yeniden derleniyorsa
zincirde dolaşan tek bir nesne değil, dört ayrı nesne vardır ve hangisinin hangisiyle aynı
olduğu ölçülmemiştir. Sonraki ders bu nesneyi adlandırır ve ölçer: aynı kaynaktan iki kez
üretilen çıktı gerçekten aynı mı, değilse farkı hangi kaynaklar sokuyor ve ortam başına
yeniden derleme kaç ayrı ikili doğuruyor?

### Yapı Çıktısı ve Değişmezlik

Source: https://academia.sh/tr/kurslar/devops-temelleri/yapi-ciktisi-ve-degismezlik

Bir kez üret her yere dağıt ilkesi ölçülür: aynı kaynaktan iki kez üretilen çıktının özeti karşılaştırılır, yeniden üretilebilirliği bozan dört kaynak tek tek kapatılır ve ortam başına yeniden derlemenin doğurduğu ayrı ikili sayısı tek çıktı düzeniyle karşılaştırılır.

Önceki ders dört ortamı üretime giden zincirin halkaları olarak ölçtü ve her halkanın yalnız
üretimle aynı olduğu boyutlardaki kusurları görebildiğini saydı. O ölçüm bir şeyi varsaydı:
halkalar arasında yolculuk eden nesne hep aynı nesnedir. Sınamada doğrulanan şey ile üretimde
koşan şey aynı değilse, sınamanın verdiği güvence de o kadar azalır.

Bu ders o nesneyi adlandırır. **Yapı çıktısı** (build artifact), kaynaktan üretilen ve
dağıtılabilen tek nesnedir: bir arşiv, bir paket, çalıştırılabilir tek bir dosya. Sorular
ölçülebilir: aynı kaynaktan iki kez üretilen çıktı gerçekten aynı mı, değilse farkı nereden
alıyor ve her ortam için yeniden derlemek kaç ayrı nesne doğuruyor?

**DK7.** Aşağıdaki yapı adımı bir modeldir: üç kaynak dosya okunur ve tek dosyada birleştirilir.
Gerçek bir derleyicinin yaptığı iş değildir, ama yeniden üretilebilirlik açısından aynı
kırılganlıkları taşır. **DK8.** İki makine künyeyle modellenir — `A` yazan ekibin makinesi,
`B` yapıyı çalıştıran koşucu — ve saat de künyede yazılıdır ki ölçüm yinelenebilsin. `A1` ve
`A2` aynı makinenin iki ayrı koşumudur. **DK9.** Özet, dosyanın sha256 değerinin ilk on altı
onaltılık basamağıdır; kısaltma yalnız okunabilirlik içindir.

#### Bir Kez Üret, Her Yere Dağıt

Değişmezlik ilkesi tek cümledir: **bir yapı çıktısı bir kez üretilir, üretildikten sonra
değiştirilmez ve her ortama aynısı dağıtılır.** Üretimdeki bir dosyayı yerinde yamalamak,
sınamada doğrulanmış nesneyi bilinmeyen bir nesneye çevirir; düzeltme gerekiyorsa yeni bir
çıktı üretilir ve yeni bir özet doğar. Geri alma da aynı kuralla çalışır: önceki çıktı yeniden
dağıtılır, mevcut çıktı geri düzenlenmez.

İlkenin ihlali de somuttur. Üretimde tek bir dosyanın elle düzeltilmesi, o ortamda artık hiçbir
yerde kaydı olmayan yeni bir nesne yaratır: zincirde bir nesne dolaşırken üretimde ikincisi
durur, ikincisinin özeti hiçbir dağıtım kaydında yazmaz ve ortam künyesi bunu göstermez. Bir
sonraki dağıtım bu düzeltmeyi sessizce siler; ortadan kalkan davranışın nedeni de aranacak
yerlerin hiçbirinde bulunmaz. Yerinde yamalamanın bedeli budur: fark, ölçüm alanının tümüyle
dışında bir yere saklanır.

İlkenin işe yaraması tek koşula bağlıdır: çıktının **kimliğinin** olması. Kimlik, içeriğin
özetidir. İki çıktının aynı olup olmadığı ancak özetleri karşılaştırılarak söylenebilir; dosya
adı, üretim tarihi ya da sürüm etiketi bunu söylemez. Bu yüzden ölçüm özetten başlar.

```js
// olcum-agi/yapi.mjs — kaynagi diske yazar, tek dosyalik yapi ciktisi uretir (model)
import { mkdirSync, writeFileSync, readFileSync, rmSync } from "node:fs";
import { createHash } from "node:crypto";

const KAYNAK = "kaynak";

export const kaynagiYaz = () => {
  rmSync(KAYNAK, { recursive: true, force: true });
  mkdirSync(KAYNAK, { recursive: true });
  writeFileSync(`${KAYNAK}/okuma-cozumleyici.js`, "export const cozumle = (s) => Number(s.slice(4));\n");
  writeFileSync(`${KAYNAK}/fatura-kurallari.js`, "export const tutar = (m3) => m3 * 7.4;\n");
  writeFileSync(`${KAYNAK}/is-emri.js`, "export const emirAc = (no) => ({ no, tur: 'yerinde' });\n");
};

// Makine kunyesi: saat de kunyede yazilidir, boylece olcum yinelenebilir.
export const A1 = { ad: "A1", saat: "21:04:07", dizin: "/ev/yazan/olcum-agi", yapan: "yazan-ekip",
  okumaSirasi: ["okuma-cozumleyici.js", "fatura-kurallari.js", "is-emri.js"] };
export const A2 = { ...A1, ad: "A2", saat: "21:19:52" };
export const B = { ad: "B", saat: "22:41:30", dizin: "/opt/kosucu/is-1873", yapan: "hat-kosucusu",
  okumaSirasi: ["is-emri.js", "fatura-kurallari.js", "okuma-cozumleyici.js"] };

export const DORT_KAYNAK = ["zamanDamgasi", "dizinSirasi", "ortamDegiskeni", "mutlakYol"];
export const yalniz = (ad) => Object.fromEntries(DORT_KAYNAK.map((k) => [k, k === ad]));

export const yapiYap = (kunye, secenek, hedef, gomulu = null) => {
  const dosyalar = secenek.dizinSirasi ? kunye.okumaSirasi : [...kunye.okumaSirasi].sort();
  const baslik = [];
  if (secenek.zamanDamgasi) baslik.push(`// uretim ani: ${kunye.saat}`);
  if (secenek.ortamDegiskeni) baslik.push(`// yapan: ${kunye.yapan}`);
  if (secenek.mutlakYol) baslik.push(`// kaynak koku: ${kunye.dizin}/${KAYNAK}`);
  if (gomulu) baslik.push(`export const AYAR = ${JSON.stringify(gomulu)};`);
  const govde = dosyalar.map((d) => readFileSync(`${KAYNAK}/${d}`, "utf8")).join("");
  mkdirSync("dagitim", { recursive: true });
  writeFileSync(`dagitim/${hedef}`, baslik.join("\n") + (baslik.length ? "\n" : "") + govde);
  return createHash("sha256").update(readFileSync(`dagitim/${hedef}`)).digest("hex").slice(0, 16);
};
```

#### Yeniden Üretilebilirliği Bozan Dört Kaynak

**DK10.** Yapı adımına dört ayrı bozucu kaynak yerleştirilmiştir ve her biri ayrı ayrı
kapatılabilir: üretim anının çıktıya yazılması (`zamanDamgasi`), kaynak dosyaların dizin okuma
sırasıyla birleştirilmesi (`dizinSirasi`), yapıyı çalıştıranın adının gömülmesi
(`ortamDegiskeni`) ve kaynak kökünün mutlak yolunun yazılması (`mutlakYol`). Dördü de gerçek
yapı adımlarında karşılaşılan kaynaklardır.

Tarama üç koşum yapar — aynı makinede iki an (`A1`, `A2`) ve ikinci makine (`B`) — ve her
seçenek kümesi için kaç ayrı özet doğduğunu sayar.

```js
// olcum-agi/tara.mjs — yeniden uretilebilirligi bozan kaynaklari tek tek tarar
import { kaynagiYaz, yapiYap, yalniz, DORT_KAYNAK, A1, A2, B } from "./yapi.mjs";

kaynagiYaz();
const hepsi = Object.fromEntries(DORT_KAYNAK.map((k) => [k, true]));
const hicbiri = Object.fromEntries(DORT_KAYNAK.map((k) => [k, false]));

const ozetler = (secenek) =>
  [A1, A2, B].map((k) => yapiYap(k, secenek, `paket-${k.ad}.js`));

const satir = (etiket, secenek) => {
  const [a1, a2, b] = ozetler(secenek);
  const ayri = new Set([a1, a2, b]).size;
  console.log(etiket.padEnd(24) + (a1 === a2 ? "AYNI   " : "FARKLI ").padEnd(12) +
    (a1 === b ? "AYNI   " : "FARKLI ").padEnd(11) + ayri);
};

console.log("etkin kaynak".padEnd(24) + "A1-A2".padEnd(12) + "A1-B".padEnd(11) + "ayri ozet");
satir("dordu birden", hepsi);
for (const k of DORT_KAYNAK) satir("yalniz " + k, yalniz(k));
satir("hicbiri", hicbiri);

const [a1, a2, b] = ozetler(hicbiri);
console.log(`\ndort kaynak kapatildiginda uc kosumun ozeti: ${a1}, ${a2}, ${b}`);
console.log("ayni girdi, ayni cikti: " + (a1 === a2 && a2 === b));
```

```
etkin kaynak            A1-A2       A1-B       ayri ozet
dordu birden            FARKLI      FARKLI     3
yalniz zamanDamgasi     FARKLI      FARKLI     3
yalniz dizinSirasi      AYNI        FARKLI     2
yalniz ortamDegiskeni   AYNI        FARKLI     2
yalniz mutlakYol        AYNI        FARKLI     2
hicbiri                 AYNI        AYNI       1

dort kaynak kapatildiginda uc kosumun ozeti: f8aa0bd8108fe25b, f8aa0bd8108fe25b, f8aa0bd8108fe25b
ayni girdi, ayni cikti: true
```

Tablo iki şeyi ayırır. Birincisi: **dört kaynağın her biri tek başına yeniden
üretilebilirliği bozmaya yeter.** Yalnız biri etkinken bile ikinci makinede üretilen çıktının
özeti farklıdır; aynı kaynaktan üretilmiş iki nesnenin aynı olduğu söylenemez.

İkincisi ve daha önemlisi: dört kaynağın üçü **aynı makinedeki iki koşumda görünmez.** Dizin
okuma sırası, ortam değişkeni ve mutlak yol, tek makinede sabit kaldıkları için `A1` ile `A2`
arasında fark üretmez. Yazan ekip kendi makinesinde yapıyı iki kez çalıştırıp aynı özeti görür
ve yapının yeniden üretilebilir olduğu sonucuna varır. Fark, çıktı ikinci bir makinede
üretildiği anda ortaya çıkar. Önceki dersin ayrımı burada da geçerlidir: bildirilmiş bir fark
değildir bu, yalnız koşumda — hem de başka bir makinedeki koşumda — görünen bir farktır ve
gizlediği hata sınıfının adı **doğrulanmamış ikilidir**: sınamadan geçen nesnenin üretime giden
nesne olduğu ölçülmemiştir.

Dördü de kapatıldığında üç koşum tek özet üretir. Bu, özetin artık koşumu değil **girdiyi**
adlandırdığı anlamına gelir: aynı özet, aynı kaynak. Kaynakların kapatılma yolları da bellidir
ve dördü de yapı adımının içindedir — zaman damgasını çıktıya yazmamak, dosyaları dizin okuma
sırasıyla değil ada göre sıralamak, yapıyı çalıştıranın kimliğini gömmemek ve yolları kaynak
köküne göre göreli tutmak.

Özetin ne söylediği ile ne söylemediği de ayrılmalıdır. Özet **bayt kimliğini** söyler: iki
çıktının özeti aynıysa iki nesne aynıdır, dağıtım kaydında biri diğerinin yerine yazılabilir.
Söylemediği iki şey vardır. Birincisi, çıktının hangi kaynaktan üretildiğini söylemez; özet
çıktının kendisinden hesaplanır, kaynağın kimliğinden değil. Yapı adımı yeniden üretilebilir
olduğunda bu boşluk kapanabilir: aynı kaynaktan yapıyı ikinci kez çalıştıran bir başkası aynı
özeti elde eder ve iddia sınanabilir hâle gelir — yeniden üretilebilirliğin düzenden öte
değeri buradadır. İkincisi, özet farkının **anlamlı** bir davranış farkı olduğunu söylemez;
çıktıya eklenen tek bir açıklama satırı da özeti baştan sona değiştirir. Farklı özet, bir kanıt
değil, incelenmesi gereken bir işarettir.

#### Ortam Başına Derleme ile Tek Çıktı

Zincirin her halkası için ayrı derleme yapmanın somut karşılığı vardır: ortama göre değişen
değerler yapı adımında çıktının içine yazılır. **DK11.** Kurgudaki ağda bu değerler dörttür —
ortam adı, fatura kapısının gerçek mi taklit mi olduğu, kütük düzeyi ve gecelik toplu işin
yığın eşiği. **DK12.** Tek çıktı düzeninde aynı dört değer açılışta ortamdan okunur; okumanın
nasıl yapıldığı ve hangi değerin sır sayıldığı sonraki dersin konusudur.

```js
// olcum-agi/ortam-basina.mjs — ortam basina yeniden derleme ile tek ciktiyi karsilastirir
import { kaynagiYaz, yapiYap, DORT_KAYNAK, A1, A2, B } from "./yapi.mjs";

const AYAR = {
  gelistirme: { ortamAdi: "gelistirme", faturaKapisi: "taklit", kutuk: "ayrintili", esik: 500 },
  sinama: { ortamAdi: "sinama", faturaKapisi: "taklit", kutuk: "bilgi", esik: 20000 },
  uretim: { ortamAdi: "uretim", faturaKapisi: "gercek", kutuk: "uyari", esik: 250000 },
};
const ORTAM = Object.keys(AYAR);
const hicbiri = Object.fromEntries(DORT_KAYNAK.map((k) => [k, false]));
const hepsi = Object.fromEntries(DORT_KAYNAK.map((k) => [k, true]));
kaynagiYaz();

console.log("gomulu deger anahtarlari: " + Object.keys(AYAR.uretim).join(", "));
const ayri = ORTAM.map((o) => [o, yapiYap(A1, hicbiri, `paket-${o}.js`, AYAR[o])]);
for (const [o, ozet] of ayri) {
  const fark = Object.keys(AYAR[o]).filter((k) => AYAR[o][k] !== AYAR.uretim[k]);
  console.log(`${o.padEnd(11)} ozet ${ozet}  uretim ikilisinden farkli deger ${fark.length}`);
}
console.log(`ortam basina derleme: ${new Set(ayri.map(([, h]) => h)).size} ayri ikili, ` +
  `ikililere gomulu deger ${ORTAM.length * Object.keys(AYAR.uretim).length}`);

const tek = ORTAM.map((o) => yapiYap(A1, hicbiri, `paket-tek-${o}.js`));
console.log(`tek cikti duzeni    : ${new Set(tek).size} ayri ikili, ozet ${tek[0]}, gomulu deger 0`);

console.log("\nortam basina derleme farkli makinelerde ve anlarda yapilirsa:");
const gurultu = [[A1, "sinama"], [B, "uretim"], [A2, "uretim"]]
  .map(([k, o]) => [`${o} @ ${k.ad}`, yapiYap(k, hepsi, `paket-g-${o}-${k.ad}.js`, AYAR[o])]);
for (const [ad, ozet] of gurultu) console.log("  " + ad.padEnd(14) + "ozet " + ozet);
console.log("  ayni ortam icin iki kosum ayni ozeti verdi: " + (gurultu[1][1] === gurultu[2][1]));
```

```
gomulu deger anahtarlari: ortamAdi, faturaKapisi, kutuk, esik
gelistirme  ozet e9b4bbcaec4a64a4  uretim ikilisinden farkli deger 4
sinama      ozet 3cb0ab9967d14e1a  uretim ikilisinden farkli deger 4
uretim      ozet 440bf8366e892e51  uretim ikilisinden farkli deger 0
ortam basina derleme: 3 ayri ikili, ikililere gomulu deger 12
tek cikti duzeni    : 1 ayri ikili, ozet f8aa0bd8108fe25b, gomulu deger 0

ortam basina derleme farkli makinelerde ve anlarda yapilirsa:
  sinama @ A1   ozet b47af357c8f24d3c
  uretim @ B    ozet 9ee506035c8f4235
  uretim @ A2   ozet 19f12b586982fdc3
  ayni ortam icin iki kosum ayni ozeti verdi: false
```

Ortam başına derleme **üç ayrı ikili** doğurur ve bu üç ikilinin içinde toplam **on iki gömülü
değer** taşınır. Sınamanın onayladığı nesne, üretime giden nesneden dört değerde ayrılır: ortam
adı, fatura kapısı, kütük düzeyi ve toplu iş eşiği. Bu dördü çıktının **içinde** durur; dışarıdan
bakan bir kişi üç dosyanın da aynı adı taşıdığını görür, farkı yalnız özet söyler. Fatura
kapısının sınama ikilisinde taklit, üretim ikilisinde gerçek olması, önceki dersin sözleşme
sapması sınıfını sınamanın hiçbir koşumunda görünmez kılar.

Tek çıktı düzeninde üç ortam **tek ikili** paylaşır: özet üçünde de aynıdır ve gömülü değer
sayısı sıfırdır. On iki değer yok olmaz, yer değiştirir — çıktının içinden ortamın künyesine
geçer. Önceki dersin ölçüsüyle söylenirse: bildirilmemiş, yalnız koşumda görünen on iki fark,
bildirilmiş on iki farka dönüşür. Farkın miktarı aynı kalır, saklandığı yer değişir; ölçülebilir
hâle gelen de budur.

Son üç satır ortam başına derlemenin ikinci bedelini gösterir. Yapılar farklı makinelerde ve
farklı anlarda koştuğunda, aynı ortam için üretilen iki çıktı bile farklı özet taşır. Özet artık
ortamı adlandırmaz; koşumu adlandırır. İki özet farklı olduğunda bunun nedeninin ortam farkı mı
yoksa yapı gürültüsü mü olduğu ayırt edilemez ve "üretimde koşan şey sınamada doğrulanan şey mi"
sorusunun yanıtı ölçülemez hâle gelir.

Çıktının gerçekten diskte durduğu ve özetin o dosyanın özeti olduğu ayrıca doğrulanabilir.

```bash
# dogrula.sh — diskteki cikti gercekten var mi, ozeti node'un bastigiyla ayni mi
ls dagitim/paket-tek-*.js
shasum -a 256 dagitim/paket-tek-uretim.js | cut -c1-16
cat dagitim/paket-tek-uretim.js
```

```
dagitim/paket-tek-gelistirme.js
dagitim/paket-tek-sinama.js
dagitim/paket-tek-uretim.js
f8aa0bd8108fe25b
export const tutar = (m3) => m3 * 7.4;
export const emirAc = (no) => ({ no, tur: 'yerinde' });
export const cozumle = (s) => Number(s.slice(4));
```

Üç ortam için yazılan dosyaların içeriği aynıdır ve kabuktan alınan özet, `node` sürecinin
bastığı `f8aa0bd8108fe25b` değeriyle örtüşür. Dosya adları farklı olsa da nesne tektir; bu,
değişmezlik ilkesinin ölçülmüş hâlidir. Dosyaların birleşme sırasının ada göre olduğu da
görülür — dizin okuma sırası kapatıldığı için.

#### Zincirde Kaç Nesne Dolaşıyor

Önceki dersin zinciri bir nesnenin dört durakta ilerlemesiydi. Ölçüm iki düzenin bu zincire ne
verdiğini de sayar. Ortam başına derlemede zincirde üç ayrı nesne dolaşır ve üç ayrı yapı koşumu
yapılır; her koşum, taramada sayılan dört bozucu kaynağın önüne yeniden açıktır. Tek çıktı
düzeninde nesne birdir, koşum birdir ve halkalar arası geçiş bir kopyalama işlemine iner.

Fark, sorulabilecek soruların sayısında görünür. Tek çıktı düzeninde "sınamada doğrulanan nesne
üretime giden nesne mi" sorusu tek bir özet karşılaştırmasıyla yanıtlanır: iki değer eşitse evet,
değilse hayır. Ortam başına derlemede aynı soru sorulamaz bile, çünkü iki ortamın özeti zaten
tanım gereği farklıdır ve farkın hangi kısmının ortam ayarından, hangi kısmının yapı
gürültüsünden geldiği ayrıştırılamaz. Ölçülebilir bir güvence, ölçülemeyen bir alışkanlığa
dönüşür.

Ayrım teslimat ölçütlerine de yazılır. Bir düzeltmenin üretime ulaşması ortam başına derlemede
üç yapı koşumu gerektirir; üçünün de başarılı olması ve doğru ortama gitmesi gerekir, bu da öncü
süreye üç kez yapı ve üç kez dağıtım hazırlığı ekler. Geri dönüş oranı tarafında ise doğrulanmamış
ikili sınıfı vardır: sınamadan geçen nesne üretime gitmediği için, sınamanın yakaladığı hata
sınıflarının bir bölümü üretimde yeniden doğabilir. Tek çıktı düzeni bu iki ölçütü aynı yönde
oynatır — ama bedeli, ortama göre değişen on iki değeri çıktının dışında bir yerde tutmayı
zorunlu kılmasıdır.

#### Özet

- Yapı çıktısı kaynaktan üretilen ve dağıtılan tek nesnedir; değişmezlik ilkesi bu nesnenin bir
  kez üretilmesini, yerinde değiştirilmemesini ve her ortama aynısının gitmesini söyler.
- İki çıktının aynı olup olmadığı yalnız içerik özetiyle söylenebilir; dosya adı, tarih ve
  sürüm etiketi bunu söylemez.
- Yeniden üretilebilirliği bozan dört kaynak ölçüldü — zaman damgası, dizin okuma sırası, ortam
  değişkeni, mutlak yol — ve her biri tek başına ikinci makinede farklı özet üretmeye yetti.
  Dördü kapatıldığında üç koşum tek özet verdi.
- Bu dört kaynağın üçü aynı makinedeki iki koşumda görünmez; fark ancak yapı başka bir makinede
  koştuğunda ortaya çıkar. Gizlediği hata sınıfı doğrulanmamış ikilidir.
- Ortam başına yeniden derleme üç ayrı ikili ve on iki gömülü değer üretti; tek çıktı düzeninde
  ikili sayısı bire, gömülü değer sayısı sıfıra indi. Değerler yok olmadı, çıktının içinden
  ortamın künyesine geçti.

#### Sonraki Adım

Tek çıktı düzeni bir soruyu yanıtsız bıraktı: üretilen bu tek nesne nerede durur ve nasıl
adlandırılır? Bir özet kimliktir ama ad değildir; on altı onaltılık basamağı dağıtım kayıtlarına
elle yazmak sürdürülebilir bir düzen değildir. Ayrıca çıktı bir kez üretilip her yere
dağıtılacaksa, üretildiği yerden dağıtılacağı yere kadar bir yerde saklanması ve geri alma
gerektiğinde önceki sürümün hâlâ bulunabilmesi gerekir. Sonraki ders bu saklama yerini ölçer:
sürüm nasıl etiketlenir, değişmez sürüm ile taşınabilir etiket arasındaki fark kaç dağıtımda
kendini gösterir ve saklama süresi kuralı geri alma penceresini nerede kapatır?

### Yapı Çıktısı Depoları

Source: https://academia.sh/tr/kurslar/devops-temelleri/yapi-ciktisi-depolari

Sürümlenmiş ikili ve paket saklama ölçülür: değişmez sürüm ile taşınabilir etiket ayrımı bir depo modelinde kurulur, taşınabilir etiketin kaç dağıtımda başka bir çıktıya işaret ettiği sayılır ve saklama kuralı geri alma penceresi, depo baytı ve ulaşılamaz dağıtım sayısı üzerinden taranır.

Önceki ders tek bir yapı çıktısı üretti ve kimliğinin içerik özeti olduğunu ölçtü. Özet
kimliktir ama ad değildir: onaltılık basamaklardan oluşan bir diziyi dağıtım kayıtlarına elle
taşımak sürdürülebilir bir düzen değildir. Ayrıca çıktı bir kez üretilip her yere dağıtılacaksa,
üretildiği an ile dağıtıldığı an arasında bir yerde durması ve geri alma gerektiğinde önceki
çıktının hâlâ bulunabilmesi gerekir.

Bu ders o duran yeri ele alır: **yapı çıktısı deposu** (artifact repository). Depo, sürümlenmiş
ikilileri ve paketleri saklayan, onlara ad veren ve istendiğinde geri veren bileşendir. Burada
bir ürün olarak değil, tür olarak ele alınır; ölçülen şey de deponun sunduğu iki adlandırma
biçiminin — değişmez sürüm ile taşınabilir etiketin — dağıtımda ne ürettiğidir.

**DK13.** Depo modeli iki işlevle sınırlıdır: değişmez sürüm kaydı ve ad çözümü. Erişim
denetimi, çoğaltma ve ağ katmanı modelin dışındadır. **DK14.** Yayım çizelgesi kendi
üretecimizle kurulur; tohum `20260311` görünürdür ve çizelge 24 sürümü ortalama dört günde bir
yayımlar. **DK15.** Sürüm boyutları 38–52 MB aralığında üreteçten gelir; gerçek bir ölçüm değil,
kurgunun büyüklük mertebesidir.

#### Depo Ne Saklar

Depo iki ayrı şey saklar: **içerik** ve **ad**. İçerik, önceki dersin ölçtüğü nesnedir; adı ise
insanların dağıtım kaydına yazdığı sözdür. Bu iki şeyin ilişkisi ikiye ayrılır.

**Değişmez sürüm**, bir kez yayımlandıktan sonra başka bir içeriğe bağlanamayan addır. `1.5.0`
bir kez yayımlandıysa, `1.5.0` her zaman aynı çıktıdır. **Taşınabilir etiket** ise bir sürümü
gösteren ve zaman içinde başka bir sürüme taşınabilen addır: `kararli`, `son`, `hazirlik-adayi`
gibi. İkisi de addır, ama biri kimliğe, diğeri bir işaretçiye karşılık gelir.

Aşağıdaki model iki işlevi ve değişmezlik kuralının denetimini içerir.

```js
// olcum-agi/depo.mjs — surumlenmis yapi ciktisi deposu ve yayim cizelgesi (model)
import { createHash } from "node:crypto";

// Kendi uretecimiz: dogrusal esleme. Tohum cagirana aittir, cikti yinelenebilir.
export const uretec = (tohum) => () =>
  (tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648;

export const ozetle = (metin) => createHash("sha256").update(metin).digest("hex").slice(0, 12);

export const depoKur = () => {
  const surumler = new Map();   // degismez: surum -> { ozet, bayt, gun }
  const etiketler = new Map();  // tasinabilir: etiket -> surum
  const ret = [];
  return {
    surumler, etiketler, ret,
    yayimla(surum, ozet, bayt, gun) {
      const eski = surumler.get(surum);
      if (eski && eski.ozet !== ozet) { ret.push(surum); return "RET"; }
      if (eski) return "AYNI";
      surumler.set(surum, { ozet, bayt, gun });
      return "YAYIM";
    },
    etiketle: (etiket, surum) => etiketler.set(etiket, surum),
    coz(ad) {
      const surum = etiketler.get(ad) ?? ad;
      const kayit = surumler.get(surum);
      return kayit ? { surum, ozet: kayit.ozet } : null;
    },
  };
};

// n surumluk yayim cizelgesi: gun araliklari ve bayt boyutlari uretecten gelir.
export const cizelge = (n, ortalamaGun, tohum) => {
  const r = uretec(tohum);
  const liste = [];
  let gun = 0;
  for (let i = 1; i <= n; i++) {
    gun += 1 + Math.round(r() * (2 * ortalamaGun - 2));
    liste.push({
      surum: `1.${i}.0`, ozet: ozetle(`1.${i}.0-icerik`),
      bayt: 38_000_000 + Math.round(r() * 14_000_000), gun,
      temizKostu: r() > 0.45,
    });
  }
  return liste;
};
```

`yayimla` işlevinin üç yanıtı vardır ve bu üçü depo davranışının tamamıdır: yeni sürüm
kaydedilir, aynı içerikle yinelenen yayım yok sayılır, aynı ad başka içerikle geldiğinde
reddedilir. Üçüncüsü değişmezlik ilkesinin depodaki karşılığıdır — reddedilmezse, önceki dersin
ölçtüğü bütün özet karşılaştırmaları anlamını yitirir, çünkü `1.5.0` adının hangi nesneyi
gösterdiği zamana bağlı hâle gelir.

#### Değişmez Sürüm ve Taşınabilir Etiket

Ölçüm 24 sürümü çizelgeye göre yayımlar ve arada gelen dağıtım isteklerini karşılar.

**DK16.** `son` etiketi her yayımda taşınır; `kararli` etiketi yalnız gecelik toplu işi temiz
koşan sürümlere taşınır. **DK17.** Dağıtım kaydı yalnız **istenen adı** saklar, çözülen sürümü
saklamaz — ölçülen kusurun kaynağı budur.

```js
// olcum-agi/etiket.mjs — tasinabilir etiketin kac dagitimda baska cikti tasidigini sayar
import { depoKur, cizelge } from "./depo.mjs";

const SURUMLER = cizelge(24, 4, 20260311);
const depo = depoKur();

// Dagitim istekleri: gun ve istenen ad. Ad ya tasinabilir etiket ya degismez surumdur.
const ISTEK = [
  [6, "kararli"], [11, "kararli"], [17, "son"], [23, "kararli"], [29, "kararli"],
  [34, "1.5.0"], [41, "kararli"], [48, "son"], [55, "kararli"], [66, "1.13.0"],
  [70, "kararli"], [79, "kararli"], [86, "son"], [92, "1.21.0"],
];

const kayitlar = [];
let sirada = 0;
for (const [gun, ad] of ISTEK) {
  while (sirada < SURUMLER.length && SURUMLER[sirada].gun <= gun) {
    const s = SURUMLER[sirada++];
    depo.yayimla(s.surum, s.ozet, s.bayt, s.gun);
    depo.etiketle("son", s.surum);
    if (s.temizKostu) depo.etiketle("kararli", s.surum);
  }
  kayitlar.push({ gun, ad, ...depo.coz(ad) });
}

console.log("gun".padEnd(5) + "istenen ad".padEnd(12) + "cozulen surum".padEnd(15) + "ozet");
for (const k of kayitlar) {
  console.log(String(k.gun).padEnd(5) + k.ad.padEnd(12) + k.surum.padEnd(15) + k.ozet);
}

const tasinabilir = kayitlar.filter((k) => k.ad === "kararli" || k.ad === "son");
const sonGorulen = new Map();
let degisim = 0;
for (const k of tasinabilir) {
  if (sonGorulen.has(k.ad) && sonGorulen.get(k.ad) !== k.ozet) degisim += 1;
  sonGorulen.set(k.ad, k.ozet);
}
const ayri = (ad) => new Set(kayitlar.filter((k) => k.ad === ad).map((k) => k.ozet)).size;

console.log(`\ntoplam dagitim ${kayitlar.length}: tasinabilir etiketle ${tasinabilir.length}, ` +
  `degismez surumle ${kayitlar.length - tasinabilir.length}`);
console.log(`"kararli" adiyla ${kayitlar.filter((k) => k.ad === "kararli").length} dagitim yapildi, ` +
  `${ayri("kararli")} ayri ciktiya isaret etti`);
console.log(`"son" adiyla ${kayitlar.filter((k) => k.ad === "son").length} dagitim yapildi, ` +
  `${ayri("son")} ayri ciktiya isaret etti`);
console.log(`ayni ad, onceki dagitimdan baska cikti: ${degisim} dagitim`);

// Degismezlik denetimi: yayimlanmis bir surum baska ozetle yeniden yayimlanmak istenirse.
console.log("\nayni surum, baska ozet: " + depo.yayimla("1.5.0", "ffffffffffff", 4e7, 99));
console.log("ayni surum, ayni ozet : " + depo.yayimla("1.5.0", depo.coz("1.5.0").ozet, 4e7, 99));
console.log("reddedilen yeniden yayim: " + depo.ret.length);
```

```
gun  istenen ad  cozulen surum  ozet
6    kararli     1.1.0          69a51066dd19
11   kararli     1.2.0          4a318efc7537
17   son         1.4.0          6c9ea8b0936a
23   kararli     1.2.0          4a318efc7537
29   kararli     1.6.0          e82d2dacf6b1
34   1.5.0       1.5.0          1d7edd1472a2
41   kararli     1.7.0          837826307ef8
48   son         1.10.0         4d590510b154
55   kararli     1.10.0         4d590510b154
66   1.13.0      1.13.0         e4438d40a263
70   kararli     1.16.0         6ed1bdfd5c1e
79   kararli     1.16.0         6ed1bdfd5c1e
86   son         1.19.0         39b3f9d7c5d7
92   1.21.0      1.21.0         90749e3c6c1c

toplam dagitim 14: tasinabilir etiketle 11, degismez surumle 3
"kararli" adiyla 8 dagitim yapildi, 6 ayri ciktiya isaret etti
"son" adiyla 3 dagitim yapildi, 3 ayri ciktiya isaret etti
ayni ad, onceki dagitimdan baska cikti: 7 dagitim

ayni surum, baska ozet: RET
ayni surum, ayni ozet : AYNI
reddedilen yeniden yayim: 1
```

Sayılar tek bir cümleye toplanır: **on dört dağıtımın on biri bir ada yapıldı ve o ad yedisinde
bir öncekinden başka bir çıktı taşıdı.** `kararli` adıyla yapılan sekiz dağıtım altı ayrı
nesneyi üretime taşımıştır; kayıtta yazan söz ise sekizinde de aynıdır.

Tabloda iki durum ayrıca okunmalıdır. Gün 11 ile gün 23 arasında `kararli` etiketi yerinde
kalmıştır: arada yayımlanan sürümler gecelik toplu işi temiz koşmadığı için etiket taşınmamış,
iki dağıtım da `1.2.0` çıktısını almıştır. Yani taşınabilir etiket her zaman taşınmaz; taşınıp
taşınmadığı dağıtımı isteyen taraftan görünmez. Gün 55 ile gün 79 arasında ise tersi olmuştur:
aynı ad, `1.10.0` yerine `1.16.0` çıktısını taşımıştır.

Bu, geri almanın da ölçülebilir tuzağıdır. Gün 79'da bir sorun görülüp "kararlı sürüme dönelim"
denirse, çözülen nesne gün 55'te dağıtılan `1.10.0` değil, güncel `1.16.0` olur — geri alma
isteği ileri bir dağıtım üretir. Geri almanın çalışması için istenen adın **değişmez sürüm**
olması gerekir; tabloda üç dağıtım bunu yapmıştır.

**Farkın saklandığı yer burada ad çözümüdür.** Çözüm dağıtım anında yapılır ve kayda geçmez;
dağıtım kaydında yalnız `kararli` yazar. Sonradan bakan biri, hangi dağıtımın hangi nesneyi
taşıdığını on bir kayıtta okuyamaz. Fark bildirilmemiş değildir yalnızca — kaydedilmemiştir.
Kapatılması da tek satırlıktır: dağıtım kaydına istenen adın yanına çözülen sürüm ve özet de
yazılır; o zaman on bir belirsiz kaydın on biri okunabilir hâle gelir.

Çıktının son üç satırı değişmezlik denetimini gösterir. Yayımlanmış `1.5.0` başka bir özetle
yeniden yayımlanmak istendiğinde depo `RET` döndürür; aynı özetle geldiğinde `AYNI` der ve
yeniden yazma yapmaz. Bu ikinci davranış, yapı adımının iki kez koşması durumunda hatayla
sonuçlanmamasını sağlar — yeniden üretilebilir bir yapı için doğal karşılıktır.

#### Girdi Tarafı ve Üstveri

Depo yalnız yapı adımının çıktısını saklamaz; aynı türden bir depo, yapı adımının **girdisi**
olan paketleri de saklar. Ölçülen ad çözümü sorunu bu tarafta da aynen geçerlidir. Bir yapı
adımı girdi paketini değişmez sürümle değil taşınabilir bir adla — "uyumlu en yeni" türünden
bir ifadeyle — istiyorsa, önceki dersin dört bozucu kaynağı kapatılmış olsa bile iki koşum
farklı çıktı üretebilir; çünkü aradan geçen sürede ad başka bir nesneye taşınmıştır. Bu,
yeniden üretilebilirliği bozan **beşinci kaynaktır** ve öncekilerin hepsinden farklı olarak
yapı adımının kendi içinde değil, dışarıda durur. Ölçülen orandaki gibi: adla çözülen on bir
istekten yedisinde nesne değişmişti; aynı belirsizlik girdi tarafında yapı adımına taşınır.
Kapatılması, girdi sürümlerinin ad değil sürüm olarak sabitlenmesiyle olur.

İkinci konu üstveridir. Önceki dersin bıraktığı boşluk, özetin çıktının hangi kaynaktan
üretildiğini söylememesiydi. Depo bu boşluğu kapatabilecek yerdir: her sürüm kaydına üç alan
eklenir — çıktının üretildiği kaynak sürümü, yapı koşumunun kimliği ve o koşumda geçen
sınamaların sonucu. Bu üç alan yazıldığında "üretimde koşan nesne hangi kaynaktan geldi"
sorusu depodan okunur; yazılmadığında yanıt yalnız insanların hatırasındadır. Üç alanın da
çıktının **içine** değil, yanına yazıldığına dikkat edilmelidir: içine yazmak, önceki dersin
ölçtüğü gibi her koşumda özeti değiştirir ve yeniden üretilebilirliği bozar.

#### Saklama Kuralı Neyi Kapatır

Depo sınırsız değildir. Saklama kuralı hangi sürümlerin ne kadar tutulacağını söyler.
**DK18.** Kural sayıya bağlıdır: "son K sürüm tutulur". Tarama, K değiştikçe üç niceliği birden
ölçer — deponun baytı, geri alma penceresi ve önceki ölçümdeki dağıtımların kaçının hedefinin
silinmiş olacağı.

```js
// olcum-agi/saklama.mjs — saklama kuralini tarar: pencere, bayt ve ulasilamaz dagitim
import { cizelge } from "./depo.mjs";

const S = cizelge(24, 4, 20260311);
const son = S[S.length - 1];
// Onceki olcumde 14 dagitimin cozuldugu surumler:
const DAGITILAN = ["1.1.0", "1.2.0", "1.4.0", "1.2.0", "1.6.0", "1.5.0", "1.7.0",
  "1.10.0", "1.10.0", "1.13.0", "1.16.0", "1.16.0", "1.19.0", "1.21.0"];

const mb = (b) => (b / 1e6).toFixed(0) + " MB";
console.log("kural".padEnd(14) + "depo".padEnd(10) + "geri alma penceresi".padEnd(21) + "ulasilamaz dagitim");
for (const k of [3, 5, 8, 12, 18, 24]) {
  const tutulan = S.slice(-k);
  const bayt = tutulan.reduce((t, s) => t + s.bayt, 0);
  const adlar = new Set(tutulan.map((s) => s.surum));
  const ulasilamaz = DAGITILAN.filter((v) => !adlar.has(v)).length;
  console.log(`son ${k} surum`.padEnd(14) + mb(bayt).padEnd(10) +
    `${son.gun - tutulan[0].gun} gun`.padEnd(21) + `${ulasilamaz}/${DAGITILAN.length}`);
}

console.log("");
for (const aralik of [4, 2]) {
  const c = cizelge(24, aralik, 20260311);
  console.log(`yayim araligi ~${aralik} gun: 24 surum ${c[23].gun} gune yayiliyor, ` +
    `"son 8 surum" penceresi ${c[23].gun - c[16].gun} gun`);
}

const toplam = S.reduce((t, s) => t + s.bayt, 0);
console.log(`\nkural yoksa: ${S.length} surum ${mb(toplam)}; bu hizda yillik buyume ` +
  mb((toplam / son.gun) * 365));
```

```
kural         depo      geri alma penceresi  ulasilamaz dagitim
son 3 surum   129 MB    4 gun                14/14
son 5 surum   214 MB    11 gun               13/14
son 8 surum   352 MB    23 gun               12/14
son 12 surum  535 MB    37 gun               9/14
son 18 surum  805 MB    69 gun               6/14
son 24 surum  1073 MB   97 gun               0/14

yayim araligi ~4 gun: 24 surum 99 gune yayiliyor, "son 8 surum" penceresi 23 gun
yayim araligi ~2 gun: 24 surum 47 gune yayiliyor, "son 8 surum" penceresi 11 gun

kural yoksa: 24 surum 1073 MB; bu hizda yillik buyume 3955 MB
```

Tarama saklama kuralını bir tercih tablosuna çevirir. "Son sekiz sürüm" kuralı depoyu 352 MB'de
tutar ama geri alma penceresini 23 güne indirir: 23 günden eski bir sürüme dönmek istendiğinde
nesne artık yoktur. Aynı kural altında, ölçülen on dört dağıtımın on ikisinin taşıdığı çıktı
silinmiştir; yani "hangi sürümü koşuyorduk" sorusunun yanıtı bilinse bile o sürüm geri
getirilemez. Pencereyi 69 güne çıkarmak deponun 805 MB'ye, yani iki katından fazlasına
büyümesini gerektirir.

Sayıya bağlı kuralın gizlediği bir bağımlılık vardır: **pencere, yayım sıklığına bağlıdır.**
Aynı "son sekiz sürüm" kuralı, dört günde bir yayımlayan bir ekipte 23 günlük, iki günde bir
yayımlayan bir ekipte 11 günlük pencere verir. Kural metni değişmemiştir, kuralın anlamı
değişmiştir. Dağıtım sıklığını artırmak — teslimat ölçütlerinden birini iyileştirmek — hiçbir
şey yapılmadan geri alma penceresini yarıya indirir; bu, bir ölçütü iyileştiren kararın
başkasında ölçülen değişimine örnektir. Pencerenin sıklıktan bağımsız olması isteniyorsa kural
süreye bağlanır ("doksan günden eski sürümler silinir") ya da iki koşul birlikte yazılır.

Kural konmadığında da bir sayı vardır: bu hızda depo yılda yaklaşık 3955 MB büyür. Sınırsız
saklama bir karar değil, ertelenmiş bir karardır; ertelendiğinde de silmeye çoğunlukla yer
kalmadığı gün, yani geri alma penceresinin en çok gerektiği anda başlanır.

#### Özet

- Yapı çıktısı deposu iki şey saklar: içerik ve ad. Ad iki türlüdür — bir kez bağlandıktan
  sonra değişmeyen sürüm ve zaman içinde başka sürüme taşınabilen etiket.
- Değişmezlik denetimi depoda uygulanır: aynı sürüm başka içerikle yeniden yayımlanmak
  istendiğinde reddedilir, aynı içerikle geldiğinde yok sayılır.
- Ölçümde 14 dağıtımın 11'i taşınabilir bir ada yapılmış, ad bunların 7'sinde bir öncekinden
  başka bir çıktı taşımıştır; `kararli` adıyla yapılan 8 dağıtım 6 ayrı nesne dağıtmıştır.
- Fark, dağıtım anındaki ad çözümünde saklıdır ve kaydedilmediği için sonradan okunamaz. Çözülen
  sürümün ve özetin kayda yazılması 11 belirsiz kaydı okunabilir kılar; geri almanın çalışması
  için istenen adın değişmez sürüm olması gerekir.
- Saklama kuralı üç niceliği birden belirler: "son 8 sürüm" 352 MB depo, 23 gün geri alma
  penceresi ve 14 dağıtımdan 12'sinin hedefinin silinmesi demektir. Sayıya bağlı kuralın
  penceresi yayım sıklığı arttıkça kısalır; sıklık iki katına çıkınca pencere 23 günden 11 güne
  inmiştir.

#### Sonraki Adım

Depoda duran çıktı artık tek ve adlandırılmıştır, ama önceki dersin sonunda bir borç kalmıştı:
ortama göre değişen on iki değer çıktının içinden çıkarıldı ve "ortamın künyesine" konuldu.
Bu değerlerin hepsi aynı türden değildir. Fatura kapısının adresi ile o kapıya bağlanmak için
kullanılan anahtar aynı yerden okunur, ama biri kütüğe yazılabilir, diğeri yazılamaz; biri
dağıtım kaydında görünebilir, diğeri görünemez. Sonraki ders bu sınırı çizer ve ölçer: ortamdan
gelen değerlerin kaçı yapılandırma, kaçı sır sayılır, sır kaç ayrı yoldan dışarı sızabilir ve
sızıntının kapatıldığı bir denetimle nasıl gösterilir?

### Yapılandırma ve Sır Ayrımı

Source: https://academia.sh/tr/kurslar/devops-temelleri/yapilandirma-ve-sir-ayrimi

Üç ortamın yapılandırma dosyaları diske yazılır ve çalışan bir denetleyici kaç anahtarın gerçekten değiştiğini, kaçının değişmediği hâlde yapılandırmada durduğunu ve kaçının bir ortamda tanımsız olduğunu sayar; sırrın sızabileceği dört yüzey bir tarayıcıyla taranır ve yakalanan, kaçan, yanlış alarm ayrı ayrı yazılır.

Aynı yazılımın üç ortamda aynı yazılım olmasını sağlayan şey kodun aynı olması değildir; kodun
okuduğu değerlerin nerede durduğudur. Bir uygulamanın yapılandırmayı ortamdan okuması, gizli
değerleri kaynaktan ayrı tutması **Sunucu Tarafı Temelleri** kursunda kurulmuştu. Bu ders o
kurulumu tekrarlamaz. Buradaki birim tek uygulama değil, **ortamlar arasındaki fark**tır: kaç
değer ortamdan ortama gerçekten değişiyor, kaçı değişmediği hâlde yapılandırmada duruyor, kaçı
bir ortamda hiç tanımlı değil ve sır sayılan değerler kaç ayrı yoldan dışarı sızıyor.

Ölçüm **bölgesel ölçüm ağı** üzerinde yapılır: su sayaçlarından okuma toplayan, okumaları
doğrulayan, faturaya çeviren ve saha ekiplerine iş emri açan **kurgu** bir yazılım. Üç ortamı
ve gecelik bir toplu işi vardır. Aşağıdaki dosyalar gerçekten diske yazılır, denetleyiciler
gerçekten koşar; içerdikleri değerlerin tamamı kurgudur ve hiçbiri gerçek bir gizli değer
değildir.

**DK19.** Ortamlar arasındaki tek ayrım yapılandırma dosyalarıdır; kod, yapı çıktısı ve işletim
adımları üç ortamda aynıdır.
**DK20.** Yapılandırma `ANAHTAR=deger` biçiminde düz dosyalarda durur; sır sayılan anahtarlar ad
kalıbıyla belirlenir, ayrı bir sır deposu yoktur.
**DK21.** Sırrın sızabileceği yüzey dörttür ve dördü de diskteki birer dosyayla temsil edilir:
yapı çıktısı, günlük, hata iletisi, sürüm deposuna işlenmiş dosya dizini.
**DK22.** Sızıntılar taramadan önce bilerek yerleştirilir ve sayıları bilinir; kaçanın
sayılabilmesi buna bağlıdır.

#### Üç Ortamın Dosyaları

```bash
#!/usr/bin/env bash
# Kurgu bolgesel olcum aginin uc ortam yapilandirmasini diske yazar.
set -e
mkdir -p yapilandirma kaynak

cat > yapilandirma/gelistirme.env <<'SON'
ORTAM_ETIKETI=gelistirme
OLCUM_VERI_ADRESI=127.0.0.1:5432
OLCUM_VERI_HAVUZ=4
OLCUM_VERI_PAROLA=kurgu-gel-p4t9
SAYAC_OKUMA_ZAMAN_ASIMI_MS=2000
DOGRULAMA_ESIK_YUZDE=12
TOPLU_IS_BASLANGIC=02:30
TOPLU_IS_ES_ZAMAN=2
SAHA_IS_EMRI_ADRESI=127.0.0.1:8081
FATURA_PARA_BIRIMI=TRY
KUTUK_DUZEYI=ayrinti
AZAMI_DENEME=3
SON

cat > yapilandirma/sinama.env <<'SON'
ORTAM_ETIKETI=sinama
OLCUM_VERI_ADRESI=olcum-sinama.ic:5432
OLCUM_VERI_HAVUZ=8
OLCUM_VERI_PAROLA=kurgu-sin-r7w2
SAYAC_OKUMA_ZAMAN_ASIMI_MS=2000
DOGRULAMA_ESIK_YUZDE=12
TOPLU_IS_BASLANGIC=02:30
TOPLU_IS_ES_ZAMAN=4
SAHA_IS_EMRI_ADRESI=is-emri-sinama.ic:8081
FATURA_PARA_BIRIMI=TRY
KUTUK_DUZEYI=ayrinti
AZAMI_DENEME=3
SINAMA_TOHUMU=4471
SON

cat > yapilandirma/uretim.env <<'SON'
ORTAM_ETIKETI=uretim
OLCUM_VERI_ADRESI=olcum-uretim.ic:5432
OLCUM_VERI_HAVUZ=32
OLCUM_VERI_PAROLA=kurgu-ure-h3m8
SAYAC_OKUMA_ZAMAN_ASIMI_MS=2000
DOGRULAMA_ESIK_YUZDE=12
TOPLU_IS_BASLANGIC=02:30
TOPLU_IS_ES_ZAMAN=16
FATURA_PARA_BIRIMI=TRY
KUTUK_DUZEYI=ozet
AZAMI_DENEME=3
FATURA_IMZA_ANAHTARI=kurgu-imza-9c1e
SON
```

Uygulamanın okuma noktası tektir ve ortam adına bakan hiçbir dallanma içermez.

```js
// kaynak/ayar.mjs — kurgu uygulamanin tek ayar noktasi: her deger ortamdan okunur.
export const ayar = {
  ortam:         process.env.ORTAM_ETIKETI,
  veriAdresi:    process.env.OLCUM_VERI_ADRESI,
  parola:        process.env.OLCUM_VERI_PAROLA,
  isEmriAdresi:  process.env.SAHA_IS_EMRI_ADRESI,
  imzaAnahtari:  process.env.FATURA_IMZA_ANAHTARI,
  havuz:         Number(process.env.OLCUM_VERI_HAVUZ),
  zamanAsimiMs:  Number(process.env.SAYAC_OKUMA_ZAMAN_ASIMI_MS ?? 2000),
  esikYuzde:     Number(process.env.DOGRULAMA_ESIK_YUZDE ?? 12),
  topluBaslangic: process.env.TOPLU_IS_BASLANGIC ?? "02:30",
  esZaman:       Number(process.env.TOPLU_IS_ES_ZAMAN ?? 2),
  paraBirimi:    process.env.FATURA_PARA_BIRIMI ?? "TRY",
  kutukDuzeyi:   process.env.KUTUK_DUZEYI ?? "ozet",
  azamiDeneme:   Number(process.env.AZAMI_DENEME ?? 3),
  yenidenOkumaGun: Number(process.env.YENIDEN_OKUMA_GUN ?? 30),
};
```

#### Farkın Sayımı

Denetleyici üç dosyayı ve kaynağın okuma noktalarını ayrı ayrı okur, sonra ikisini karşılaştırır.

```js
// denetle.mjs — uc ortam dosyasi ile kaynaktaki okuma noktalarini karsilastirir.
import { readFileSync } from "node:fs";

const ORTAMLAR = ["gelistirme", "sinama", "uretim"];
const oku = (a) => Object.fromEntries(readFileSync(`yapilandirma/${a}.env`, "utf8")
  .split("\n").filter(Boolean).map((s) => [s.slice(0, s.indexOf("=")), s.slice(s.indexOf("=") + 1)]));

const dosya = Object.fromEntries(ORTAMLAR.map((a) => [a, oku(a)]));
const anahtarlar = [...new Set(ORTAMLAR.flatMap((a) => Object.keys(dosya[a])))].sort();

const kaynak = readFileSync("kaynak/ayar.mjs", "utf8");     // hangi anahtar okunuyor,
const okunan = new Map();                                   // kacinin gomulu varsayilani var
for (const [, ad, vars] of kaynak.matchAll(/process\.env\.([A-Z_]+)(\s*\?\?)?/g))
  okunan.set(ad, Boolean(vars));

const say = { degisen: [], sabit: [], eksik: [] };
for (const k of anahtarlar) {
  const v = ORTAMLAR.map((a) => dosya[a][k]);
  if (v.some((x) => x === undefined)) say.eksik.push(k);
  else if (new Set(v).size === 1) say.sabit.push(k);
  else say.degisen.push(k);
}
const gizliVarsayilan = [...okunan].filter(([k]) => !anahtarlar.includes(k)).map(([k]) => k);
const zorunlu = [...okunan].filter(([, v]) => !v).map(([k]) => k);

const yaz = (etiket, liste) => {                            // sayiyi bas, adlari ucerli sar
  console.log(`${etiket.padEnd(30)}: ${liste.length}`);
  for (let i = 0; i < liste.length; i += 3) console.log("    " + liste.slice(i, i + 3).join(" "));
};
console.log(`toplam anahtar (uc dosyada)   : ${anahtarlar.length}`);
yaz("  ucunde var, degeri farkli", say.degisen);
yaz("  ucunde var, degeri ayni", say.sabit);
yaz("  en az bir ortamda eksik", say.eksik);
console.log(`kaynagin okudugu anahtar      : ${okunan.size}, varsayilansiz: ${zorunlu.length}`);
yaz("  hicbir ortam dosyasinda yok", gizliVarsayilan);
yaz("  dosyada var, kaynak okumuyor", anahtarlar.filter((k) => !okunan.has(k)));
for (const a of ORTAMLAR)
  yaz(`kosumda patlar / ${a}`, zorunlu.filter((k) => dosya[a][k] === undefined));
```

```
toplam anahtar (uc dosyada)   : 14
  ucunde var, degeri farkli   : 6
    KUTUK_DUZEYI OLCUM_VERI_ADRESI OLCUM_VERI_HAVUZ
    OLCUM_VERI_PAROLA ORTAM_ETIKETI TOPLU_IS_ES_ZAMAN
  ucunde var, degeri ayni     : 5
    AZAMI_DENEME DOGRULAMA_ESIK_YUZDE FATURA_PARA_BIRIMI
    SAYAC_OKUMA_ZAMAN_ASIMI_MS TOPLU_IS_BASLANGIC
  en az bir ortamda eksik     : 3
    FATURA_IMZA_ANAHTARI SAHA_IS_EMRI_ADRESI SINAMA_TOHUMU
kaynagin okudugu anahtar      : 14, varsayilansiz: 6
  hicbir ortam dosyasinda yok : 1
    YENIDEN_OKUMA_GUN
  dosyada var, kaynak okumuyor: 1
    SINAMA_TOHUMU
kosumda patlar / gelistirme   : 1
    FATURA_IMZA_ANAHTARI
kosumda patlar / sinama       : 1
    FATURA_IMZA_ANAHTARI
kosumda patlar / uretim       : 1
    SAHA_IS_EMRI_ADRESI
```

On dört anahtarın yalnız altısı üç ortamda tanımlı ve değeri gerçekten farklı. **Farkın
saklandığı yer bu altı satırdır.** Geri kalan sekiz anahtar farkı değil, farkın görüntüsünü
taşır.

Beş anahtar üç ortamda da aynı değeri taşıyor. Bunlar yapılandırma değil, sabittir; yapılandırma
dosyasında durmalarının bir bedeli vardır: tek bir ortamda elle değiştirilebilirler.
`DOGRULAMA_ESIK_YUZDE` üretimde on ikiden on beşe çekildiğinde doğrulama davranışı sessizce
ayrışır ve bu değişiklik hiçbir kod incelemesine düşmez, çünkü kod değişmemiştir.

Bildirilmiş fark ile yalnız koşumda görünen fark burada ayrışır. Bildirilmiş olan, dosyalardaki
altı satırdır: yazılıdır, okunabilir, karşılaştırılabilir. Yalnız koşumda görünen ise ikiye
ayrılır. `YENIDEN_OKUMA_GUN` hiçbir ortam dosyasında yok; kaynakta varsayılanı otuz. Yani
**dördüncü bir ortam tanımı kaynağın içinde duruyor** ve üç ortamın hepsi onu kullanıyor.
Değerini değiştirmek için yapılandırma değil kod değiştirmek gerekir; yapılandırmanın ortamda
durması ilkesi tam burada kırılır ve kırıldığı hiçbir dosyadan okunmaz. `SINAMA_TOHUMU` bunun
aynası: sınama dosyasında yazılı ama kaynak onu hiç okumuyor. Bildirilmiş bir farkın etkili
olduğu varsayılamaz; sınamanın sabit tohumla koştuğunu sanan biri, tohumsuz koşan bir sınamaya
bakıyor.

Farkın gizlediği hata sınıfı, eksik anahtarların dağılımında görülür. `SAHA_IS_EMRI_ADRESI`
yalnız üretimde eksik: iş emri açma yolu geliştirme ve sınamada sorunsuz koşar, üretimde ilk iş
emrinde tanımsız bir adrese gider. Bu hata sınıfının adı **yalnız üretimde görünen yol**dur ve
sınama onu göremez, çünkü sınamada eksik olan şey yoktur. `FATURA_IMZA_ANAHTARI` bunun tersidir:
yalnız üretimde tanımlı olduğu için imzalama yolu üretim dışında hiç koşmamıştır. İki eksiklik
aynı sayıya sahiptir — her ortamda bir tane — ama biri üretimde patlar, öteki üretimde ilk kez
denenir.

#### Farkın Ne Zaman Göründüğü

Sayım her ortamda bir eksik zorunlu anahtar bildirdi; eksikliğin **ne zaman** görüneceğini
bildirmedi. Aynı sayı iki ayrı hata sınıfına karşılık gelir ve aradaki farkı belirleyen şey,
uygulamanın o anahtarı açılışta mı yoksa ilk kullanımda mı okuduğudur.

```js
// baslat.mjs — acilista zorunlu anahtarlari dogrular; imza yolu ise is aninda calisir.
import { ayar } from "./kaynak/ayar.mjs";

const ACILIS_ZORUNLU = ["ortam", "veriAdresi", "parola", "isEmriAdresi"];
const eksik = ACILIS_ZORUNLU.filter((k) => ayar[k] === undefined);
if (eksik.length) {
  console.log(`  acilis reddedildi -> eksik: ${eksik.join(", ")}`);
  process.exit(1);
}
console.log(`  acildi -> havuz=${ayar.havuz} esZaman=${ayar.esZaman} kutuk=${ayar.kutukDuzeyi}`);
try {                                                  // gecelik toplu isin imzalama adimi
  if (!ayar.imzaAnahtari) throw new Error("imza anahtari tanimsiz");
  console.log(`  03:00 toplu is -> imzalandi`);
} catch (h) {
  console.log(`  03:00 toplu is -> basarisiz: ${h.message}`);
}
```

```bash
#!/usr/bin/env bash
# Her ortamin dosyasini yukleyip uygulamayi ayri ayri baslatir.
for o in gelistirme sinama uretim; do
  echo "$o:"
  ( set -a; . "yapilandirma/$o.env"; set +a; node baslat.mjs ) || true
done
```

```
gelistirme:
  acildi -> havuz=4 esZaman=2 kutuk=ayrinti
  03:00 toplu is -> basarisiz: imza anahtari tanimsiz
sinama:
  acildi -> havuz=8 esZaman=4 kutuk=ayrinti
  03:00 toplu is -> basarisiz: imza anahtari tanimsiz
uretim:
  acilis reddedildi -> eksik: isEmriAdresi
```

Üç ortamın üçünde de bir zorunlu anahtar eksikti ve sayı üçünde de birdi. Koşum üç ayrı sonuç
verdi. Üretim açılışta reddedildi: bu, eksikliğin en ucuz biçimidir, çünkü hata dağıtımı yapan
kişinin gözü ekrandayken görünür. Geliştirme ve sınama açıldı ve hata gece üçte, gecelik toplu
işin ortasında çıktı. Eksiklik aynı, bedeli değil — **farkı yaratan tek şey açılış denetimi
listesinin uzunluğudur.** `imzaAnahtari` o listede olmadığı için üç ortamda da geç patlar.

Çıktıda ölçümün konusu olmayan iki fark daha yazılı. Kütük düzeyi iki ortamda ayrıntı, üretimde
özettir. Yalnız üretimde görünen bir yolun kaydı, yalnız üretimde kısılmış bir kütükle tutuluyor:
fark, ürettiği hatayı görecek sinyali de aynı ortamda kısar. Gecelik toplu işin eş zamanlılığı
ise iki, dört ve on altıdır. Sınamada dört koşucuyla geçen bir yarış durumu üretimde on altı
koşucuyla ilk gecede görünür. Bu bildirilmiş bir farktır, dosyada yazılıdır — ama bildirilmiş
olması sınandığı anlamına gelmez.

Bu üç değeri kimin değiştirdiği de ayrı bir sorudur. Havuz büyüklüğü, eş zamanlılık ve kütük
düzeyi işleten ekibin elindedir ve genellikle bir olaydan sonra değişir; doğrulama eşiği ile
ödeme biçimi yazan ekibin kararıdır. İkisi aynı dosyada durduğu için değişiklikler aynı görünür
ve hangi farkın hangi ekipten geldiği ancak dosya geçmişine bakılarak ayrılır.

#### Sırrın Dört Çıkış Yolu

Sır da ortamdan ortama değişen bir değerdir ve buraya kadarki sayıma dahildir. Ayrı sayılmasının
nedeni tek bir asimetridir: yanlış bir bağlantı noktası düzeltilir, sızmış bir sır düzeltilemez;
yalnız değiştirilebilir ve değiştirilene kadar geçerli kalır. Sızabileceği dört yüzey aşağıda
kurgu içerikle diske yazılır.

```bash
#!/usr/bin/env bash
# Dort yuzey: yapi ciktisi, gunluk, hata iletisi, surum deposuna islenmis dosya dizini.
set -e
mkdir -p yapi kutuk hata

cat > yapi/paket.mjs <<'SON'
// Yapi cikti dosyasi (kurgu): kaynak, uretim degerleriyle birlikte tek dosyaya toplandi.
const ayar = {
  adres: "olcum-uretim.ic:5432",
  OLCUM_VERI_PAROLA: "kurgu-ure-h3m8",
  imza: "kurgu-imza-" + "9c1e",
};
export const baglan = () => ayar;
SON

cat > kutuk/gecelik.jsonl <<'SON'
{"an":"03:12:04","olay":"toplu_is_basladi","ortam":"uretim","sayac":48210}
{"an":"03:12:04","olay":"veri_baglantisi","baglanti":"olcum:kurgu-ure-h3m8@olcum-uretim.ic:5432"}
{"an":"03:12:05","olay":"ayar_ozeti","OLCUM_VERI_PAROLA":"****","KUTUK_DUZEYI":"ozet"}
{"an":"04:41:19","olay":"fatura_imzalandi","imzaB64":"a3VyZ3UtaW16YS05YzFl","adet":48210}
SON

cat > hata/son-hata.txt <<'SON'
Yakalanmayan hata: fatura imzasi dogrulanamadi (gecelik toplu is, uretim)
  istek : POST /fatura/imzala?imza=kurgu-imza-9c1e
  ayar  : { ortam: 'uretim', OLCUM_VERI_PAROLA: 'kurgu-ure-h3m8', havuz: 32 }
  yigin : toplu-is.mjs:118 -> imzala.mjs:42
SON

cat > depo-dizini.txt <<'SON'
kaynak/ayar.mjs
yapilandirma/ornek.env
yapilandirma/uretim.env
paket.json
SON
```

Tarayıcının iki kuralı vardır: sır değerinin birebir eşleşmesi ve sır anahtarı ad kalıbı.

```js
// tarayici.mjs — dort yuzeyde sir arar; kural=deger birebir esleme, kural=ad ad kalibi.
import { readFileSync } from "node:fs";

const YUZEY = { yapi: "yapi/paket.mjs", kutuk: "kutuk/gecelik.jsonl",
                hata: "hata/son-hata.txt", depo: "depo-dizini.txt" };
const AD_KALIBI = /PAROLA|ANAHTAR|\.env$/;

const degerler = ["gelistirme", "sinama", "uretim"]              // uc dosyadaki sir degerleri
  .flatMap((a) => readFileSync(`yapilandirma/${a}.env`, "utf8").split("\n").filter(Boolean))
  .filter((s) => AD_KALIBI.test(s.slice(0, s.indexOf("="))))
  .map((s) => s.slice(s.indexOf("=") + 1));

const bulgu = [];
for (const [ad, yol] of Object.entries(YUZEY))
  readFileSync(yol, "utf8").split("\n").filter(Boolean).forEach((satir, i) => {
    const kural = [degerler.some((d) => satir.includes(d)) && "deger",
                   AD_KALIBI.test(satir.trim()) && "ad"].filter(Boolean);
    if (kural.length) bulgu.push({ ad, satirNo: i + 1, satir, kural: kural.join("+") });
  });

// Yerlestirilmis sizintilar: yuzey adi + o satirin ayirt edici izi.
const YERLESIK = [["yapi", "OLCUM_VERI_PAROLA:"], ["yapi", 'imza: "kurgu-imza-'],
  ["kutuk", '"baglanti"'], ["kutuk", '"imzaB64"'], ["hata", "OLCUM_VERI_PAROLA:"],
  ["hata", "imza=kurgu"], ["depo", "uretim.env"]];

const eslesen = (b) => YERLESIK.some(([y, iz]) => y === b.ad && b.satir.includes(iz));
const kacan = YERLESIK.filter(([y, iz]) => !bulgu.some((b) => b.ad === y && b.satir.includes(iz)));

console.log(`sir degeri: ${degerler.length}   yuzey: ${Object.keys(YUZEY).length}   ` +
  `yerlestirilen sizinti: ${YERLESIK.length}   bildirilen satir: ${bulgu.length}`);
console.log(`yakalanan: ${YERLESIK.length - kacan.length}   kacan: ${kacan.length}   ` +
  `yanlis alarm: ${bulgu.filter((b) => !eslesen(b)).length}`);
for (const b of bulgu)
  console.log(`  [${eslesen(b) ? "gercek" : "YANLIS"}] ${b.ad}:${b.satirNo}  kural=${b.kural}`);
for (const [y, iz] of kacan) console.log(`  [KACAN ] ${y}  iz=${iz}`);
```

```
sir degeri: 4   yuzey: 4   yerlestirilen sizinti: 7   bildirilen satir: 7
yakalanan: 5   kacan: 2   yanlis alarm: 2
  [gercek] yapi:4  kural=deger+ad
  [gercek] kutuk:2  kural=deger
  [YANLIS] kutuk:3  kural=ad
  [gercek] hata:2  kural=deger
  [gercek] hata:3  kural=deger+ad
  [YANLIS] depo:2  kural=ad
  [gercek] depo:3  kural=ad
  [KACAN ] yapi  iz=imza: "kurgu-imza-
  [KACAN ] kutuk  iz="imzaB64"
```

#### Yakalanan, Kaçan, Yanlış Alarm

Tarayıcı yedi satır bildirdi, yerleştirilmiş sızıntı da yedi. **Sayılar eşit, kümeler değil.**
Bu eşitlik, bir tarama raporunun toplamına bakarak kapsama karar veren her okuma için uyarıdır.

Kaçan iki sızıntının ortak yanı, sır değerinin aranan biçimde durmamasıdır. Biri birleştirmeyle
ikiye bölünmüş (`"kurgu-imza-" + "9c1e"`), öteki taban altmış dörde çevrilmiş
(`a3VyZ3UtaW16YS05YzFl`). İkisi de aynı sırrı taşır, ikisi de değer eşleme kuralının dışında
kalır. Bunun genel biçimi şudur: **birebir değer araması, değeri dönüştüren her adımın gerisinde
kalır** — yapı aracının satır birleştirmesi, günlük yazıcısının kodlaması, ileti biçimlendiricinin
kısaltması. Yakalanan beş sızıntının hepsi değerin olduğu gibi durduğu satırlardır.

Yakalama oranını yükseltmenin yolu bellidir: aranan değerin dönüşmüş biçimleri de üretilir —
kodlanmış hâli, kısaltılmış hâli, parçalarının her biri — ve hepsi ayrı ayrı aranır. Bunun
bedeli doğrudan yanlış alarma yazılır: değer kısaldıkça rastgele eşleşme olasılığı büyür ve
`9c1e` gibi dört karakterlik bir parça normal metinde de bulunur. İki kural arasındaki ilişki
budur; kaçanı azaltan her genişletme yanlış alarmı artırır ve iki sayı ayrı ayrı yazılmadıkça
hangisinin arttığı görünmez.

Yanlış alarmların ikisi de ad kuralından gelir ve ikisi de **doğru davranışın kendisidir**:
maskelenmiş kütük satırı sırrı gizlemek için yazılmıştır, örnek yapılandırma dosyası ise
sürüm deposunda bulunması gereken şeydir. Bedeli sayısal değil davranışsaldır. İki yanlış alarm
listeye girdiğinde listeyi okuyan kişi bir sonraki taramada satırlara tek tek bakmaz; kaçan iki
sızıntının bulunma olasılığı, yanlış alarmların sayısıyla birlikte düşer.

Dört yüzeyin sahipleri de ayrıdır: yapı çıktısı derleme adımının, günlük işletimin, hata iletisi
uygulama kodunun, depo dizini sürüm kontrolünün alanındadır. Bir yüzeyde sızıntı kapatıldığında
ötekiler açık kalır, çünkü kapatan kişi yalnız kendi yüzeyini görür. Sayının burada verdiği karar
şudur: sır ayrımı tek bir yerde alınan bir karar değil, dört ayrı yüzeyde ayrı ayrı korunan bir
sınırdır.

#### Özet

- Üç ortam dosyasındaki on dört anahtarın altısı gerçekten değişiyor; farkın saklandığı yer bu
  altı satırdır. Beş anahtar üç ortamda da aynı değeri taşıyor, yani yapılandırma değil sabit.
- Üç anahtar en az bir ortamda eksik; zorunlu altı anahtardan biri her ortamda tanımsız kalıyor.
  Üretimde eksik olan iş emri adresi yalnız üretimde patlar, yalnız üretimde tanımlı imza anahtarı
  ise imzalama yolunu üretim dışında hiç koşturmaz.
- Koşumda aynı sayı üç ayrı sonuç verdi: üretim açılışta reddedildi, öteki iki ortam açıldı ve
  gece üçte toplu işin ortasında düştü. Farkı yaratan şey açılış denetimi listesinin uzunluğudur.
- Bildirilmiş fark dosyalardaki altı satırdır; yalnız koşumda görünen fark, kaynağa gömülü
  varsayılanla tanımlanan dördüncü ortam (`YENIDEN_OKUMA_GUN`) ve hiçbir kodun okumadığı ölü
  anahtardır (`SINAMA_TOHUMU`).
- Dört yüzeye yerleştirilen yedi sızıntıdan beşi yakalandı, ikisi kaçtı; kaçanların ikisi de
  değerin dönüştürülmüş hâliydi (birleştirme ve taban altmış dört).
- Tarayıcı yedi satır bildirdi, sızıntı da yedi taneydi; ikisi yanlış alarmdı ve ikisi de doğru
  davranışı işaretliyordu. Toplam sayının eşitliği kapsama kanıtı değildir.

#### Sonraki Adım

Yapılandırmanın ortamda durması tek başına duran bir kural değil, birbirine bağlı bir kümenin
üyesidir; bu ders o kümenin bir üyesini ölçtü ve ölçerken kuralın kaynağa gömülü varsayılanla
sessizce kırıldığını gördü. Kümenin tamamı **Sunucu Tarafı Temelleri** kursunda adlarıyla
kurulmuştu. Sonraki ders o adları tekrarlamak yerine tek bir soru sorar: her ilke, diskteki
dosyalar üzerinde koşan bir denetime çevrilebiliyor mu? Çevrilebilenler kurgu uygulamanın gerçek
dosyaları üzerinde koşturulur, yakalananla kaçan ayrı sayılır; çevrilemeyenler için de yerine ne
konduğu yazılır.

### On İki Etmen Uygulama

Source: https://academia.sh/tr/kurslar/devops-temelleri/on-iki-etmen-uygulama

On iki ilkenin sekizi diskteki dosyalara bakıp karar veren koşturulabilir bir denetime çevrilir ve kurgu bir uygulamanın gerçek dosyaları üzerinde koşturulur; yerleştirilmiş sekiz kusurdan kaçının yakalandığı, kaçının kaçtığı ve kaç yanlış alarm verildiği sayılır, çevrilemeyen dört ilkenin yerine ne konduğu yazılır.

On iki etmen uygulama ilkeleri, uygulamayı yazan ile onu çalıştıran arasındaki sözleşmeyi
adlandırır. İlkelerin ne söylediği **Sunucu Tarafı Temelleri** kursunda kurulmuştu ve burada
tekrarlanmaz. Bu dersin sorusu başkadır: bir ilke, diskteki dosyalara bakıp evet ya da hayır
diyen **koşturulabilir bir denetime** çevrilebiliyor mu? Çevrilebiliyorsa denetim neyi yakalıyor,
neyi kaçırıyor, neye boş yere alarm veriyor? Çevrilemiyorsa yerine ne konuyor?

Bir ilkenin karar taşıması, cümlesinin doğru görünmesine değil, ihlal edildiğinde birinin bunu
göreceğine bağlıdır. Denetime çevrilemeyen ilke ancak biri bakmayı akıl ettiğinde görünür ve akıl
edilmesi gereken bakış, ölçülmemiş bakıştır. Ölçüm yine **bölgesel ölçüm ağı** üzerinde yapılır:
su sayacı okumalarını toplayan, doğrulayan, faturaya çeviren ve saha iş emri açan **kurgu** bir
yazılım. Aşağıdaki dosya ağacı gerçekten diske yazılır, denetleyici gerçekten koşar; dosyaların
ve bağımlılık adlarının tamamı kurgudur.

**DK23.** Denetleyici yalnız diskteki dosya ağacını görür; depo geçmişini, işletim adımlarını ve
ekip alışkanlıklarını görmez.
**DK24.** Bir ilke, tek bir ağaç üzerinde tek bir koşumda ikili karar üretebiliyorsa çevrilebilir
sayılır; karar için ikinci bir ortam, ikinci bir süreç ya da insan yorumu isteyen ilke çevrilemez
sayılır.
**DK25.** Kusurlar taramadan önce bilerek yerleştirilir ve sayıları bilinir; kaçanın sayılabilmesi
buna bağlıdır.
**DK26.** Denetimlerin tamamı dizgi ve dosya düzeyindedir; sözdizim ağacı çözümlemesi yoktur.
Kaçan kusurların sınıfı doğrudan bu seçimden doğar.

#### Denetime Çevrilen Sekiz İlke

Aşağıdaki tablo ilkenin ne söylediğini değil, ilkenin **diskte neye baktığını** yazar.

| İlke | Denetimin baktığı şey | Kararı veren |
|---|---|---|
| Bağımlılıklar | bildirim dosyasının yanında kilit dosyası var mı | dosya varlığı |
| Yapılandırma | kaynakta gömülü varsayılan ve gömülü sunucu adresi | `??` kalıbı, adres kalıbı |
| Bağlantı noktası bağlama | kaynak kendi soketini açıyor mu | `.listen(` çağrısı |
| Kütükler | kütük standart çıktı yerine dosyaya mı yazılıyor | dosya yazma çağrısı |
| Tek kullanımlık olma | bildirilen her giriş noktası kapanma sinyalini işliyor mu | `SIGTERM` dizgesi |
| Süreçler | süreç belleğinde kalıcı durum tutuluyor mu | üst düzey değişebilir kap |
| Derle, yayımla, çalıştır | yapı çıktısına ortam değeri gömülmüş mü | adres kalıbı |
| Yönetim süreçleri | tek seferlik iş uygulamanın kodunu kullanıyor mu | içe aktarım yolu |

Sekizinin ortak yanı, kararın tek bir ağaçtan okunabilmesidir. Kalan dört ilke bu tabloya
girmedi; nedenleri ölçümden sonra sayılır.

Üçüncü sütun, tablonun asıl bilgisini taşır. İlke bir niyet cümlesidir; denetim ise bir metin
kalıbıdır. Aradaki çeviri her satırda bir daraltmadır: "kütükler bir olay akışıdır" cümlesi
"kaynak dizininde dosya yazma çağrısı bulunmasın" kuralına indirgenir, "süreçler durumsuzdur"
cümlesi "üst düzeyde değişebilir kap bildirilmesin" kuralına. Daraltma iki yönde de kayıp
üretir. Kural ilkeden dar kaldığı yerde kusur kaçar; ilkenin kapsamadığı bir dosyaya uzandığı
yerde yanlış alarm doğar. Aşağıdaki sayılar bu iki kaybın ikisini de ayrı ayrı ölçer, çünkü
tek bir "geçti / kaldı" toplamı hangi yönde kaybedildiğini söylemez.

#### Kurgu Uygulamanın Dosyaları

```bash
#!/usr/bin/env bash
# Kurgu olcum agi uygulamasinin dosya agacini diske yazar. Bagimlilik adlari da kurgudur.
set -e
mkdir -p kaynak sinama betik yapi

cat > paket.json <<'SON'
{ "ad": "olcum-agi", "tur": "modul",
  "girisler": ["kaynak/sunucu.mjs", "betik/gecelik-duzeltme.mjs"],
  "bagimlilik": { "olcum-cozumleyici": "2.4.0", "fatura-bicimleyici": "1.1.3" } }
SON

cat > kaynak/ayar.mjs <<'SON'
export const ayar = {
  ortam: process.env.ORTAM_ETIKETI,
  veriAdresi: process.env.OLCUM_VERI_ADRESI,
  baglantiNoktasi: Number(process.env.OLCUM_BAGLANTI_NOKTASI),
  yenidenOkumaGun: Number(process.env.YENIDEN_OKUMA_GUN ?? 30),
};
SON

cat > kaynak/sunucu.mjs <<'SON'
import { createServer } from "node:http";
import { ayar } from "./ayar.mjs";
export const sunucu = createServer((istek, yanit) => yanit.end(ayar.ortam ?? "yok"));
sunucu.listen(ayar.baglantiNoktasi);
SON

cat > kaynak/kutuk.mjs <<'SON'
import { appendFileSync } from "node:fs";
export const kutuk = (k) => appendFileSync("/var/kutuk/olcum.log", JSON.stringify(k) + "\n");
SON

cat > kaynak/rapor.mjs <<'SON'
import { writeFileSync } from "node:fs";
export const faturayiYaz = (f) => writeFileSync(`cikti/fatura-${f.no}.json`, JSON.stringify(f));
SON

cat > kaynak/toplu-is.mjs <<'SON'
const IS_EMRI_ADRESI = "is-emri-uretim.ic:8081";
export const kuyruk = (() => {
  const bekleyen = new Map();
  return { ekle: (id, v) => bekleyen.set(id, v), sayi: () => bekleyen.size, IS_EMRI_ADRESI };
})();
SON

cat > sinama/sahte-olcum.mjs <<'SON'
// Surec ici sahte olcum deposu; adres gercek bir hedefe gitmez.
export const sahteAdres = "127.0.0.1:5432";
SON

cat > betik/gecelik-duzeltme.mjs <<'SON'
const ADRES = process.env.OLCUM_VERI_ADRESI;
console.log(`duzeltme calisti -> ${ADRES}`);
SON

cat > yapi/paket.mjs <<'SON'
// Yapi cikti dosyasi (kurgu): uretim adresi derleme aninda gomuldu.
export const HEDEF = "olcum-uretim.ic:" + 5432;
SON
```

Bu ağaca sekiz kusur yerleştirilmiştir. Sayıları denetleyicinin içinde yazılı olduğu için kaçan
da sayılabilir; denetimlerin hiçbiri o listeyi okumaz.

#### Koşum

```js
// denetim.mjs — cevrilebilen ilkeleri kurgu uygulamanin gercek dosyalari uzerinde kosturur.
import { readFileSync, existsSync } from "node:fs";

const DOSYA = ["paket.json", "kaynak/ayar.mjs", "kaynak/sunucu.mjs", "kaynak/kutuk.mjs",
  "kaynak/rapor.mjs", "kaynak/toplu-is.mjs", "sinama/sahte-olcum.mjs",
  "betik/gecelik-duzeltme.mjs", "yapi/paket.mjs"];
const metin = Object.fromEntries(DOSYA.map((y) => [y, readFileSync(y, "utf8")]));
const alt = (on) => DOSYA.filter((y) => y.startsWith(on));
const ara = (kapsam, kalip) => kapsam
  .flatMap((y) => metin[y].split("\n").map((s, i) => ({ yol: y, satirNo: i + 1, satir: s })))
  .filter((b) => kalip.test(b.satir));
const not = (yol, satir) => ({ yol, satirNo: 0, satir });
const ADRES = /["'][\w.-]+:\d{4,5}["']/;

const DENETIM = [
  ["bagimliliklar", () => existsSync("paket.kilit") ? [] : [not("paket.json", "paket.kilit yok")]],
  ["yapilandirma", () => [...ara(alt("kaynak/"), /process\.env\.\w+\s*\?\?/),
    ...ara([...alt("kaynak/"), ...alt("sinama/"), ...alt("betik/")], ADRES)]],
  ["baglanti-noktasi", () => ara(alt("kaynak/"), /\.listen\(/).length
    ? [] : [not("kaynak/", "listen cagrisi yok")]],
  ["kutukler", () => ara(alt("kaynak/"), /(appendFileSync|writeFileSync|createWriteStream)\(/)],
  ["tek-kullanimlik", () => JSON.parse(metin["paket.json"]).girisler
    .filter((y) => !metin[y].includes("SIGTERM")).map((y) => not(y, "SIGTERM isleyicisi yok"))],
  ["surecler", () => ara(alt("kaynak/"), /^(const|let|var)\s+\w+\s*=\s*new (Map|Set)\(/)],
  ["derle-yayimla-calistir", () => ara(alt("yapi/"), ADRES)],
  ["yonetim-surecleri", () => alt("betik/").filter((y) => !metin[y].includes("kaynak/"))
    .map((y) => not(y, "kaynak/ altindan ice aktarim yok"))],
];

const YERLESIK = [                                   // taramadan once yerlestirilen kusurlar
  ["paket.json", "paket.kilit"], ["kaynak/ayar.mjs", "?? 30"],
  ["kaynak/toplu-is.mjs", "is-emri-uretim.ic"], ["kaynak/kutuk.mjs", "appendFileSync"],
  ["kaynak/sunucu.mjs", "SIGTERM"], ["kaynak/toplu-is.mjs", "new Map("],
  ["yapi/paket.mjs", "olcum-uretim.ic:"], ["betik/gecelik-duzeltme.mjs", "kaynak/"],
];

const bulgu = DENETIM.flatMap(([ad, f]) => f().map((b) => ({ ...b, denetim: ad })));
const gercek = (b) => YERLESIK.some(([y, iz]) => y === b.yol && b.satir.includes(iz));
const kacan = YERLESIK.filter(([y, iz]) => !bulgu.some((b) => b.yol === y && b.satir.includes(iz)));
const yanlis = bulgu.filter((b) => !gercek(b));

const satir = (a, b, c, d) => a.padEnd(24) + b.padStart(6) + c.padStart(8) + d.padStart(8);
console.log(satir("denetim", "bulgu", "gercek", "yanlis"));
for (const [ad, f] of DENETIM) {
  const b = f();
  console.log(satir(ad, `${b.length}`, `${b.filter(gercek).length}`,
    `${b.filter((x) => !gercek(x)).length}`));
}
console.log(`cevrilebilen ilke: ${DENETIM.length}   cevrilemeyen: ${12 - DENETIM.length}`);
console.log(`yerlestirilen kusur: ${YERLESIK.length}   bildirilen bulgu: ${bulgu.length}`);
console.log(`yakalanan: ${YERLESIK.length - kacan.length}   kacan: ${kacan.length}   ` +
  `yanlis alarm: ${yanlis.length}`);
for (const [y, iz] of kacan) console.log(`  [KACAN ] ${y}  iz=${iz}`);
for (const b of yanlis) console.log(`  [YANLIS] ${b.yol}:${b.satirNo}  denetim=${b.denetim}`);
```

```
denetim                  bulgu  gercek  yanlis
bagimliliklar                1       1       0
yapilandirma                 3       2       1
baglanti-noktasi             0       0       0
kutukler                     2       1       1
tek-kullanimlik              2       1       1
surecler                     0       0       0
derle-yayimla-calistir       0       0       0
yonetim-surecleri            1       1       0
cevrilebilen ilke: 8   cevrilemeyen: 4
yerlestirilen kusur: 8   bildirilen bulgu: 9
yakalanan: 6   kacan: 2   yanlis alarm: 3
  [KACAN ] kaynak/toplu-is.mjs  iz=new Map(
  [KACAN ] yapi/paket.mjs  iz=olcum-uretim.ic:
  [YANLIS] sinama/sahte-olcum.mjs:2  denetim=yapilandirma
  [YANLIS] kaynak/rapor.mjs:2  denetim=kutukler
  [YANLIS] betik/gecelik-duzeltme.mjs:0  denetim=tek-kullanimlik
```

#### Yakalanan, Kaçan, Yanlış Alarm

Sekiz kusurdan altısı yakalandı, ikisi kaçtı ve denetimler üç yanlış alarm verdi. Tabloda okunması
gereken asıl satırlar sıfır bildirenlerdir. `baglanti-noktasi` sıfır bulgu bildirdi ve haklıydı:
kaynak kendi soketini açıyor. `surecler` ile `derle-yayimla-calistir` de sıfır bildirdi ve
**ikisi de yanılıyordu** — kusur her ikisinde de yerindeydi. **Sıfır bulgu kusursuzluğu değil,
kuralın kapsamını ölçer** ve tablo bu iki durumu aynı biçimde yazar.

Kaçan iki kusurun sınıfı ortaktır. `toplu-is.mjs` süreç belleğinde bir eşleme tutuyor, ama eşleme
bir kapanışın içinde: kural üst düzey bir bildirim arıyor, kap ise iki boşluk içeride. Yapı
çıktısındaki üretim adresi ise derleme anında birleştirilmiş (`"olcum-uretim.ic:" + 5432`), yani
adres kalıbının aradığı biçimde hiç durmuyor. İkisi de dizgi düzeyinde çalışan bir kuralın yapı
düzeyinde duran bir olguyu göremediği örneklerdir; bir önceki dersin sır tarayıcısı da tam bu
sınıfı kaçırmıştı. Bu, denetimlerin dikkatsizliği değil, DK26'nın doğrudan sonucudur — kural
dizgiye bakar, kusur ağaca yerleşir.

Üç yanlış alarmın üçü de **doğru davranışı** işaretledi. Sınama düzeneğindeki sabit adres, süreç
içinde kalan sahte bir depoya işaret ediyor; orada yapılandırmadan okumak anlamsızdır. Fatura
dosyası yazan çağrı bir kütük değil, ürünün kendisidir. Gecelik düzeltme betiği tek seferlik bir
iştir ve kapanma sinyali işlemesi gerekmez. Üçü de kuralın **kapsamı** ile ilkenin **konusu**
arasındaki açıklıktan doğuyor: kural dosyaya bakıyor, ilke ise o dosyanın ne işe yaradığını
soruyor.

Yanlış alarmın bedeli, kaçanın bedeliyle aynı yöne çalışır. Dokuz satırlık bir raporun üçü boşsa,
raporu ikinci kez okuyan kişi satırları tek tek açmaz; kaçan iki kusurun bulunma olasılığı da bu
noktada düşer. Bir denetim kümesini değerlendiren tek sayı yoktur — yakalanan, kaçan ve yanlış
alarm ayrı ayrı yazılmadıkça hangisinin arttığı görünmez.

#### Kaçanın Koşumdaki Karşılığı

Kaçan iki kusur denetim tablosunda yalnız birer boşluktu. Boşluğun neye karşılık geldiğini görmek
için ikisi de aynı süreçte çalıştırılır.

```js
// kacan.mjs — denetimin goremedigi iki kusuru kosumda gosterir.
import { kuyruk } from "./kaynak/toplu-is.mjs";
import { HEDEF } from "./yapi/paket.mjs";

kuyruk.ekle("sayac-1041", 3120);                    // birinci okuma paketi
kuyruk.ekle("sayac-2277", 8840);                    // ikinci paket, ayni surec
console.log(`ORTAM_ETIKETI          : ${process.env.ORTAM_ETIKETI}`);
console.log(`kuyrukta kalan kayit   : ${kuyruk.sayi()}`);
console.log(`yapi ciktisinin hedefi : ${HEDEF}`);
```

```bash
#!/usr/bin/env bash
# Ayni yapi ciktisini iki ortam etiketiyle kosturur.
for o in sinama uretim; do ORTAM_ETIKETI="$o" node kacan.mjs; done
```

```
ORTAM_ETIKETI          : sinama
kuyrukta kalan kayit   : 2
yapi ciktisinin hedefi : olcum-uretim.ic:5432
ORTAM_ETIKETI          : uretim
kuyrukta kalan kayit   : 2
yapi ciktisinin hedefi : olcum-uretim.ic:5432
```

Kuyrukta iki kayıt kaldı. İkinci okuma paketi, birincinin süreç belleğinde bıraktığını buldu.
Süreç yeniden başladığında bu kayıtlar yok olur; ölçek değiştiğinde ikinci sürecin kuyruğu boş
başlar ve iki süreç aynı gecelik işi iki farklı durumla koşar. Denetimin göremediği kusur,
koşumda bir sayı olarak görünüyor.

İkinci satır daha keskindir. Ortam etiketi sınamayken de üretimken de yapı çıktısının hedefi
aynı kalıyor: üretim veri deposunun adresi. **Yapı çıktısı ortamı taşıyor, ortam yapı çıktısını
değil.** Sınama ortamında koşan bir gecelik toplu iş üretim verisine bakar ve bunu hiçbir
yapılandırma dosyası bildirmez, çünkü fark yapılandırmada değil, derleme anında alınmış bir
kararda saklıdır. Bir önceki dersin ortam farkı sayımı bu değeri hiç göremezdi; sayılan şey
yapılandırma dosyalarıydı ve bu adres onların hiçbirinde geçmiyor.

Bu, kursun kuralının en dar biçimidir. Aynı yazılım iki ortamda başka davranmadı — **aynı
davrandı** ve sorun tam olarak budur. Ortam etiketi değişti, davranış değişmedi; fark, ortam
değişkeninin erişemeyeceği bir yere gömüldüğü için ortamın onu değiştirme yetkisi kalmadı.
Denetim tablosundaki `derle-yayimla-calistir` satırının sıfırı, bu farkın üstünü örten şeydi.

İki kusuru da yakalamanın yolu bellidir: kural dizgiye değil, çözümlenmiş bir sözdizim ağacına
bakar; kapanış içindeki bildirimi ve derleme anında birleştirilen değeri ancak o düzeyde görür.
Bedeli DK26'nın kaldırılmasıdır — denetim artık dosyayı okumakla kalmaz, dili de çözümlemek
zorundadır. Sekiz denetimin ucuzluğu bu seçimden geliyordu; ucuzluk kaybedilince denetimin sık
koşma özelliği de tartışmaya açılır.

#### Çevrilemeyen Dört İlkenin Yerine

| İlke | Tek ağaçta neden ölçülemez | Yerine konan |
|---|---|---|
| Kod tabanı | tek kod tabanından kaç dağıtım çıktığı depo düzeyinde bir olgudur; ağaç tek bir dağıtımı gösterir | yapı çıktısının taşıdığı kaynak kimliğinin dağıtım kayıtlarında eşleşmesi |
| Destekleyici servisler | adresin yapılandırmadan geldiği denetlenir, ama kaynağın değiştirilebilir olduğu ancak değiştirilerek görülür | adres değiştirilip koşumun yinelenmesi |
| Eşzamanlılık | süreç modeliyle ölçeklendiği tek süreçlik bir ağaçtan okunamaz | iki süreçle yük altında koşum ve süreç sayısıyla değişmeyen çıktı |
| Geliştirme/üretim eşliği | iki ortamın karşılaştırılmasını ister; ağaç tek ortamdır | bir önceki dersin ortam farkı sayımı |

Dördünün ortak yanı, karar için **ikinci bir gözlem** istemeleridir: ikinci bir dağıtım, ikinci
bir adres, ikinci bir süreç, ikinci bir ortam. Sınır tam buradan geçiyor ve adı **tek gözlemle
karar verilebilirlik**tir. Sekiz denetim tek ağaçta karar verdi; dördü karşılaştırma istedi.

Bu ayrım maliyeti de belirler. Sekiz denetim her değişiklikte saniyeler içinde koşar; kalan dördü
ayrı bir ortam, ayrı bir koşum ya da yük üreten bir düzenek ister. Ucuz olan sık koşulur, pahalı
olan seyrek — ve seyrek koşan ölçümün yakaladığı kusur yakalandığında çoktan üretime gitmiştir.
Bir önceki dersin ortam farkı sayımı, dört pahalı ilkeden birinin yerine konan şeydi ve bu
dersteki hiçbir denetim onun yerini tutmuyor.

Maliyet farkı sahiplik farkını da getirir. Sekiz ucuz denetim yazan ekibin elindedir; kod
değiştiği anda koşar ve sonucunu değiştiren kişi görür. Dört pahalı ölçüm ise ikinci ortamı,
ikinci süreci ya da yük düzeneğini elinde tutan işleten ekibin alanına düşer. Aynı ilke kümesinin
yarısı bir ekipte, yarısı ötekinde ölçülüyor; ihlalin hangi ekibe göründüğü, ihlalin türüne göre
değişiyor. Ölçüm ağının iki ekibi arasındaki sinyal farkı bu bölünmeden doğar.

#### Özet

- On iki ilkenin sekizi tek bir dosya ağacında karar veren denetime çevrildi, dördü çevrilemedi;
  ayıran ölçüt tek gözlemle karar verilebilirliktir.
- Yerleştirilen sekiz kusurdan altısı yakalandı, ikisi kaçtı; denetimler dokuz bulgu bildirdi ve
  üçü yanlış alarmdı.
- Sıfır bulgu bildiren üç denetimden biri haklıydı, ikisi yanılıyordu. Sıfır bulgu kuralın
  kapsamını ölçer, kusursuzluğu değil.
- Kaçan iki kusur da aynı sınıftan: kural dizgiye bakıyor, kusur yapıya yerleşiyor — kapanış
  içindeki durum ve derleme anında birleştirilen adres. Koşumda ikisi de göründü: süreç belleğinde
  iki kayıt kaldı, yapı çıktısının hedefi iki ortam etiketinde de üretim adresi çıktı.
- Üç yanlış alarmın üçü de doğru davranışı işaretledi; kuralın kapsamı ile ilkenin konusu
  arasındaki açıklıktan doğdular.
- Çevrilemeyen dört ilkenin yerine konan şeylerin hepsi ikinci bir gözlem ister; bu yüzden seyrek
  koşarlar ve yakaladıkları kusur geç yakalanır.

#### Sonraki Adım

Çevrilemeyen dört ilkenin dördü de ikinci bir gözlem istedi ve ikisi bu gözlemin adını doğrudan
koydu: ikinci bir ortam. Buraya kadar ortamların var olduğu varsayıldı — geliştirme, sınama ve
üretim vardı, aralarındaki fark sayıldı, aynı ağaç üzerinde denetimler koşturuldu. Ortamın
kendisinin **nasıl var olduğu** ise hiç sorulmadı. Elle mi kuruluyor, bir betik mi kuruyor, yoksa
istenen son durumu bildiren bir tanım mı? Sonraki ders bu üç biçimi karşılaştırır ve aynı soruyu
sorar: aynı tanımdan iki kez kurulan iki ortam arasında kaç fark kalıyor ve o fark nerede
saklanıyor?

### Altyapı Sağlama Modelleri

Source: https://academia.sh/tr/kurslar/devops-temelleri/altyapi-saglama-modelleri

Aynı ortam elle, betikle ve bildirimsel olarak kurulur; iki kurulum arasındaki fark, betiğin ikinci koşumda ve yarıda kaldığında bıraktığı durum ve altı dönem boyunca biriken yapılandırma sapması sayılır. Çalışan bir uzlaştırıcı istenen durumu dosyadan, gerçek durumu diskten okur, farkı kapatır ve ikinci koşumda sıfır iş yapar.

Bir önceki ders on iki ilkeyi denetime çevirdi ve dördünün karar için ikinci bir gözlem — çoğu
zaman ikinci bir ortam — istediğini yazdı. Uygulamanın kendisi artık denetlenebilir durumda:
bağımlılığı bildirilmiş, yapılandırması dışarıda, kapanışı sınanabilir. Altında durduğu makine
ise hâlâ elle kuruluyor ve o makinenin nasıl kurulduğu hiçbir denetimin kapsamında değil.

**Sağlama**, bir ortamı istenen duruma getirme işidir: paketlerin kurulması, ayarların yazılması,
dizinlerin açılması. Üç biçimi vardır — **elle**, **betikle**, **bildirimsel** — ve aralarındaki
ayrım hız değil, **aynı tariften kaç ayrı sonuç doğduğu**dur. Bu ders aynı ortamı üçünde de kurar
ve üç sayıyı ölçer: kurulum adımı, iki kurulum arasındaki fark ve yapılandırma sapmasının
dönemler boyunca ne kadar büyüdüğü.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir: su sayacı okumalarını toplayan, doğrulayan ve saha
iş emri açan **kurgu** yazılım. Dosyalar gerçekten diske yazılır, betikler ve uzlaştırıcı
gerçekten koşar.

**DK27.** Ortam yedi kalemle temsil edilir — iki paket sürümü, üç ayar, iki dizin.
**DK28.** Elle kurulumun yönergesi düzyazıdır ve yedi adımın üçü sayı vermez; iki elin yorumu bu
üç adımda ayrılır. **El bir modeldir**, yorumu önceden yazılıdır.
**DK29.** Betik yedi adımı sırayla koşar, hiçbir adım önce durumu okumaz; yarıda kalma noktası bir
ortam değişkeniyle tetiklenir.
**DK30.** Bildirimsel modelde istenen durum bir dosyadır; uzlaştırıcı gerçek durumu diskten okur
ve yalnız farklı kaleme dokunur.
**DK31.** Sapma taramasında altı dönem koşulur ve her dönemde bir elle müdahale yapılır;
müdahaleler önceden yazılıdır, rastgelelik yoktur.

#### Üç Model, Aynı Yedi Kalem

```bash
#!/usr/bin/env bash
# Ayni ortamin uc ayri tarifi: bildirim, duzyazi yonerge ve saglama betigi.
set -e

cat > istenen.json <<'SON'
{ "paket/cozumleyici": "3.4.0", "paket/kural-paketi": "9.1.0",
  "ayar/kutuk-duzeyi": "ozet", "ayar/es-zamanli-isci": "8",
  "ayar/toplu-is-baslangic": "02:30", "dizin/veri": null, "dizin/kutuk": null }
SON

cat > tarif-elle.txt <<'SON'
1. paket dizinini ac, cozumleyicinin 3.4.0 surumunu kur
2. kural paketini 9.1.0 surumune sabitle
3. kutuk duzeyini uretime uygun bir degere cek
4. es zamanli isci sayisini makinenin gucune gore ayarla
5. gecelik toplu isi trafigin dusuk oldugu bir saate al
6. veri dizinini ac
7. kutuk dizinini ac
SON

cat > kur.sh <<'SON'
#!/usr/bin/env bash
# Betikle saglama: yedi adim sirayla kosar; hicbir adim once durumu okumaz.
set -e
mkdir -p ortam/paket ortam/ayar ortam/dizin
echo "3.4.0" >> ortam/paket/cozumleyici
echo "9.1.0" >> ortam/paket/kural-paketi
echo "ozet"  >> ortam/ayar/kutuk-duzeyi
[ -z "$KES" ] || exit 3                       # yarida kalma noktasi
echo "8"     >> ortam/ayar/es-zamanli-isci
echo "02:30" >> ortam/ayar/toplu-is-baslangic
mkdir ortam/dizin/veri ortam/dizin/kutuk
SON
```

Üç tarif de aynı yedi kalemi hedefler. Bildirim kalemleri değerleriyle sayar; yönerge üç adımda
sayı vermez ("uygun bir değer", "makinenin gücüne göre", "trafiğin düşük olduğu bir saat"); betik
yedi adımı sırayla koşar. Denetleyici hiçbir şey düzeltmez, yalnız diski istenen durumla
karşılaştırıp sayar.

```js
// denetle.mjs — diskteki ortami istenen durumla karsilastirir ve sayar; hicbir sey duzeltmez.
import { readFileSync, existsSync, statSync } from "node:fs";

const kok = process.argv[2] ?? "ortam";
const istenen = JSON.parse(readFileSync("istenen.json", "utf8"));
const durum = (yol) => {
  const t = `${kok}/${yol}`;
  if (!existsSync(t)) return "eksik";
  const g = statSync(t).isDirectory() ? "" : readFileSync(t, "utf8").trim();
  return g === (istenen[yol] ?? "") ? "uygun" : "sapmis";
};
const s = Object.keys(istenen).map(durum);
const say = (t) => s.filter((x) => x === t).length;
const sapma = say("sapmis") + say("eksik");
console.log(process.argv[3] === "-k" ? sapma                       // -k: yalniz sapma sayisi
  : `  kalem ${s.length}   uygun ${say("uygun")}   sapmis ${say("sapmis")}` +
    `   eksik ${say("eksik")}   sapma ${sapma}`);
```

#### Aynı Tarif, Kaç Ayrı Sonuç

```bash
#!/usr/bin/env bash
# Betik modelinin uc senaryosu ve elle kurulumun iki eli.
kos() { printf '%s\n' "$1"; shift; "$@" >/dev/null 2>&1; printf '  betigin cikis kodu %s\n' "$?"; }

rm -rf ortam
kos "1. kosum (bos ortam)"        bash kur.sh
node denetle.mjs
kos "2. kosum (ayni betik yeniden)" bash kur.sh
node denetle.mjs

rm -rf ortam
kos "3. kosum (yarida kesilen)" env KES=1 bash kur.sh
node denetle.mjs
printf '  nerede kaldigini yazan kayit: %s dosya\n' "$(ls ortam/*.durum 2>/dev/null | wc -l | tr -d ' ')"

el() {                                       # $1 dizin, $2..$4 elin yorumladigi uc deger
  rm -rf "$1"; mkdir -p "$1/paket" "$1/ayar" "$1/dizin/veri" "$1/dizin/kutuk"
  printf '3.4.0\n' > "$1/paket/cozumleyici"; printf '9.1.0\n' > "$1/paket/kural-paketi"
  printf '%s\n' "$2" > "$1/ayar/kutuk-duzeyi"; printf '%s\n' "$3" > "$1/ayar/es-zamanli-isci"
  printf '%s\n' "$4" > "$1/ayar/toplu-is-baslangic"
}
el el-1 ozet 8 02:30
el el-2 ayrinti 4 03:00
printf 'elle kurulum: ayni yonergeden iki el\n  iki kurulum arasindaki fark %s kalem\n' \
  "$(diff -rq el-1 el-2 | wc -l | tr -d ' ')"
node denetle.mjs el-1
node denetle.mjs el-2
```

```
1. kosum (bos ortam)
  betigin cikis kodu 0
  kalem 7   uygun 7   sapmis 0   eksik 0   sapma 0
2. kosum (ayni betik yeniden)
  betigin cikis kodu 1
  kalem 7   uygun 2   sapmis 5   eksik 0   sapma 5
3. kosum (yarida kesilen)
  betigin cikis kodu 3
  kalem 7   uygun 3   sapmis 0   eksik 4   sapma 4
  nerede kaldigini yazan kayit: 0 dosya
elle kurulum: ayni yonergeden iki el
  iki kurulum arasindaki fark 3 kalem
  kalem 7   uygun 7   sapmis 0   eksik 0   sapma 0
  kalem 7   uygun 4   sapmis 3   eksik 0   sapma 3
```

Betiğin ilk koşumu yedi kalemin yedisini yerine koyar. Aynı betiğin ikinci koşumu ortamı
**bozar**: beş kalem sapar ve betik yedinci adımda düşer. Nedeni iki karakterdedir — ekleme yapan
`>>` ve `-p` almayan `mkdir`. Betik önce durumu okumadığı için işin daha önce yapılıp
yapılmadığını bilemez; bir işlemin bir kez ile çok kez uygulanmasının aynı sonucu vermesine
**etkisizlik** denir ve bu betik onu taşımaz.

Yarıda kesilen koşum daha pahalıdır: üç kalem yerinde, dört kalem eksik ve **nerede kalındığını
yazan kayıt sıfır**. Ortam ne eski ne yeni durumdadır; betiğin bildirdiği tek şey bir çıkış
kodudur ve o kod hangi adımda durulduğunu söylemez.

Elle kurulumda iki el aynı yönergeyi okudu ve üç kalemde ayrıldı — tam olarak yönergenin sayı
vermediği üç adımda. Buradaki fark bir dikkatsizlik değil, **tarifin yazılmamış kısmıdır**: tarif
ile ortam arasındaki boşluğu insan doldurur ve doldurduğu değer hiçbir yere yazılmaz. Ölçü tek
satıra iner: elle kurulumda aynı tarif iki ayrı sonuç doğurdu, betikle sağlamada ikinci koşum
üçüncü bir sonuç doğurdu — üstelik ilkinden de bozuk olanı.

#### Sapmanın Sayılabilir Olması

```js
// uzlastir.mjs — istenen durumu dosyadan, gercek durumu diskten okur; farki yazar ve kapatir.
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync } from "node:fs";

const istenen = JSON.parse(readFileSync("istenen.json", "utf8"));
const gercek = (yol) => {
  const t = `ortam/${yol}`;
  if (!existsSync(t)) return null;
  return statSync(t).isDirectory() ? "" : readFileSync(t, "utf8").trim();
};

const fark = Object.entries(istenen).map(([yol, d]) => ({ yol, d: d ?? "", g: gercek(yol) }))
  .filter((f) => f.g !== f.d)
  .map((f) => ({ ...f, tur: f.g === null ? "eksik" : "sapmis" }));

for (const f of fark) {                        // uzlastirma: yalniz farkli olan kaleme dokunulur
  const t = `ortam/${f.yol}`;
  if (istenen[f.yol] === null) mkdirSync(t, { recursive: true });
  else {
    mkdirSync(t.slice(0, t.lastIndexOf("/")), { recursive: true });
    writeFileSync(t, istenen[f.yol] + "\n");
  }
}
console.log(`  kalem ${Object.keys(istenen).length}   fark ${fark.length}` +
  `   (eksik ${fark.filter((f) => f.tur === "eksik").length},` +
  ` sapmis ${fark.filter((f) => f.tur === "sapmis").length})   yapilan is ${fark.length}`);
for (const f of fark) console.log(`    ${f.tur.padEnd(6)} ${f.yol.padEnd(24)}` +
  (istenen[f.yol] === null ? " (dizin acilir)" : ` "${f.g ?? ""}" -> "${f.d}"`));
```

```bash
#!/usr/bin/env bash
# Uzlastirici: bos ortam, ikinci kosum (etkisizlik), elle mudahale sonrasi.
rm -rf ortam
echo "1. kosum (bos ortam)";        node uzlastir.mjs
echo "2. kosum (hemen ardindan)";   node uzlastir.mjs
echo "elle mudahale: isci sayisi 16 yapildi, kutuk dizini silindi"
echo 16 > ortam/ayar/es-zamanli-isci; rm -rf ortam/dizin/kutuk
echo "3. kosum (mudahaleden sonra)"; node uzlastir.mjs

mudahale() { case $1 in
  1) echo 16 > ortam/ayar/es-zamanli-isci ;;   2) echo ayrinti > ortam/ayar/kutuk-duzeyi ;;
  3) rm -rf ortam/dizin/kutuk ;;               4) echo 3.5.0 > ortam/paket/cozumleyici ;;
  5) echo 03:15 > ortam/ayar/toplu-is-baslangic ;; 6) echo 9.2.0 > ortam/paket/kural-paketi ;;
esac; }

echo ""
echo "alti donem, her donemde bir elle mudahale (sapma birikimi)"
for uzlastirma in yok var; do
  rm -rf ortam; node uzlastir.mjs > /dev/null
  printf '  uzlastirma %s :' "$uzlastirma"
  for d in 1 2 3 4 5 6; do
    mudahale "$d"
    [ "$uzlastirma" = var ] && node uzlastir.mjs > /dev/null
    printf ' %s' "$(node denetle.mjs ortam -k)"
  done
  printf '\n'
done

echo ""
printf 'tarif buyuklugu (satir): yonerge %s, betik %s, bildirim %s, uzlastirici %s\n' \
  "$(wc -l < tarif-elle.txt)" "$(wc -l < kur.sh)" "$(wc -l < istenen.json)" \
  "$(wc -l < uzlastir.mjs)" | tr -s ' '
```

```
1. kosum (bos ortam)
  kalem 7   fark 7   (eksik 7, sapmis 0)   yapilan is 7
    eksik  paket/cozumleyici        "" -> "3.4.0"
    eksik  paket/kural-paketi       "" -> "9.1.0"
    eksik  ayar/kutuk-duzeyi        "" -> "ozet"
    eksik  ayar/es-zamanli-isci     "" -> "8"
    eksik  ayar/toplu-is-baslangic  "" -> "02:30"
    eksik  dizin/veri               (dizin acilir)
    eksik  dizin/kutuk              (dizin acilir)
2. kosum (hemen ardindan)
  kalem 7   fark 0   (eksik 0, sapmis 0)   yapilan is 0
elle mudahale: isci sayisi 16 yapildi, kutuk dizini silindi
3. kosum (mudahaleden sonra)
  kalem 7   fark 2   (eksik 1, sapmis 1)   yapilan is 2
    sapmis ayar/es-zamanli-isci     "16" -> "8"
    eksik  dizin/kutuk              (dizin acilir)

alti donem, her donemde bir elle mudahale (sapma birikimi)
  uzlastirma yok : 1 2 3 4 5 6
  uzlastirma var : 0 0 0 0 0 0

tarif buyuklugu (satir): yonerge 7, betik 11, bildirim 3, uzlastirici 27
```

Uzlaştırıcı üç iş yapar: istenen durumu dosyadan okur, gerçek durumu diskten okur, yalnız farklı
kaleme dokunur. İlk koşum yedi kalemi eksik bulup yedi iş yapar; ikinci koşum **sıfır iş** yapar.
Betiğin taşımadığı etkisizlik burada ölçülmüş hâldedir ve nedeni tek bir sıra değişikliğidir —
önce okumak, sonra yazmak.

Ayırt edici yan üçüncü koşumdadır. Elle müdahale iki kalemi bozdu; uzlaştırıcı ikisini de adıyla,
eski ve yeni değeriyle yazıp kapattı. **Sapma burada bir sayıdır:** `fark 2`. Öteki iki modelde
sapmayı sayacak yer yoktu, çünkü istenen durum okunabilir bir nesne değildi — biri insanın
yorumunda, öteki bir komut dizisinde duruyordu. Komut dizisi **ne yapılacağını** söyler, **ne
olması gerektiğini** söylemez; sapmanın sayılabilirliği bu iki cümle arasındaki farktır.

Altı dönemlik tarama bunu iki satıra indirir: uzlaştırma koşmadığında müdahaleler birikir (1, 2,
3, 4, 5, 6), koştuğunda dizi sıfırda kalır. Sapma yok olmuyor, her dönemde doğup kapanıyor.
Birikmeyen şey sapmanın kendisi değil, **bilinmeyen sapmadır**.

#### Üç Modelin Bedeli

| Ölçü | Elle | Betikle | Bildirimsel |
|---|---|---|---|
| tarif büyüklüğü (satır) | 7 | 11 | 3 artı 27 (bir kez yazılır) |
| ilk kurulumda yerine gelen kalem | 7 ve 4 (iki el) | 7 | 7 |
| aynı tariften ayrı sonuç | 2 | 2 | 1 |
| tarif ikinci kez koşarsa | ölçülemez | 5 kalem sapar, çıkış 1 | 0 iş |
| yarıda kalırsa geriye kalan | kayıtsız | 3 kalem, 0 kayıt | fark yeniden hesaplanır |
| 6 dönemde biriken sapma | 1'den 6'ya | 1'den 6'ya | her dönem 0 |
| sapmayı yakalama | yok | yok | bildirimdeki 7 kalem |

Yazım maliyeti bildirimsel modelde en düşük görünür — üç satır — ama sayı yanıltıcıdır:
uzlaştırıcı yirmi yedi satırdır ve farkı yapan şey onun **bir kez** yazılıp her ortam için yeniden
kullanılmasıdır. Betik on bir satırdır ve her yeni kalemle büyür; yönerge yedi satırdır ve
büyüdükçe belirsizliği de büyür, çünkü düzyazının her cümlesi bir yorum noktasıdır.

İlk kurulum süresi üç modelde de aynı mertebededir; ayrım orada değil, ikinci koşumda ve
müdahaleden sonra çıkar. Sağlama tartışmasının en sık kaçırdığı yer budur: yalnız ilk kurulumla
karşılaştırıldığında betik yeterli görünür, çünkü orada bildirimsel modelle **aynı sonucu** verir.

Bildirimsel modelin sınırı da sayılabilir. Uzlaştırıcı yalnız bildirimde yazan yedi kalemi görür;
ortama sekizinci bir dosya elle eklendiğinde hiçbir koşumda fark olarak çıkmaz. **Sapmayı
sayılabilir kılan şey bildirimin kapsamıdır** ve kapsam dışındaki fark hiçbir yerde yazılı olmayan
bir yerde birikir: bir elin yorumunda, yarıda kalmış bir koşumun kısmi durumunda. Bu konunun ilk
dersinde yalnız koşumda görünen altı farkın kaynağı burasıdır.

#### Özet

- Elle kurulumda iki el aynı yönergeden 3 kalemde ayrıldı; ayrıldıkları adımlar yönergenin sayı
  vermediği üç adımdı.
- Betiğin ilk koşumu 7 kalemi yerine koydu; ikincisi 5 kalemi bozup düştü, yarıda kesileni 3 kalem
  bırakıp 4'ünü eksik ve nerede kalındığını yazan 0 kayıt bıraktı.
- Uzlaştırıcı ilk koşumda 7, ikinci koşumda 0 iş yaptı; elle müdahaleden sonra 2 sapmayı adıyla
  yazıp kapattı.
- Altı dönemde uzlaştırma yokken sapma 1'den 6'ya birikti, varken 0'da kaldı; birikmeyen şey sapma
  değil, bilinmeyen sapmadır.
- Bildirimsel modelin sınırı bildirimin kapsamıdır: kapsam dışındaki her şey elle kurulumdaki
  durumuna geri düşer.

#### Kurs Kapanışı

| Ders | Ölçülen fark ya da ölçüt | Sayı | Farkın saklandığı yer |
|---|---|---|---|
| DevOps Nedir | sahibine ulaşmayan olgu, ulaşma adımı | 22 olgunun 4'ü; 7,0 → 1,6 adım | gözlem alanının bölünmesi |
| Duvar Üzerinden Atma | sınırda düşen bağlam kalemi | 29 kalemin 21'i yazısız, 14'ü düşüyor | yazılmamış bağlam |
| Değer Akışı | beklemenin tek adımda yığılması | 2237 adımın 1485'i; katma değer %38,5 | beklemenin dağılımı |
| Teslimat Ölçütleri | parti 8'den 2'ye inince oynayan ölçüt | dağıtım 3,2 → 13,5; hata 12'de sabit | ölçütün paydası |
| Site Güvenilirliği Mühendisliği | hata bütçesi ve tükenmesi | 43,2 dakika; ağır olay %208; 8/12 dönem | hedef ile kesinti dağılımı arası |
| Geri Bildirim Döngüleri | erken döngüye düşmeyen hata | 120 hatanın 32'si, gecikmenin %95'i | döngü kapsamı |
| Ortamlar | ortam denkliği, boyut başına fark | 18 fark; 12 künyede, 6 koşumda | künyede yazmayan boyut |
| Yapı Çıktısı ve Değişmezlik | yeniden üretilebilirliği bozan kaynak | 4 kaynak, 3'ü tek makinede görünmez | çıktıya gömülü değer |
| Yapı Çıktısı Depoları | etiketin taşıdığı ayrı çıktı | 11 adla dağıtım, 7'sinde başka çıktı | dağıtım anındaki ad çözümü |
| Yapılandırma ve Sır Ayrımı | değişen anahtar, sızma yolu | 14 anahtarın 6'sı; 7 sızıntıdan 5'i | kaynağa gömülü varsayılan |
| On İki Etmen Uygulama | denetime çevrilen ilke, yakalanan kusur | 12 ilkenin 8'i; 8 kusurdan 6'sı | kuralın kapsamı ile ilkenin konusu arası |
| Altyapı Sağlama Modelleri | aynı tariften doğan ayrı sonuç | elle 3, betik 5, bildirimsel 0; sapma 6 → 0 | tarifin yazılmamış kısmı |

On iki satırın hepsi tek bir kuralın örneğidir: **aynı yazılım iki ortamda başka davranıyorsa fark
bir yerdedir ve adı konmadıkça ölçülmez.** Tablodaki hiçbir sayı yazılımın kendisinden gelmiyor;
hepsi farkın saklandığı yerden geliyor. Bir kalemin yazılı olup olmadığı, bir adın dağıtım anında
neye çözüldüğü, bir yönergenin hangi adımda sayı vermediği — bunların hiçbiri kodun içinde
değildir ve hiçbiri kendiliğinden görünmez.

Son sütun okunduğunda bir yığılma görünür: farkın saklandığı yerlerin çoğu **ortamın kendisiydi**
— kurulu paketler, kütüphane sürümleri, dosya yolları, saat dilimi. Künyeyi genişletmek,
yapılandırmayı dışarı almak ve sağlamayı bildirimsel yapmak bu farkı ölçülebilir kıldı, ama farkı
**ortamdan çıkarmadı**; her seferinde yapılan, farkı sayılabilir bir yere taşımak oldu.

Buradan bir soru kalır ve **M22/K02 Konteynerler** onu üstlenir: bu farkı yapı çıktısının içine
alıp ortamdan tümüyle çıkarmak mümkün mü? Kurulu paketler, sürümler ve dosya yolları çıktının
parçası olursa ortamın yapabileceği tek şey o çıktıyı çalıştırmak olur ve sağlanacak bir şey
kalmaz. Mümkünse bedeli nedir — çıktı ne kadar büyür, yeniden üretilebilirlik ne olur, ortamdan
çıkarılamayan ne kalır?

