---
title: 'Platform Mühendisliği'
source: 'https://academia.sh/tr/kurslar/platform-muhendisligi'
language: tr
updated: '2026-08-17T04:40:43+00:00'
license: 'CC BY-SA 4.0'
lessons: 12
outcomes:
    - 'İç geliştirici platformunu ürün olarak konumlandırır'
    - 'Altın yol tanımlayarak standart ile özerklik dengesini kurar'
    - 'Platform etkisini ölçütlerle değerlendirir'
---

# Platform Mühendisliği

Yedi kurs boyunca kurulan katmanların her ekip için yeniden kurulmaması: platform mühendisliğinin ölçekteki gerekçesi, iç müşteri ve geri bildirim döngüsüyle ürün olarak platform, önerilen ve desteklenen altın yollar, zorunluluk ile seçim özgürlüğü dengesi, talep kuyruğunu ortadan kaldıran kendi kendine hizmet, istek üzerine ortam sağlama, yeni servis başlatan şablon ve iskelet üretimi, sahiplik ve bağımlılık görünürlüğü veren servis kataloğu, kuralların hatta gömülmesi, ekip bazlı maliyet muhasebesi, platform geçişlerinin aşamalandırılması ve benimseme, teslimat hızı ile kararlılık göstergeleri.

## Platform Yaklaşımı

Soyutlamanın ne zaman kazandırdığı: platform mühendisliğinin ölçekteki gerekçesi ve eşiği, iç müşteri ile geri bildirim döngüsünün ürün olarak kurulması, önerilen ve desteklenen altın yolun kapsamı, zorunluluk ile seçim özgürlüğü arasındaki dengenin sayıya bağlanması ve talep kuyruğunu ortadan kaldıran kendi kendine hizmetin bedeli.

### Platform Mühendisliği Nedir

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/platform-muhendisligi-nedir

Platformun bir soyutlama olarak ölçülmesi: yedi kursun her ekipte yeniden kurulan on sekiz kalemi listelenir, ekip başına yeniden kurma işi sayılır, ekip sayısı taranarak platformun kendini ödediği eşik çıkarılır ve az ekipte platformun kaybettirdiği iş günü aynı tabloda gösterilir.

Önceki kurs sertleştirmeyi kapatırken bir soru bıraktı. Yedi kurs boyunca her katman ayrı ayrı
kuruldu: ortam sağlandı, hat kuruldu, küme nesnesi yazıldı, altyapı kaydı tutuldu, gösterge
bağlandı, varsayılan yüzey daraltıldı. Bunların hepsini **her ekip yeniden mi kuracak?**

Karşılık bir görüş değil, bir sayıdır: ortak bir yere taşımanın bedeli peşin ödenir, kazancı ekip
sayısıyla çarpılır ve ikisi belli bir ekip sayısında eşitlenir. Bu kursun ölçü birimi
**soyutlama**dır — platform bir katmanı gizler, yerine bir arayüz koyar, o arayüzün de kendi bedeli
olur. Her ders üçünü sayar: ne gizlendi ve kaç ekip ne kadar kurtuldu, gizlenen nerede geri sızdı,
kim yolun dışına çıktı.

Platformun bir **ekip türü** olarak nerede durduğu — akış odaklı ekipler, bilişsel yük, ekip
topolojileri — `ekip-ve-teslimat/02` dersinde ölçüldü; tekrarlanmaz. Burada platform ekip düzeni
değil, soyutlamadır. Through-line **bölgesel ölçüm ağıdır**; bu kursta ağın yazılımını üreten **beş
ekip** eklenir: sayaç okuma, doğrulama, faturalama, saha ve raporlama. Ağ da ekipler de kurgudur.

#### Yedi Kursun Bıraktığı Kalem Kümesi

**PY1 — yedi kursun bıraktığı iş, altı türde on sekiz kaleme ayrılır: ortam, hat, küme nesnesi,
kayıt, gösterge ve sertleştirme adımı.** Her kalem üç sayı taşır: bir ekibin kalemi kendi kurup üç
yıl sürdürmesinin bedeli, platformun kalemi bir kez devralmasının bedeli ve devirden sonra **ekipte
kalan** iş. Birim iş günüdür. Gerekçe: kalem kümesi sayılmadan platform tartışması ölçülemez.

**PY2 — bir kalemin eşiği, devir bedelinin ekip başına net kazanca bölümünün yukarı
yuvarlanmasıdır**; net kazanç, ekip başına iş ile ekipte kalan işin farkıdır. Gerekçe: devir bir
kez ödenir, kazanç her ekipte tekrarlanır.

**PY3 — iki düzen karşılaştırılır: her ekibin on sekiz kalemi kendi kurduğu düzen ve platformun
hepsini devraldığı düzen.** **PY4 — üçüncü düzen, seçici devir, yalnız eşiği beşe kadar olan
kalemleri taşır; geri kalanlar ekiplerde tam bedelle durur.** Gerekçe: devir kurumsal değil, kalem
kalem verilen bir karardır.

```js
// kalem.mjs — yedi kursun biraktigi kalem kumesi, kalem basina esik ve ekip taramasi (model)
import { writeFileSync } from "node:fs";

// PY1 — yedi kursun biraktigi ve her ekipte yeniden kurulan 18 kalem: tur, ad, ekip basina
// is, platform devri (bir kez), devirden sonra ekipte kalan is. Birim is gunu, pencere uc
// yil. PY2 — kalem esigi = ceil(devir / (ekip - kalan)). Sayilar kurgudur.
const KALEM = [
  ["ortam", "gelistirme ortami", 12, 55, 3],
  ["ortam", "sinama ortami", 9, 40, 2],
  ["ortam", "gizli deger baglama", 7, 46, 2],
  ["hat", "derleme adimi", 8, 30, 2],
  ["hat", "sinama kosumu", 6, 22, 4],
  ["hat", "kanit uretimi", 10, 44, 1],
  ["hat", "dagitim adimi", 11, 52, 3],
  ["kume nesnesi", "is yuku tanimi", 9, 38, 3],
  ["kume nesnesi", "ag kurali", 7, 34, 2],
  ["kume nesnesi", "olcekleme kurali", 5, 18, 3],
  ["kayit", "altyapi durum kaydi", 13, 62, 2],
  ["kayit", "surum kaydi", 6, 20, 1],
  ["gosterge", "dort gosterge baglama", 8, 30, 5],
  ["gosterge", "gunluk toplama", 7, 26, 2],
  ["gosterge", "uyari kurali", 9, 24, 6],
  ["sertlestirme", "taban imge taramasi", 10, 42, 1],
  ["sertlestirme", "yetki daraltma", 12, 50, 4],
  ["sertlestirme", "gizli deger dondurme", 8, 33, 2],
].map(([tur, ad, ekip, devir, kalan]) => ({ tur, ad, ekip, devir, kalan,
  net: ekip - kalan, esik: Math.ceil(devir / (ekip - kalan)), sizma: kalan / ekip }));
writeFileSync("kalem.json", JSON.stringify(KALEM));

const T = (d, f) => d.reduce((t, k) => t + f(k), 0);
const pay = (a, b) => `%${(100 * a / b).toFixed(1)}`;
const grup = (t) => KALEM.filter((k) => k.tur === t);
console.log(`${KALEM.length} kalem — ekip basina ${T(KALEM, (k) => k.ekip)}, devir ` +
  `${T(KALEM, (k) => k.devir)}, devirden sonra ekipte kalan ${T(KALEM, (k) => k.kalan)} is gunu ` +
  `(kalan payi ${pay(T(KALEM, (k) => k.kalan), T(KALEM, (k) => k.ekip))})`);
console.log("tur basina kalan payi — " + [...new Set(KALEM.map((k) => k.tur))]
  .map((t) => `${t} ${pay(T(grup(t), (k) => k.kalan), T(grup(t), (k) => k.ekip))}`).join(", "));

console.log("\n" + "kalem".padEnd(23) + "ekip".padStart(5) + "kalan".padStart(7) +
  "devir".padStart(7) + "esik".padStart(6));
for (const k of [...KALEM].sort((a, b) => a.esik - b.esik || a.ad.localeCompare(b.ad)))
  console.log(k.ad.padEnd(23) + `${k.ekip}`.padStart(5) + `${k.kalan}`.padStart(7) +
    `${k.devir}`.padStart(7) + `${k.esik}`.padStart(6));

// PY3 — iki duzen: her ekip 18 kalemi kendi kurar; ya da platform devralir, ekipte artik
// kalir. PY4 — ucuncu duzen, secici devir, yalniz esigi bese kadar olan kalemleri tasir.
const TAM = T(KALEM, (k) => k.ekip);
const H_DEVIR = T(KALEM, (k) => k.devir), H_KALAN = T(KALEM, (k) => k.kalan);
const S_DEVIR = T(KALEM.filter((k) => k.esik <= 5), (k) => k.devir);
const S_KALAN = T(KALEM, (k) => (k.esik <= 5 ? k.kalan : k.ekip));
const im = (v) => (v > 0 ? `+${v}` : `${v}`);
console.log("\n" + "ekip".padStart(5) + "platformsuz".padStart(13) + "tum kalemler".padStart(14) +
  "fark".padStart(8) + "secici".padStart(9) + "fark".padStart(8) + "kazanan".padStart(14));
for (let n = 1; n <= 12; n++) {
  const yok = n * TAM, hep = H_DEVIR + n * H_KALAN, sec = S_DEVIR + n * S_KALAN;
  const en = Math.min(yok, hep, sec);
  console.log(`${n}`.padStart(5) + `${yok}`.padStart(13) + `${hep}`.padStart(14) +
    im(yok - hep).padStart(8) + `${sec}`.padStart(9) + im(yok - sec).padStart(8) +
    (en === yok ? "platformsuz" : en === sec ? "secici" : "tum kalemler").padStart(14));
}
const esik = (devir, ekipte) => Math.ceil(devir / (TAM - ekipte));
console.log(`\ntum kalemler devredilirse esik: ${esik(H_DEVIR, H_KALAN)} ekip; ` +
  `secici devirde: ${esik(S_DEVIR, S_KALAN)} ekip (devir ${H_DEVIR} ve ${S_DEVIR})`);
const agir = KALEM.filter((k) => k.sizma > 0.4).sort((a, b) => b.esik - a.esik);
console.log(`artik isi sifir olan kalem: ${KALEM.filter((k) => k.kalan === 0).length} / ` +
  `${KALEM.length}; artigi ekip isinin %40'ini asan kalem: ${agir.length} — ` +
  agir.map((k) => `${k.ad} (${pay(k.kalan, k.ekip)}, esik ${k.esik})`).join(", "));
```

```
18 kalem — ekip basina 157, devir 666, devirden sonra ekipte kalan 48 is gunu (kalan payi %30.6)
tur basina kalan payi — ortam %25.0, hat %28.6, kume nesnesi %38.1, kayit %15.8, gosterge %54.2, sertlestirme %23.3

kalem                   ekip  kalan  devir  esik
surum kaydi                6      1     20     4
derleme adimi              8      2     30     5
kanit uretimi             10      1     44     5
taban imge taramasi       10      1     42     5
altyapi durum kaydi       13      2     62     6
gizli deger dondurme       8      2     33     6
gunluk toplama             7      2     26     6
sinama ortami              9      2     40     6
ag kurali                  7      2     34     7
dagitim adimi             11      3     52     7
gelistirme ortami         12      3     55     7
is yuku tanimi             9      3     38     7
yetki daraltma            12      4     50     7
uyari kurali               9      6     24     8
olcekleme kurali           5      3     18     9
dort gosterge baglama      8      5     30    10
gizli deger baglama        7      2     46    10
sinama kosumu              6      4     22    11

 ekip  platformsuz  tum kalemler    fark   secici    fark       kazanan
    1          157           714    -557      264    -107   platformsuz
    2          314           762    -448      392     -78   platformsuz
    3          471           810    -339      520     -49   platformsuz
    4          628           858    -230      648     -20   platformsuz
    5          785           906    -121      776      +9        secici
    6          942           954     -12      904     +38        secici
    7         1099          1002     +97     1032     +67  tum kalemler
    8         1256          1050    +206     1160     +96  tum kalemler
    9         1413          1098    +315     1288    +125  tum kalemler
   10         1570          1146    +424     1416    +154  tum kalemler
   11         1727          1194    +533     1544    +183  tum kalemler
   12         1884          1242    +642     1672    +212  tum kalemler

tum kalemler devredilirse esik: 7 ekip; secici devirde: 5 ekip (devir 666 ve 136)
artik isi sifir olan kalem: 0 / 18; artigi ekip isinin %40'ini asan kalem: 4 — sinama kosumu (%66.7, esik 11), dort gosterge baglama (%62.5, esik 10), olcekleme kurali (%60.0, esik 9), uyari kurali (%66.7, esik 8)
```

#### Eşik Nerede

İlk iki satır peşin bedeli verir: bir ekibin yedi kursun tamamını kendi kurup üç yıl sürdürmesi
**157 iş günü**, aynı kalemleri platformun devralması **666 iş günü**dür — tek bir ekibin işinin
dört katından fazlası. Devirden sonra ekipte duran iş **48 iş günü**, ekip başına işin
**%30,6**'sı. Tür başına en yüksek artık gösterge kalemlerindedir (%54,2), çünkü hangi göstergenin
izleneceği ve uyarının hangi değerde çalacağı ekibin kendi işine bağlıdır; en düşüğü kayıt
kalemleridir (%15,8), altyapı durum kaydının tutulma biçimi ekipten ekibe değişmez.

Tablo kararı kalem başına verir. `surum kaydi` dört ekipte kendini öder; `sinama kosumu` on bir
ekipten önce ödemez, çünkü altı iş gününün dördü ekipte kalır ve net kazanç ikiye iner. **Beş
ekiplik bir kuruluşta on sekiz kalemin yalnız dördü kendini öder.**

Tarama üç bölge gösterir. **Bir ile dört ekip arasında platformsuz düzen kazanır**; tek ekipte tüm
kalemleri devretmek 557 iş günü kaybettirir. Beş ve altı ekipte seçici devir öne geçer. **Yedi
ekipten sonra tüm kalemlerin devri kazanır** ve fark açılır: on iki ekipte 642 iş günü. Beş ekiplik
satır bu kursun ilk kararıdır: beş ekip tüm kalemleri platforma taşıdığında **121 iş günü
kaybeder**, platformsuz düzenin %15,4 üstüne çıkar; aynı beş ekip seçici devirle 9 iş günü kazanır.
Soru "platform kuralım mı" değil, **"kaç ekip ve hangi kalemler"** sorusudur.

Son satır sızmayı adlandırır: on sekiz kalemin hiçbirinde artık iş sıfır değildir, dördünde ekip
işinin %40'ını aşar ve bu dördünün eşikleri 8, 9, 10 ve 11'dir — listenin en geç ödeyen ucu.
İki sayı aynı kaynaktan gelir: artık büyüdükçe net kazanç küçülür, eşik yukarı çıkar. **En çok
sızan kalem, en geç kendini ödeyen kalemdir.**

#### Beş Ekip ve Dışına Çıkanlar

**PY5 — ölçüm ağının yazılımını beş ekip üretir ve her ekibin platformun biçimine sığmayan
kalemleri vardır.** **PY6 — dışına çıkan ekip o kalemin tam bedelini öder, üstüne platformun
ürettiği biçimle kendi biçimini bağdaştırmak için `ceil(ekip / 4)` uyum bedeli öder.** Gerekçe:
dışarı çıkmak platformdan kurtulmak değildir; ekip yine platformun sınırına değer ve çıktısını
onun beklediği biçime çevirmek zorunda kalır.

```js
// ekipler.mjs — bes ekip, disina cikilan kalemler ve muafiyetli esik
import { readFileSync } from "node:fs";
const KALEM = JSON.parse(readFileSync("kalem.json", "utf8"));
const bul = (ad) => KALEM.find((k) => k.ad === ad);

// PY5 — bolgesel olcum aginin yazilimini ureten bes ekip ve platformun bicimine sigmayan
// kalemleri; ekipler de gerekceler de kurgudur. PY6 — disina cikan ekip kalemin tam
// bedelini oder, ustune bagdastirma icin ceil(ekip / 4) uyum bedeli oder.
const EKIP = [
  ["sayac okuma", { "gelistirme ortami": "donanim benzetimi", "ag kurali": "dogrudan hat" }],
  ["dogrulama", { "olcekleme kurali": "gece toplu kosumu", "is yuku tanimi": "uzun is" }],
  ["faturalama", { "altyapi durum kaydi": "saklama zorunlulugu",
    "surum kaydi": "geriye donuk hesap", "gizli deger dondurme": "ayri imza zinciri" }],
  ["saha", { "dagitim adimi": "baglantisiz calisma", "gunluk toplama": "aralikli baglanti",
    "gelistirme ortami": "donanim benzetimi" }],
  ["raporlama", {}],
].map(([ad, disari]) => ({ ad, disari }));

const uyum = (k) => Math.ceil(k.ekip / 4);
const TAM = KALEM.reduce((t, k) => t + k.ekip, 0);
const bedel = (e, uygun) => KALEM.reduce((t, k) => t + (uygun(k)
  ? (k.ad in e.disari ? k.ekip + uyum(k) : k.kalan) : k.ekip), 0);
console.log("ekip".padEnd(13) + "disina cikan".padStart(13) + "disarida is".padStart(13) +
  "iceride artik".padStart(15) + "toplam".padStart(8) + "kurtulan".padStart(10));
for (const e of EKIP) {
  const d = Object.keys(e.disari);
  e.dis = d.reduce((t, ad) => t + bul(ad).ekip + uyum(bul(ad)), 0);
  e.ic = KALEM.filter((k) => !d.includes(k.ad)).reduce((t, k) => t + k.kalan, 0);
  e.toplam = e.dis + e.ic;
  console.log(e.ad.padEnd(13) + `${d.length}`.padStart(13) + `${e.dis}`.padStart(13) +
    `${e.ic}`.padStart(15) + `${e.toplam}`.padStart(8) + `${TAM - e.toplam}`.padStart(10));
}

const ODENEN = EKIP.reduce((t, e) => t + e.toplam, 0);
const DEVIR = KALEM.reduce((t, k) => t + k.devir, 0);
const dokunulan = new Set(EKIP.flatMap((e) => Object.keys(e.disari)));
const ort = ODENEN / EKIP.length;
console.log(`\nen az bir ekibin disina ciktigi kalem: ${dokunulan.size} / ${KALEM.length}; ` +
  `toplam disari cikma: ${EKIP.reduce((t, e) => t + Object.keys(e.disari).length, 0)}`);
console.log(`5 ekip — platformsuz ${5 * TAM}, tum kalemler muafiyetsiz ${DEVIR + 5 * 48}, ` +
  `tum kalemler muafiyetli ${DEVIR + ODENEN} is gunu`);
console.log(`muafiyetli ortalama ekip bedeli ${ort.toFixed(1)}; net kazanc ` +
  `${(TAM - ort).toFixed(1)}; esik ${Math.ceil(DEVIR / (TAM - ort))} ekip`);

// Secici devir ayni bes ekipte, muafiyetler yerinde dururken tekrar denenir.
const sec = (k) => k.esik <= 5;
const S = KALEM.filter(sec).reduce((t, k) => t + k.devir, 0) +
  EKIP.reduce((t, e) => t + bedel(e, sec), 0);
console.log(`5 ekip, secici devir, muafiyetli: ${S} is gunu — platformsuza gore ` +
  `${5 * TAM - S} is gunu, %${(100 * (5 * TAM - S) / (5 * TAM)).toFixed(1)}`);
```

```
ekip          disina cikan  disarida is  iceride artik  toplam  kurtulan
sayac okuma              2           24             43      67        90
dogrulama                2           19             42      61        96
faturalama               3           35             43      78        79
saha                     3           38             40      78        79
raporlama                0            0             48      48       109

en az bir ekibin disina ciktigi kalem: 9 / 18; toplam disari cikma: 10
5 ekip — platformsuz 785, tum kalemler muafiyetsiz 906, tum kalemler muafiyetli 998 is gunu
muafiyetli ortalama ekip bedeli 66.4; net kazanc 90.6; esik 8 ekip
5 ekip, secici devir, muafiyetli: 783 is gunu — platformsuza gore 2 is gunu, %0.3
```

Tek bir ekip platformun tarif ettiği ekiptir: `raporlama` on sekiz kalemin hepsini devralır ve 109
iş günü kurtarır. Diğer dördü kurtardığı işin bir kısmını geri verir. `faturalama` üç kalemin
dışındadır — saklama zorunluluğu, geriye dönük hesap ve ayrı imza zinciri yüzünden — ve 79 iş günü
kurtarır, `raporlama`nın otuz iş günü gerisinde. `saha` da 79 iş günü kurtarır ama dışarıda kalan
işi daha ağırdır (38'e karşı 35), çünkü bağlantısız çalışma dağıtım adımının tamamını dışarı taşır.

**On sekiz kalemin dokuzunda en az bir ekip yolun dışındadır**; kalem kümesinin yarısı beş ekibin
hepsine birden hizmet edemiyor. `gelistirme ortami` iki ekibin birden dışındadır: sayaç okuma da
saha da donanım benzetimine ihtiyaç duyar.

Muafiyetlerin faturası son iki satırdadır. Muafiyetsiz hesapta beş ekip 906 iş günü ödüyordu;
muafiyetlerle **998 iş gününe** çıkar, platformsuz düzenin (785) **%27 üstüne**. Ortalama ekip
bedeli 48'den 66,4'e çıktığı için net kazanç 109'dan 90,6'ya iner ve **eşik yedi ekipten sekize
kayar**. Seçici devir bile kaçamaz: `faturalama` seçili dört kalemden birinin, `surum kaydi`nin
dışındadır; seçici devrin beş ekipteki kazancı 9 iş gününden **2 iş gününe**, 785 iş günlük
toplamın **%0,3**'üne düşer. Bu ölçüde bir fark karar taşımaz.

#### Özet

- Yedi kursun bıraktığı iş altı türde on sekiz kaleme ayrıldı: bir ekibin hepsini kendi kurup üç
  yıl sürdürmesi 157, platformun devralması 666 iş günüdür.
- Devirden sonra ekipte kalan artık 48 iş günü, ekip başına işin %30,6'sıdır; hiçbir kalemde sıfır
  değildir, en yükseği gösterge kalemlerindedir (%54,2).
- Ekip taraması üç bölge verdi: 1–4 ekipte platformsuz düzen, 5–6 ekipte seçici devir, 7 ekipten
  sonra tüm kalemlerin devri kazanır. Beş ekipte hepsini devretmek 121 iş günü kaybettirir.
- Beş ekiplik kuruluşta on sekiz kalemin yalnız dördü kendini öder; en çok sızan dört kalemin
  eşikleri 8, 9, 10 ve 11'dir — artık büyüdükçe eşik yukarı çıkar.
- Beş ekibin dördü en az bir kalemin dışına çıkar, on sekiz kalemin dokuzunda muafiyet vardır.
  Muafiyetler beş ekiplik toplamı 906'dan 998 iş gününe, eşiği yedi ekipten sekize, seçici devrin
  kazancını 9 iş gününden 2 iş gününe (%0,3) taşır.

#### Sonraki Adım

Platform burada bir maliyet hesabı olarak kuruldu: devredilen kalem, ekipte kalan artık ve kendini
ödeme eşiği. Hesap kalem bedellerinin bilindiğini varsayıyordu; ekiplerin hangi kalemi isteyip
istemediği hiç sorulmadı. Devir bedeli ödendikten sonra bir kalemin kullanılmaması, onu 666 iş
günlük yatırımın ölü bir parçasına çevirir. Sonraki ders platformu iki işletme biçiminde koşturur —
talep üzerine yapılan ve ürün gibi yönetilen — ve benimsemeyi, hiç kullanılmayan yetenekleri, onlara
harcanan işi, geri bildirim döngüsünün uzunluğunu ve ürün yaklaşımının ürün ekiplerinden çektiği
kişi sayısını ölçer.

### Ürün Olarak Platform

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/urun-olarak-platform

İç müşteri ve geri bildirim döngüsünün ölçülmesi: aynı yirmi dört istek talep üzerine yapan ve ürün gibi yönetilen iki düzende koşturulur; benimseme, hiç kullanılmayan yetenek sayısı, ona harcanan iş, istek ile karşılık arası süre ve ürün yaklaşımının ürün ekiplerinde açtığı boşluk sayılır.

Önceki ders platformu bir maliyet hesabı olarak kurdu: on sekiz kalem, devir bedeli, ekipte kalan
artık ve kendini ödeme eşiği. Hesabın her satırı **hangi kalemin devredileceğinin bilindiğini**
varsayıyordu. Gerçekte platform ekibinin elinde kalem listesi yoktur; **istekler** vardır ve istek
ihtiyaçla aynı şey değildir. İki ekip aynı ihtiyacı iki ayrı istekle söyler; bir ekip istediği şeyi
karşılık geldiğinde artık kullanmaz.

Bu ders aynı istek kümesini iki işletme biçiminde koşturur. **Talep üzerine yapan** düzen isteği
geldiği gibi alır ve sırayla karşılar. **Ürün gibi yönetilen** düzen ekipleri **iç müşteri** sayar:
istekleri arkalarındaki ihtiyaca göre toplar, hangi ihtiyacı kaç ekibin beklediğine bakar, bir
ihtiyacı bir kez kurar; bedeli keşif işidir. Sayılanlar: benimseme, hiç kullanılmayan yetenek, ona
harcanan iş, istek ile karşılık arasındaki süre ve ürün yaklaşımının ürün ekiplerinde açtığı boşluk.
Through-line bölgesel ölçüm ağı ve onun beş ekibidir; ağ da ekipler de kurgudur.

#### İki İşletme Biçimi

**PY7 — beş ekip ilk on iki çeyrekte yirmi dört istek açar; bu isteklerin arkasında on dört ayrı
ihtiyaç vardır.** Koşum on altı çeyrek sürer, çünkü biriken sıranın boşalması ancak istek akışı
kesildikten sonra görülebilir. **PY8 — platformun çeyrek başına kapasitesi 26 iş günüdür ve her
koşumda aynıdır.** Gerekçe: iki düzen ancak aynı kapasiteyle karşılaştırılabilir.

**PY9 — talep üzerine düzen istekleri geliş sırasına göre işler ve aynı ihtiyaca gelen her isteği
ayrı yetenek olarak kurar.** **PY10 — ürün gibi yönetilen düzen ilk iki çeyrekte yalnız keşif
yapar, sonraki her çeyrekte kapasitenin 4 iş gününü keşfe ayırır, bir ihtiyacı bir kez kurar ve
bekleyen ekip sayısı çok olanı öne alır.** Gerekçe: ürün yaklaşımının ayırt edici yanı önceliği
istek sırasından alıp ihtiyacın genişliğine bağlamasıdır ve bu bilgi bedavaya gelmez.

**PY11 — karşılık istekten dört çeyrekten geç gelirse ekip kendi çözümünü kurmuştur ve o yeteneği
hiç kullanmaz.** Gerekçe: bekleme yalnız gecikme değildir; belli bir uzunluktan sonra teslim edilen
şeyin alıcısı kalmaz. Üçüncü bir koşum, keşifsiz ürün düzeni, keşif işinin bedelini ölçmek için
eklenir.

```js
// istek.mjs — ayni istek kumesi iki isletme bicimiyle kosturulur (model)
import { writeFileSync } from "node:fs";

// PY7 — bes ekibin ilk on iki ceyrekte actigi 24 istek ve arkalarindaki 14 ayri ihtiyac;
// kosum on alti ceyrek surer ki birikmis sira bosalsin. Sayilar kurgudur.
const IHTIYAC = {
  "ortam istegi": 28, "gizli deger dagitimi": 22, "hat sablonu": 18, "kanit arsivi": 16,
  "is yuku sablonu": 24, "ag kurali sablonu": 14, "olcek ayari": 12, "durum kaydi devri": 34,
  "surum defteri": 10, "gosterge baglama": 20, "gunluk borusu": 26, "uyari sablonu": 12,
  "imge tarama kapisi": 18, "yetki sablonu": 30,
};
const ISTEK = [
  [1, "sayac", "ortam istegi"], [1, "faturalama", "durum kaydi devri"],
  [2, "dogrulama", "hat sablonu"], [3, "saha", "ortam istegi"],
  [3, "raporlama", "gosterge baglama"], [4, "faturalama", "gizli deger dagitimi"],
  [4, "sayac", "ag kurali sablonu"], [5, "dogrulama", "olcek ayari"],
  [5, "saha", "gunluk borusu"], [6, "raporlama", "hat sablonu"],
  [6, "faturalama", "surum defteri"], [7, "sayac", "gosterge baglama"],
  [7, "dogrulama", "is yuku sablonu"], [8, "saha", "uyari sablonu"],
  [8, "faturalama", "kanit arsivi"], [9, "raporlama", "gunluk borusu"],
  [9, "sayac", "imge tarama kapisi"], [10, "dogrulama", "yetki sablonu"],
  [10, "saha", "gizli deger dagitimi"], [11, "faturalama", "hat sablonu"],
  [11, "raporlama", "ortam istegi"], [12, "sayac", "uyari sablonu"],
  [12, "dogrulama", "durum kaydi devri"], [12, "saha", "yetki sablonu"],
].map(([ceyrek, ekip, ihtiyac]) => ({ ceyrek, ekip, ihtiyac }));

// PY8 kapasite iki kosumda da 26 is gunu/ceyrek. PY9 talep uzerine duzen: gelis sirasi, her
// istek ayri yetenek. PY10 urun duzeni: ilk iki ceyrek yalniz kesif, sonra 4 is gunu/ceyrek
// kesif, bir ihtiyac bir kez, bekleyen ekip sayisina gore siralama. PY11 sabir dort ceyrek.
const KAPASITE = 26, KESIF = 4, CEYREK = 16, SABIR = 4;

function kos(ad, urun, kesifli = urun) {
  const istek = ISTEK.map((r) => ({ ...r, bitis: null }));
  const acik = [], kurulu = new Map();
  let yapim = 0, kesif = 0;
  for (let c = 1; c <= CEYREK; c++) {
    for (const r of istek.filter((x) => x.ceyrek === c)) {
      if (urun && kurulu.has(r.ihtiyac)) { r.bitis = c; continue; }
      const v = urun && acik.find((a) => a.ihtiyac === r.ihtiyac);
      if (v) { v.ekip.add(r.ekip); continue; }
      acik.push({ ihtiyac: r.ihtiyac, ekip: new Set([r.ekip]), kalan: IHTIYAC[r.ihtiyac] });
    }
    let g = KAPASITE;
    if (kesifli) { const k = c <= 2 ? KAPASITE : KESIF; kesif += k; g -= k; }
    if (urun) acik.sort((a, b) => b.ekip.size - a.ekip.size || a.kalan - b.kalan);
    while (g > 0 && acik.length) {
      const it = acik[0], h = Math.min(g, it.kalan);
      it.kalan -= h; g -= h; yapim += h;
      if (it.kalan > 0) break;
      acik.shift();
      if (urun) kurulu.set(it.ihtiyac, c);
      for (const r of istek)
        if (r.ihtiyac === it.ihtiyac && r.ceyrek <= c && r.bitis === null &&
          (urun || it.ekip.has(r.ekip))) { r.bitis = c; if (!urun) break; }
    }
  }
  for (const r of istek) {
    r.bekleme = r.bitis === null ? null : r.bitis - r.ceyrek;
    r.benimser = r.bitis !== null && r.bekleme <= SABIR;
  }
  return { ad, urun, istek, kurulu: [...kurulu], yapim, kesif,
    yetenek: urun ? kurulu.size : istek.filter((r) => r.bitis !== null).length };
}

const D = [kos("talep uzerine", false), kos("urun gibi", true),
  kos("urun, kesifsiz", true, false)];
writeFileSync("kosum.json", JSON.stringify({ IHTIYAC, D, SABIR }));
const ort = (v) => (v.length ? (v.reduce((a, b) => a + b, 0) / v.length).toFixed(1) : "-");
console.log("duzen".padEnd(16) + "yetenek".padStart(8) + "yapim".padStart(7) +
  "kesif".padStart(7) + "karsilanan".padStart(12) + "karsilanmayan".padStart(15) +
  "ort. bekleme".padStart(14) + "benimseyen".padStart(12));
for (const d of D) {
  const b = d.istek.filter((r) => r.bitis !== null);
  console.log(d.ad.padEnd(16) + `${d.yetenek}`.padStart(8) + `${d.yapim}`.padStart(7) +
    `${d.kesif}`.padStart(7) + `${b.length}`.padStart(12) +
    `${d.istek.length - b.length}`.padStart(15) + ort(b.map((r) => r.bekleme)).padStart(14) +
    `${d.istek.filter((r) => r.benimser).length}`.padStart(12));
}

console.log("\n" + "ekip".padEnd(13) + "istek".padStart(6) +
  D.map((d) => d.ad.padStart(16) + "benimsenen".padStart(12)).join(""));
for (const e of [...new Set(ISTEK.map((r) => r.ekip))]) {
  console.log(e.padEnd(13) + `${ISTEK.filter((r) => r.ekip === e).length}`.padStart(6) +
    D.map((d) => {
      const x = d.istek.filter((r) => r.ekip === e);
      return ort(x.filter((r) => r.bitis !== null).map((r) => r.bekleme)).padStart(16) +
        `${x.filter((r) => r.benimser).length}`.padStart(12);
    }).join(""));
}
```

```
duzen            yetenek  yapim  kesif  karsilanan  karsilanmayan  ort. bekleme  benimseyen
talep uzerine         20    416      0          20              4           3.2          16
urun gibi             14    284    108          24              0           2.3          20
urun, kesifsiz        14    284      0          24              0           0.7          24

ekip          istek   talep uzerine  benimsenen       urun gibi  benimsenen  urun, kesifsiz  benimsenen
sayac             5             3.0           3             1.0           5             0.4           5
faturalama        5             3.2           4             4.4           3             1.8           5
dogrulama         5             3.3           3             3.4           4             0.2           5
saha              5             3.5           3             1.4           4             0.8           5
raporlama         4             3.0           3             1.3           4             0.0           4
```

#### Bekleme ve Benimseme

İlk tablo iki düzeni yan yana koyar. Talep üzerine düzen **yirmi yetenek** kurar ve **416 iş günü**
harcar; dört istek on altı çeyrek boyunca sıraya bile giremez. Ürün düzeni aynı yirmi dört isteği
**on dört yetenekle** ve **284 iş günü** yapımla karşılar — dört istek daha fazlasını, yüz otuz iki
iş günü daha azıyla. Fark yapım hızında değil, **yineleme**dedir: `hat sablonu` da `ortam istegi`
de üçer kez kurulur, çünkü her istek ayrı bir yetenektir.

Bekleme sayıları bunu yumuşatır. Talep üzerine düzende ortalama bekleme **3,2 çeyrek**, ürün
düzeninde **2,3 çeyrektir**; keşifsiz koşumda **0,7 çeyreğe** iner. Aradaki 1,6 çeyrek keşif işinin
fiyatıdır: ilk iki çeyreğin tamamı ve sonraki her çeyreğin dört iş günü yapıma gitmemektedir.

İkinci tablo ürün düzeninin kimden aldığını gösterir. `sayac` beklemesi 3,0'dan 1,0'a, `saha`
3,5'ten 1,4'e iner. `faturalama` ise ters yöne gider: beklemesi **3,2'den 4,4 çeyreğe çıkar** ve
benimsediği istek sayısı dörtten üçe düşer. Nedeni önceliklendirme kuralıdır — `surum defteri` ve
`kanit arsivi` yalnız `faturalama`nın istediği ihtiyaçlardır ve bekleyen ekip sayısına göre
sıralanan bir kuyruğun sonuna düşerler. **Ürün yaklaşımı çoğunluğun ihtiyacını öne alırken
azınlığın ihtiyacını geriye atar; bu bir yan etki değil, kuralın kendisidir.**

#### Ölü Yetenek ve Ürün Yaklaşımının Bedeli

**PY12 — ürün düzeninin keşif işi platform kapasitesinden düşülür; bunun üstüne her istek için
isteyen ekipten 2 iş günü görüşme ve her çeyrek her ekipten 1 iş günü geri bildirim alınır.** Bu
ikinci kalem ürün ekiplerinde açılan boşluktur ve platformun defterine hiç yazılmaz. Kırk iş günü
bir kişi-çeyrek sayılır. Gerekçe: ürün yaklaşımının bedeli platform ekibinde değil, ölçtüğü
ekiplerde birikir; aynı birime çevrilmeden iki taraf toplanamaz.

```js
// benimseme.mjs — benimseme dagilimi, olu yetenek ve urun yaklasiminin bedeli
import { readFileSync } from "node:fs";
const { IHTIYAC, D, SABIR } = JSON.parse(readFileSync("kosum.json", "utf8"));
const EKIP = [...new Set(D[0].istek.map((r) => r.ekip))];

// Bir yetenegin benimseyen ekipleri: talep uzerine duzende yetenek istegi acan tek ekibe
// aittir; urun duzeninde ayni ihtiyaci isteyen butun ekipler tek yetenegi paylasir.
function yetenekler(d, sabir = SABIR) {
  const alan = (r) => r.bitis !== null && r.bitis - r.ceyrek <= sabir;
  if (!d.urun)
    return d.istek.filter((r) => r.bitis !== null)
      .map((r) => ({ ihtiyac: r.ihtiyac, is: IHTIYAC[r.ihtiyac], benimseyen: alan(r) ? 1 : 0 }));
  return d.kurulu.map(([ih]) => ({ ihtiyac: ih, is: IHTIYAC[ih],
    benimseyen: d.istek.filter((r) => r.ihtiyac === ih && alan(r)).length }));
}

console.log("duzen".padEnd(16) + "yetenek".padStart(8) + "yinelenen yapim".padStart(17) +
  "olu yetenek".padStart(13) + "olu yetenege giden is".padStart(23) +
  "ekip-yetenek cifti".padStart(20) + "yetenek basina".padStart(16));
for (const d of D) {
  const Y = yetenekler(d), olu = Y.filter((y) => y.benimseyen === 0);
  const tekil = [...new Set(Y.map((y) => y.ihtiyac))].reduce((t, i) => t + IHTIYAC[i], 0);
  const cift = Y.reduce((t, y) => t + y.benimseyen, 0);
  console.log(d.ad.padEnd(16) + `${Y.length}`.padStart(8) + `${d.yapim - tekil}`.padStart(17) +
    `${olu.length}`.padStart(13) + `${olu.reduce((t, y) => t + y.is, 0)}`.padStart(23) +
    `${cift}`.padStart(20) + (cift / Y.length).toFixed(2).padStart(16));
}

const adet = (ih) => new Set(D[0].istek.filter((r) => r.ihtiyac === ih).map((r) => r.ekip)).size;
for (const d of D.slice(0, 2)) {
  const olu = [...new Set(yetenekler(d).filter((y) => y.benimseyen === 0).map((y) => y.ihtiyac))];
  console.log(`${d.ad}: hic kullanilmayan yetenek — ` +
    olu.map((ih) => `${ih} (${IHTIYAC[ih]} is gunu, ${adet(ih)} ekip istedi)`).join("; "));
}

// PY12 — urun duzeninin kesif isi platform kapasitesinden dusuldu; ustune her istek icin
// isteyen ekipten 2 is gunu gorusme ve her ceyrek her ekipten 1 is gunu geri bildirim alinir.
// Bu ikinci kalem urun ekiplerinde acilan bosluktur. 40 is gunu bir kisi-ceyrektir.
const KC = 40, CEYREK = 16;
const gorusme = D[0].istek.length * 2, geri = EKIP.length * CEYREK;
const bosluk = gorusme + geri, kesif = D[1].kesif;
console.log(`\nurun duzeninin bedeli — platformda kesif ${kesif} is gunu ` +
  `(${(kesif / KC).toFixed(1)} kisi-ceyrek); urun ekiplerinde gorusme ${gorusme} + ` +
  `geri bildirim ${geri} = ${bosluk} is gunu (${(bosluk / KC).toFixed(1)} kisi-ceyrek)`);
console.log(`platformun yapim isinde kazanc: ${D[0].yapim} - ${D[1].yapim} = ` +
  `${D[0].yapim - D[1].yapim} is gunu; urun ekiplerine yazilan bosluk ${bosluk} is gunu ` +
  `(kazancin %${(100 * bosluk / (D[0].yapim - D[1].yapim)).toFixed(0)}'i)`);

// Geri bildirim dongusunun uzunlugu tek kaldirac: sabir penceresi taranir.
console.log("\n" + "sabir (ceyrek)".padEnd(16) +
  D.map((d) => d.ad.padStart(17)).join("") + "   (benimsenen istek / olu yetenege giden is)");
for (let s = 2; s <= 6; s++)
  console.log(`${s}`.padEnd(16) + D.map((d) => {
    const Y = yetenekler(d, s);
    const b = d.istek.filter((r) => r.bitis !== null && r.bitis - r.ceyrek <= s).length;
    return `${b} / ${Y.filter((y) => y.benimseyen === 0).reduce((t, y) => t + y.is, 0)}`
      .padStart(17);
  }).join(""));
```

```
duzen            yetenek  yinelenen yapim  olu yetenek  olu yetenege giden is  ekip-yetenek cifti  yetenek basina
talep uzerine         20              132            4                     88                  16            0.80
urun gibi             14                0            1                     24                  20            1.43
urun, kesifsiz        14                0            0                      0                  24            1.71
talep uzerine: hic kullanilmayan yetenek — imge tarama kapisi (18 is gunu, 1 ekip istedi); yetki sablonu (30 is gunu, 2 ekip istedi); gizli deger dagitimi (22 is gunu, 2 ekip istedi); hat sablonu (18 is gunu, 3 ekip istedi)
urun gibi: hic kullanilmayan yetenek — is yuku sablonu (24 is gunu, 1 ekip istedi)

urun duzeninin bedeli — platformda kesif 108 is gunu (2.7 kisi-ceyrek); urun ekiplerinde gorusme 48 + geri bildirim 80 = 128 is gunu (3.2 kisi-ceyrek)
platformun yapim isinde kazanc: 416 - 284 = 132 is gunu; urun ekiplerine yazilan bosluk 128 is gunu (kazancin %97'i)

sabir (ceyrek)      talep uzerine        urun gibi   urun, kesifsiz   (benimsenen istek / olu yetenege giden is)
2                         7 / 254          15 / 40           21 / 0
3                        13 / 154          18 / 24           22 / 0
4                         16 / 88          20 / 24           24 / 0
5                         19 / 22          21 / 24           24 / 0
6                          20 / 0          22 / 24           24 / 0
```

Benimseme sütunu asıl farkı verir. Talep üzerine düzende bir yeteneği ortalama **0,80 ekip**
kullanır — birden küçüktür, çünkü yeteneklerin dördü hiç kullanılmaz. Ürün düzeninde aynı sayı
**1,43**, keşifsiz koşumda **1,71**'dir. Yirmi yetenek on altı ekip-yetenek çifti üretirken on
dört yetenek yirmi çift üretir: **daha az yetenek, daha çok kullanım.**

Hiç kullanılmayan yetenek satırı iki düzende farklı bir hikâye anlatır. Talep üzerine düzende dört
yetenek ölüdür ve **88 iş günü** onlara gitmiştir; bunlardan `hat sablonu` üç ekibin istediği bir
ihtiyaçtır — istek geldiğinde önemliydi, karşılık geldiğinde geç kalmıştı. Ürün düzeninde tek bir
ölü yetenek vardır: **`is yuku sablonu`, 24 iş günü, tek ekibin istediği ihtiyaç.** Ölü işin kaynağı
karşıttır: birinde **sıranın uzunluğu**, diğerinde **önceliklendirmenin kendisi**.

Bedel satırı ürün yaklaşımının faturasını keser. Platformda keşfe giden iş **108 iş günü**, yani
2,7 kişi-çeyrektir. Ürün ekiplerinde açılan boşluk **128 iş günü**, 3,2 kişi-çeyrektir. Platformun
yapım işinde kazandığı 132 iş günüdür ve ürün ekiplerine yazılan boşluk bunun **%97**'sidir.
Platformun defterinde görünen kazancın neredeyse tamamı, görünmeyen bir defterde geri ödenir.

Son tarama sabır penceresini değiştirir. İki çeyreklik sabırda talep üzerine düzen yirmi dört
isteğin yalnız yedisini zamanında karşılar ve **254 iş günü** ölü işe gider; ürün düzeninde aynı
sayı 15 ve 40'tır. Pencere altı çeyreğe açıldığında talep üzerine düzenin ölü işi **sıfıra** iner,
ürün düzeninde ise **24 iş günü olarak kalır**. Sabırlı ekiplerde sıra beklemek işe yarar;
sıralamanın geriye attığı ihtiyaç ise beklemekle gelmez.

#### Özet

- Aynı 24 istek (14 ayrı ihtiyaç, 5 ekip, 16 çeyrek, çeyrek başına 26 iş günü kapasite) iki
  düzende koşturuldu: talep üzerine 20 yetenek ve 416 iş günü, ürün gibi 14 yetenek ve 284 iş günü.
- Talep üzerine düzende yinelenen yapım 132 iş günüdür; dört istek hiç karşılanmaz. Ürün düzeni
  yirmi dört isteğin hepsini karşılar.
- Ortalama bekleme talep üzerine 3,2, ürün gibi 2,3, keşifsiz ürün koşumunda 0,7 çeyrektir; aradaki
  1,6 çeyrek keşif işinin fiyatıdır.
- Yetenek başına benimseme 0,80'den 1,43'e çıkar; hiç kullanılmayan yetenek dörtten (88 iş günü)
  bire (`is yuku sablonu`, 24 iş günü) iner. Ölü işin kaynağı birinde sıra, diğerinde önceliktir.
- `faturalama` ekibinin beklemesi ürün düzeninde 3,2'den 4,4 çeyreğe çıkar ve benimsediği istek
  dörtten üçe iner: tek ekibin istediği ihtiyaç kuyruğun sonuna düşer.
- Ürün yaklaşımının bedeli platformda 108, ürün ekiplerinde 128 iş günüdür; ikincisi platformun
  yapım işinde kazandığı 132 iş gününün %97'sine denktir.

#### Sonraki Adım

İki düzen de aynı sorunun iki yanıtıdır: platform neyi yapsın. Ürün düzeni yanıtı ihtiyacın
genişliğine bağladı ve azınlığın ihtiyacını geriye attı; talep üzerine düzen sırayı korudu ve 132
iş günü yinelenen yapım ödedi. İkisinin de söylemediği şey **sınır**dır: platformun neyi kapsayıp
neyi kapsamadığı hiçbir yerde yazılı değildi. Sonraki ders bu sınırı tanımlar — bir yol kapsam
olarak yazılır, beş ekibin gereksinimine uygulanır, kaç ekibin sığdığı ve dışına çıkanın kalem
kalem neyi kaybettiği sayılır, sonra yolu genişletmenin bakım yüküne ne yaptığı taranır.

### Altın Yollar

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/altin-yollar

Önerilen ve desteklenen yolun kapsam olarak ölçülmesi: bir altın yol dil, veri deposu ve dağıtım biçimi eksenlerinde tanımlanır, beş ekibin gereksinimine uygulanır, dışına çıkanın kaybettiği destek kalem kalem sayılır ve kapsam genişletildikçe sığan ekip, bakım yükü ile bileşim sayısı birlikte taranır.

Önceki ders iki işletme biçimini karşılaştırdı ve ikisinin de aynı şeyi söylemediğini gösterdi:
platformun **sınırı**. Talep üzerine düzen sırayı, ürün düzeni ihtiyacın genişliğini takip etti;
hiçbiri "bu istek kapsam içinde mi" sorusuna yazılı bir karşılık vermedi.

**Altın yol** (golden path) o yazılı karşılıktır: platformun önerdiği ve desteklediği yolun
kapsamı. Bir yol iyi niyet beyanı değil, bir **kapsam tanımı**dır — hangi dil, hangi veri deposu,
hangi dağıtım biçimi. Kapsam yazıldığı anda ikiye böler: içeride kalanlar desteği alır, dışarıda
kalanlar almaz. Bu ders yolu kapsam olarak yazar, beş ekibe uygular, dışarıda kalanın kaybettiğini
kalem kalem sayar ve sonra yolu genişletir. Through-line bölgesel ölçüm ağı ve onun beş ekibidir;
ağ da ekipler de kurgudur.

#### Yolu Kapsam Olarak Yazmak

**PY13 — altın yol üç eksende kapsam olarak tanımlanır: dil, veri deposu, dağıtım biçimi. Yolun on
destek kalemi vardır ve her kalem tek bir eksene bağlıdır.** Her kalemin iki sayısı var: ekibin o
kalemden yılda kazandığı iş günü ve o eksene eklenen her seçenek için platformun yılda ödediği
bakım. Gerekçe: destek bir bütün değildir; bir ekip yolun bir kısmını alıp bir kısmını alamaz ve
bu ancak kalemler eksenlere bağlandığında ölçülebilir.

**PY14 — beş ekibin gereksinimi üç eksende yazılır; bir ekip ancak her üç eksende de kapsamın
içindeyse yola tam sığar.** **PY15 — dışında kaldığı eksene bağlı destek kalemlerinin hepsini
kaybeder, içeride kaldığı eksenlerin kalemlerini kullanmayı sürdürür.** Gerekçe: yolun dışına
çıkmak hep-ya-hiç değildir; kısmen yararlanma da ölçülmesi gereken bir durumdur.

```js
// yol.mjs — bir altin yol kapsam olarak tanimlanir ve bes ekibe uygulanir (model)
import { writeFileSync } from "node:fs";

// PY13 — altin yol uc eksende kapsam olarak tanimlanir: dil, veri deposu, dagitim bicimi.
// Yolun on destek kalemi vardir; her kalem tek bir eksene baglidir. Deger, ekibin o kalemden
// yilda kazandigi is gunu; bakim, o eksendeki her secenek icin platformun yilda odedigi.
const KALEM = [
  ["iskelet uretimi", "dil", 6, 4], ["derleme hatti", "dil", 8, 5],
  ["bagimlilik taramasi", "dil", 5, 3], ["sinama kosumu", "dil", 4, 3],
  ["sema gocu", "depo", 7, 5], ["yedek ve geri alma", "depo", 9, 6],
  ["baglanti havuzu", "depo", 4, 3], ["dagitim adimi", "dagitim", 10, 6],
  ["geri alma adimi", "dagitim", 6, 4], ["gosterge baglama", "dagitim", 5, 3],
].map(([ad, eksen, deger, bakim]) => ({ ad, eksen, deger, bakim }));
const EKSEN = ["dil", "depo", "dagitim"];

// PY14 — bes ekibin gereksinimi uc eksende yazilir; bir ekip ancak her uc eksende de yolun
// kapsami icindeyse yola sigar. Ekipler ve gereksinimleri kurgudur.
const EKIP = [
  ["sayac okuma", "dil A", "zaman serisi", "kenar birimi"],
  ["dogrulama", "dil A", "iliskisel", "toplu is"],
  ["faturalama", "dil B", "iliskisel", "uzun omurlu servis"],
  ["saha", "dil C", "belge", "kenar birimi"],
  ["raporlama", "dil A", "iliskisel", "uzun omurlu servis"],
].map(([ad, dil, depo, dagitim]) => ({ ad, ister: { dil, depo, dagitim } }));

// PY15 — disina cikan ekip, disarida kaldigi eksene bagli destek kalemlerinin hepsini
// kaybeder; ici eksenlerin kalemlerini kullanmayi surdurur.
const YOL0 = { dil: ["dil A"], depo: ["iliskisel"], dagitim: ["uzun omurlu servis"] };
const disari = (yol, e) => EKSEN.filter((x) => !yol[x].includes(e.ister[x]));
const kayip = (yol, e) => KALEM.filter((k) => disari(yol, e).includes(k.eksen));
const kazanc = (yol, e) => KALEM.filter((k) => !disari(yol, e).includes(k.eksen))
  .reduce((t, k) => t + k.deger, 0);
writeFileSync("yol.json", JSON.stringify({ KALEM, EKSEN, EKIP, YOL0 }));

const eksenToplam = (x) => KALEM.filter((k) => k.eksen === x).reduce((t, k) => t + k.deger, 0);
console.log("eksen".padEnd(10) + "kalem".padStart(6) + "toplam deger".padStart(14) +
  "secenek basina bakim".padStart(22) + "   kalemler");
for (const x of EKSEN) {
  const g = KALEM.filter((k) => k.eksen === x);
  console.log(x.padEnd(10) + `${g.length}`.padStart(6) + `${eksenToplam(x)}`.padStart(14) +
    `${g.reduce((t, k) => t + k.bakim, 0)}`.padStart(22) + "   " + g.map((k) => k.ad).join(", "));
}
console.log(`yola tam sigan ekibin yillik kazanci: ` +
  `${KALEM.reduce((t, k) => t + k.deger, 0)} is gunu`);

const TAM = KALEM.reduce((t, k) => t + k.deger, 0);
console.log("\nyol: dil A / iliskisel / uzun omurlu servis");
console.log("ekip".padEnd(13) + "sigan eksen".padStart(12) + "kazanc".padStart(8) +
  "yolun payi".padStart(12) + "kayip kalem".padStart(13) + "kayip deger".padStart(13) +
  "   disarida kalan eksen");
for (const e of EKIP) {
  const d = disari(YOL0, e), K = kayip(YOL0, e);
  console.log(e.ad.padEnd(13) + `${EKSEN.length - d.length}/3`.padStart(12) +
    `${kazanc(YOL0, e)}`.padStart(8) +
    `%${(100 * kazanc(YOL0, e) / TAM).toFixed(0)}`.padStart(12) + `${K.length}`.padStart(13) +
    `${K.reduce((t, k) => t + k.deger, 0)}`.padStart(13) +
    "   " + (d.length ? d.map((x) => `${x} (${e.ister[x]})`).join(", ") : "-"));
}
console.log("eksen basina disarida kalan ekip — " +
  EKSEN.map((x) => `${x}: ${EKIP.filter((e) => disari(YOL0, e).includes(x)).length}`).join(", "));

console.log("\ndisina cikanin kalem kalem kaybettigi destek:");
for (const e of EKIP.filter((e) => disari(YOL0, e).length))
  console.log(`  ${e.ad}: ` + kayip(YOL0, e).map((k) => `${k.ad} (${k.deger})`).join(", "));
```

```
eksen      kalem  toplam deger  secenek basina bakim   kalemler
dil            4            23                    15   iskelet uretimi, derleme hatti, bagimlilik taramasi, sinama kosumu
depo           3            20                    14   sema gocu, yedek ve geri alma, baglanti havuzu
dagitim        3            21                    13   dagitim adimi, geri alma adimi, gosterge baglama
yola tam sigan ekibin yillik kazanci: 64 is gunu

yol: dil A / iliskisel / uzun omurlu servis
ekip          sigan eksen  kazanc  yolun payi  kayip kalem  kayip deger   disarida kalan eksen
sayac okuma           1/3      23         %36            6           41   depo (zaman serisi), dagitim (kenar birimi)
dogrulama             2/3      43         %67            3           21   dagitim (toplu is)
faturalama            2/3      41         %64            4           23   dil (dil B)
saha                  0/3       0          %0           10           64   dil (dil C), depo (belge), dagitim (kenar birimi)
raporlama             3/3      64        %100            0            0   -
eksen basina disarida kalan ekip — dil: 2, depo: 2, dagitim: 3

disina cikanin kalem kalem kaybettigi destek:
  sayac okuma: sema gocu (7), yedek ve geri alma (9), baglanti havuzu (4), dagitim adimi (10), geri alma adimi (6), gosterge baglama (5)
  dogrulama: dagitim adimi (10), geri alma adimi (6), gosterge baglama (5)
  faturalama: iskelet uretimi (6), derleme hatti (8), bagimlilik taramasi (5), sinama kosumu (4)
  saha: iskelet uretimi (6), derleme hatti (8), bagimlilik taramasi (5), sinama kosumu (4), sema gocu (7), yedek ve geri alma (9), baglanti havuzu (4), dagitim adimi (10), geri alma adimi (6), gosterge baglama (5)
```

#### Kimin Dışında Kaldığı

Yola tam sığan bir ekip yılda **64 iş günü** kazanır. Başlangıç yolunda — dil A, ilişkisel depo,
uzun ömürlü servis — bu kazancı **beş ekipten yalnız biri** alır: `raporlama`. Geri kalan dördü
yedi ekip-eksen çiftinde dışarıdadır.

Dışarıda kalmanın dereceleri vardır ve tablo bunu ayırır. `dogrulama` üç eksenin ikisinde
içeridedir: dil ve depo desteğini alır, yalnız dağıtım kalemlerini kaybeder — dağıtım adımı (10),
geri alma adımı (6), gösterge bağlama (5), toplam **21 iş günü**. `faturalama` da 2/3'tür ama
kaybettiği eksen dildir: dört kalem, **23 iş günü**. `sayac okuma` iki eksende dışarıdadır ve
altı kalem, **41 iş günü** kaybeder — yolun içinde olduğu tek eksen dil olduğu için kazancı 23'te
kalır.

`saha` ekibi sıfır eksende içeridedir. On destek kaleminin **hepsini** kaybeder ve yoldan **hiçbir
şey** almaz. Bu ayrımın karar değeri şudur: `dogrulama` için yolun dışına çıkmak 21 iş günlük bir
eksiktir, `saha` için yolun varlığı ile yokluğu aynı şeydir. **Aynı yol, aynı kuruluşta, bir ekibe
küçük bir eksik, başka bir ekibe tam bir yokluk olarak görünür.**

Kısmen sığan ekipler bu kursun **sızan soyutlama** dediği durumun kendisidir. `sayac okuma`
platformun içindedir — iskelet üretimini, derleme hattını, bağımlılık taramasını ve sınama koşumunu
platformdan alır — ama şema göçünü, yedeği, bağlantı havuzunu, dağıtımı, geri almayı ve gösterge
bağlamayı kendi kurar. Ekip her iki dünyayı birden bilmek zorundadır; yolun sağladığı sadeleşme onun
için **%36**'da kalır. `dogrulama` için %67, `faturalama` için %64. Yolun ortalama etkisi bu beş
ekipte %53'tür, oysa tanım "beş ekipten biri hariç hepsi kısmen destekleniyor" cümlesiyle çok daha
iyi görünür.

Son satır hangi ekseni genişletmek gerektiğini söyler: dil ekseninde iki, depo ekseninde iki,
dağıtım ekseninde **üç** ekip dışarıdadır. Kapsam kararı, en çok ekibin çarptığı eksenden başlar —
tabloda o eksen dağıtım biçimidir.

#### Yolu Genişletmek

**PY16 — yolun bakım yükü, her destek kaleminin bağlı olduğu eksendeki seçenek sayısıyla
çarpılmasıdır**; kapsama eklenen her seçenek o eksenin bütün kalemlerinin bakımını bir kez daha
getirir. **PY17 — yolun kendi karmaşıklığı, sınanması gereken bileşim sayısıdır (dil × depo ×
dağıtım) ve her bileşim yılda 3 iş günü tutar.** Gerekçe: kapsam genişledikçe kalemler yalnız
çoğalmaz, birbirleriyle çarpışır; bir dil ile bir depo bir arada çalışıyor diye o dilin başka bir
depoyla çalışacağı çıkmaz. **PY18 — genişletme her adımda tek eksene tek seçenek ekler.**

```js
// genislet.mjs — yolun kapsami adim adim genisletilir
import { readFileSync } from "node:fs";
const { KALEM, EKSEN, EKIP, YOL0 } = JSON.parse(readFileSync("yol.json", "utf8"));

// PY16 — yolun bakim yuku, her destek kaleminin bagli oldugu eksendeki secenek sayisiyla
// carpilmasidir: kapsama eklenen her secenek o eksenin butun kalemlerinin bakimini bir kez
// daha getirir. PY17 — yolun kendi karmasikligi, sinanmasi gereken bilesim sayisidir
// (dil x depo x dagitim) ve her bilesim yilda 3 is gunu tutar. PY18 — genisletme her adimda
// tek eksene tek secenek ekler.
const BILESIM_BEDELI = 3;
const ADIM = [
  ["dagitim", "toplu is"], ["dil", "dil B"], ["depo", "zaman serisi"],
  ["dagitim", "kenar birimi"], ["dil", "dil C"], ["depo", "belge"],
];
const disari = (yol, e) => EKSEN.filter((x) => !yol[x].includes(e.ister[x]));
const olc = (yol) => {
  const kazanc = EKIP.reduce((t, e) => t + KALEM
    .filter((k) => !disari(yol, e).includes(k.eksen)).reduce((a, k) => a + k.deger, 0), 0);
  const bakim = KALEM.reduce((t, k) => t + k.bakim * yol[k.eksen].length, 0);
  const bilesim = EKSEN.reduce((t, x) => t * yol[x].length, 1);
  return { kazanc, bakim, bilesim, yuk: bakim + bilesim * BILESIM_BEDELI,
    sigan: EKIP.filter((e) => disari(yol, e).length === 0).length,
    cikma: EKIP.reduce((t, e) => t + disari(yol, e).length, 0) };
};

const yol = { dil: [...YOL0.dil], depo: [...YOL0.depo], dagitim: [...YOL0.dagitim] };
const S = [{ ad: "baslangic", ...olc(yol), kapsam: "1/1/1" }];
for (const [eksen, secenek] of ADIM) {
  yol[eksen] = [...yol[eksen], secenek];
  S.push({ ad: `+${secenek}`, ...olc(yol),
    kapsam: EKSEN.map((x) => yol[x].length).join("/") });
}
console.log("asama".padEnd(16) + "kapsam".padStart(8) + "sigan ekip".padStart(11) +
  "disari cikma".padStart(13) + "kazanc".padStart(8) + "bakim".padStart(7) +
  "bilesim".padStart(9) + "bilesim yuku".padStart(14) + "toplam yuk".padStart(12) +
  "net".padStart(6));
for (const s of S)
  console.log(s.ad.padEnd(16) + s.kapsam.padStart(8) + `${s.sigan}/5`.padStart(11) +
    `${s.cikma}`.padStart(13) + `${s.kazanc}`.padStart(8) + `${s.bakim}`.padStart(7) +
    `${s.bilesim}`.padStart(9) + `${s.bilesim * BILESIM_BEDELI}`.padStart(14) +
    `${s.yuk}`.padStart(12) + `${s.kazanc - s.yuk}`.padStart(6));

const enIyi = S.reduce((a, b) => (a.kazanc - a.yuk >= b.kazanc - b.yuk ? a : b));
const son = S[S.length - 1], ilk = S[0];
console.log(`\nen yuksek net: "${enIyi.ad}" asamasi, kapsam ${enIyi.kapsam}, ` +
  `${enIyi.sigan}/5 ekip sigar, net ${enIyi.kazanc - enIyi.yuk} is gunu`);
console.log(`bes ekibin hepsinin sigdigi asama (${son.kapsam}): net ${son.kazanc - son.yuk} — ` +
  `baslangictan (${ilk.kapsam}, ${ilk.sigan}/5 ekip) ${ilk.kazanc - ilk.yuk - son.kazanc + son.yuk}` +
  ` is gunu dusuk`);
console.log(`kapsam bir seceneklikten uc seceneklige cikarken kazanc ` +
  `%${(100 * (son.kazanc / ilk.kazanc - 1)).toFixed(0)} artti, yuk ` +
  `%${(100 * (son.yuk / ilk.yuk - 1)).toFixed(0)} artti`);
```

```
asama             kapsam sigan ekip disari cikma  kazanc  bakim  bilesim  bilesim yuku  toplam yuk   net
baslangic          1/1/1        1/5            7     171     42        1             3          45   126
+toplu is          1/1/2        2/5            6     192     55        2             6          61   131
+dil B             2/1/2        3/5            5     215     70        4            12          82   133
+zaman serisi      2/2/2        3/5            4     235     84        8            24         108   127
+kenar birimi      2/2/3        4/5            2     277     97       12            36         133   144
+dil C             3/2/3        4/5            1     300    112       18            54         166   134
+belge             3/3/3        5/5            0     320    126       27            81         207   113

en yuksek net: "+kenar birimi" asamasi, kapsam 2/2/3, 4/5 ekip sigar, net 144 is gunu
bes ekibin hepsinin sigdigi asama (3/3/3): net 113 — baslangictan (1/1/1, 1/5 ekip) 13 is gunu dusuk
kapsam bir seceneklikten uc seceneklige cikarken kazanc %87 artti, yuk %360 artti
```

Tarama beklenen yönde başlar. Dağıtım eksenine toplu iş eklenince `dogrulama` yola girer ve net
126'dan 131'e çıkar; dil B eklenince `faturalama` girer, net 133 olur. Üçüncü adımda kırılma
görünür: zaman serisi deposu kapsama alınır, kazanç 215'ten 235'e çıkar ama **sığan ekip sayısı
değişmez** — `sayac okuma` hâlâ kenar birimini bekler — ve net 133'ten 127'ye düşer. Kapsam
büyümüştür, kimse yola girmemiştir.

Dördüncü adım en yüksek noktadır: kenar birimi eklenince hem `sayac okuma` yola girer hem `saha`
dağıtım kalemlerini kazanır, net **144 iş günü** olur. Kapsam 2/2/3'tür, beş ekipten dördü sığar.
Buradan sonrası kaybettirir: dil C eklenince net 134'e, belge deposu eklenince **113**'e iner.

Son satır dersin kararıdır. **Beş ekibin hepsinin sığdığı yol (3/3/3), hiç genişletilmemiş yoldan
13 iş günü daha kötüdür** — üstelik başlangıç yolunda beş ekipten yalnız biri sığıyordu. Kapsam bir
seçeneklikten üç seçenekliğe çıkarken kazanç **%87** arttı, yük **%360**. Sınanması gereken bileşim
sayısı birden yirmi yediye çıktı; yolun kendi karmaşıklığı, yolun ortadan kaldırdığı karmaşıklığı
geçti. Herkesi kapsayan yol, artık yol değildir.

#### Özet

- Altın yol üç eksende kapsam olarak yazıldı (dil, veri deposu, dağıtım biçimi) ve on destek
  kalemi eksenlere bağlandı; yola tam sığan ekip yılda 64 iş günü kazanır.
- Başlangıç yolunda beş ekipten yalnız `raporlama` tam sığar; kalan dördü yedi ekip-eksen çiftinde
  dışarıdadır.
- Dışarıda kalmanın derecesi ölçüldü: `dogrulama` 21, `faturalama` 23, `sayac okuma` 41 iş günü
  kaybeder; `saha` on kalemin hepsini kaybeder ve yoldan hiçbir şey almaz.
- Kısmen sığan ekip soyutlamanın sızdığı yerdir: `sayac okuma` yolun sadeleştirmesinin ancak
  %36'sını alır, geri kalanını kendi kurar ve iki dünyayı birden bilmek zorunda kalır.
- Kapsam genişletildikçe net 126, 131, 133, 127, 144, 134 ve 113 iş günü izler; en yüksek nokta
  2/2/3 kapsamında, beş ekipten dördünün sığdığı aşamadadır.
- Beş ekibin hepsinin sığdığı yol başlangıç yolundan 13 iş günü kötüdür; kapsam üçe çıkarken kazanç
  %87, yük %360 arttı ve sınanacak bileşim sayısı birden yirmi yediye çıktı.

#### Sonraki Adım

Bu derste yol bir kapsam olarak yazıldı ve kapsamın iki yüzü sayıldı: içeride kalanın kazancı,
dışarıda kalanın kaybı. Yolun tanımında söylenmeyen bir şey vardı — **yola girmek zorunlu muydu?**
Bütün tabloda ekiplerin gereksinimleri sabit tutuldu ve yol onlara uyduğu kadar uydu. Zorunluluk
konulsaydı `saha` ekibi kenar biriminden vazgeçer miydi, yoksa yol onun meşru bir gereksinimini mi
engellerdi? Sonraki ders her kalem için üç kip dener — zorunlu, öntanımlı ama değiştirilebilir,
serbest — ve çeşitlilik ile uyumu birlikte sayar: kaç ayrı seçim doğuyor, ortak araç kaç kalemde
işe yaramaz hâle geliyor, zorunluluk kaç ekipte gerçek bir gereksinimi engelliyor.

### Standart ve Özerklik Dengesi

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/standart-ve-ozerklik-dengesi

Zorunluluk ile seçim özgürlüğünün birlikte ölçülmesi: on kalemin her biri zorunlu, öntanımlı ve serbest kiplerde işletilir, doğan ayrı seçim sayısı ile ortak aracın işe yaradığı kalem sayısı yan yana sayılır, zorunluluğun kaç ekipte meşru bir gereksinimi engellediği çıkarılır ve korkuluk ile duvarın farkı iş günü cinsinden gösterilir.

Önceki ders altın yolu bir kapsam olarak yazdı ve kapsamın iki yüzünü saydı: içeride kalanın
kazancı, dışarıda kalanın kaybı. Tablonun tamamında ekiplerin gereksinimleri sabit tutuldu ve yol
onlara uyduğu kadar uydu. Söylenmeyen soru şuydu: **yola girmek zorunlu muydu?**

Zorunluluk ile seçim özgürlüğü aynı eksende iki uçtur ve ikisinin de kendi ölçüsü vardır.
Zorunluluk **uyum** üretir: aynı kalemde tek bir seçim varsa o kalem için tek bir ortak araç yazmak
yeter. Özgürlük **çeşitlilik** üretir: her ekip kendi işine uygun olanı seçer, ama ortak araç
seçenek sayısı arttıkça işe yaramaz hâle gelir. Bu ders ikisini aynı tabloda sayar ve zorunluluğun
iki ayrı biçimini ayırır. Through-line bölgesel ölçüm ağı ve onun beş ekibidir; ağ da ekipler de
kurgudur.

#### Üç Kip ve On Kalem

**PY19 — on kalemin her biri üç kipten birinde işletilir: zorunlu, öntanımlı ama değiştirilebilir,
serbest.** Her kalemin bir **ortak araç değeri** vardır: o kalem bütün kuruluşta tek seçenekte
durursa yılda kazanılan iş günü. **PY20 — her ekibin kalem başına tercihi ve tercihin gerekçesi
yazılır; gerekçe ya işin gerektirdiği bir meşru gereksinimdir ya da ekibin alışkanlığıdır.**
Gerekçe: zorunluluk ikisini de engeller, ama bedelleri aynı değildir ve ayrılmadan ölçülemez.

**PY21 — bir kalemde doğan ayrı seçim sayısı çeşitliliktir; ortak araç seçim sayısı bir ise
değerinin tamamını, iki ise yarısını, üç ve üstünde hiç vermez.** Serbest kipte platform hiçbir
seçenek önermez ve tercihi olmayan ekipler de kendi seçimlerini kurar. Gerekçe: öntanımlı bir
seçenek yoksa ekiplerin aynı noktada buluşması için sebep yoktur.

**PY22 — zorunluluk iki biçimde işletilir. Duvar hiçbir istisnaya izin vermez; korkuluk meşru
gerekçeyle istisna verir, alışkanlığa vermez.** Gerekçe: pratikte "zorunlu" tek bir şey değildir ve
ikisinin farkı ancak engellenen meşru gereksinim sayısıyla görünür.

```js
// kip.mjs — her kalem uc kipte islenir: zorunlu, ontanimli, serbest (model)
import { writeFileSync } from "node:fs";

// PY19 — on kalemin her biri uc kipten birinde isletilir. Her kalemin bir "ortak arac degeri"
// vardir: butun kuruluşta o kalem tek secenekte durursa yilda kazanilan is gunu.
// PY20 — her ekibin kalem basina tercihi bir dizede yazilir: "-" ontanimliyi kabul eder,
// "2m" iki numarali secenegi mesru bir gereksinim icin, "3a" uc numarali secenegi aliskanlik
// icin ister. Ekip sirasi: sayac okuma, dogrulama, faturalama, saha, raporlama. Kurgudur.
const EKIP = ["sayac okuma", "dogrulama", "faturalama", "saha", "raporlama"];
const KALEM = [
  ["gunluk bicimi", 14, "- - - - -"],
  ["gosterge adlandirmasi", 12, "- - 2a - -"],
  ["taban imge", 11, "- - - 2m -"],
  ["gizli deger deposu", 10, "2m - - - -"],
  ["dagitim adimi sirasi", 8, "- 2a - 3m -"],
  ["sinama esigi", 7, "- 2m - - 3a"],
  ["dil surumu", 6, "- - 2m - -"],
  ["ag kurali bicimi", 5, "2m - - 2m -"],
  ["veri deposu surumu", 4, "2m 3a - 4m -"],
  ["yedek araligi", 3, "- - 2m 3a 4a"],
].map(([ad, ortak, dize]) => ({ ad, ortak, tercih: dize.split(" ").map((s) =>
  s === "-" ? null : { secenek: parseInt(s, 10), mesru: s.endsWith("m") }) }));

// PY21 — bir kalemde dogan ayri secim sayisi cesitliliktir; ortak arac secim sayisi 1 ise
// degerinin tamamini, 2 ise yarisini (asagi yuvarlanarak) verir, 3 ve ustunde hic vermez.
// Serbest kipte platform hicbir secenek onermez; tercihi olmayan her ekip de kendi secimini
// kurar. Gerekce: ontanimli bir secenek yoksa ekiplerin ayni noktada bulusmasi icin sebep yok.
const KIP = {
  duvar: (t) => 1,
  korkuluk: (t) => (t && t.mesru ? t.secenek : 1),
  ontanimli: (t) => (t ? t.secenek : 1),
  serbest: (t, i) => (t ? t.secenek : 100 + i),
};
const secimler = (k, kip) => k.tercih.map((t, i) => KIP[kip](t, i));
const cesit = (k, kip) => new Set(secimler(k, kip)).size;
const uyum = (k, kip) => { const c = cesit(k, kip);
  return c === 1 ? k.ortak : c === 2 ? Math.floor(k.ortak / 2) : 0; };
const engel = (k, kip, mesru) => k.tercih.filter((t, i) =>
  t && t.mesru === mesru && KIP[kip](t, i) !== t.secenek).length;
writeFileSync("kip.json", JSON.stringify({ EKIP, KALEM }));

const KIPLER = ["duvar", "korkuluk", "ontanimli", "serbest"];
console.log("kalem".padEnd(23) + "ortak".padStart(6) +
  KIPLER.map((x) => `${x} c/u`.padStart(16)).join("") + "engel m/a".padStart(11));
for (const k of KALEM)
  console.log(k.ad.padEnd(23) + `${k.ortak}`.padStart(6) +
    KIPLER.map((x) => `${cesit(k, x)} / ${uyum(k, x)}`.padStart(16)).join("") +
    `${engel(k, "duvar", true)} / ${engel(k, "duvar", false)}`.padStart(11));
const T = (f) => KALEM.reduce((t, k) => t + f(k), 0);
console.log("TOPLAM".padEnd(23) + `${T((k) => k.ortak)}`.padStart(6) +
  KIPLER.map((x) => `${T((k) => cesit(k, x))} / ${T((k) => uyum(k, x))}`.padStart(16)).join("") +
  `${T((k) => engel(k, "duvar", true))} / ${T((k) => engel(k, "duvar", false))}`.padStart(11));
console.log("\nc = kalemde dogan ayri secim sayisi, u = ortak aracin verdigi is gunu");
console.log("engel m/a = duvar kipinde engellenen mesru gereksinim / aliskanlik sayisi");
```

```
kalem                   ortak       duvar c/u    korkuluk c/u   ontanimli c/u     serbest c/u  engel m/a
gunluk bicimi              14          1 / 14          1 / 14          1 / 14           5 / 0      0 / 0
gosterge adlandirmasi      12          1 / 12          1 / 12           2 / 6           5 / 0      0 / 1
taban imge                 11          1 / 11           2 / 5           2 / 5           5 / 0      1 / 0
gizli deger deposu         10          1 / 10           2 / 5           2 / 5           5 / 0      1 / 0
dagitim adimi sirasi        8           1 / 8           2 / 4           3 / 0           5 / 0      1 / 1
sinama esigi                7           1 / 7           2 / 3           3 / 0           5 / 0      1 / 1
dil surumu                  6           1 / 6           2 / 3           2 / 3           5 / 0      1 / 0
ag kurali bicimi            5           1 / 5           2 / 2           2 / 2           4 / 0      2 / 0
veri deposu surumu          4           1 / 4           3 / 0           4 / 0           5 / 0      2 / 1
yedek araligi               3           1 / 3           2 / 1           4 / 0           5 / 0      1 / 2
TOPLAM                     80         10 / 80         19 / 49         25 / 35          49 / 0     10 / 6

c = kalemde dogan ayri secim sayisi, u = ortak aracin verdigi is gunu
engel m/a = duvar kipinde engellenen mesru gereksinim / aliskanlik sayisi
```

#### Çeşitlilik ile Uyum

Toplam satırı dört kipi tek bakışta verir. Duvar kipinde çeşitlilik **10**'dur — on kalem, on
seçim — ve ortak araç değerinin **tamamı** alınır: 80 iş günü. Serbest kipte çeşitlilik **49**'a
çıkar ve ortak araç **80 iş gününün sıfırını** verir. Aradaki iki kip sırasıyla 19 ve 25
çeşitlilikte, 49 ve 35 iş günü değerdedir.

Sayılar kipin adından bağımsız bir kural gösterir: çeşitlilik iki katına çıktığında ortak aracın
değeri yarıya inmez, çok daha hızlı düşer. `veri deposu surumu` kaleminde öntanımlı kip dört ayrı
seçim doğurur ve dört iş günlük ortak araç değeri sıfırlanır; `yedek araligi` kaleminde aynı şey
olur. Serbest kipte ise `ag kurali bicimi` dışındaki her kalem beş ayrı seçim doğurur, çünkü
tercihi olmayan ekipler de kendi yollarına gider.

Son sütun zorunluluğun ne engellediğini ayırır. Duvar kipi **on meşru gereksinimi** ve **altı
alışkanlığı** engeller. Bu on gereksinim dört ekibe dağılmıştır ve hepsi işin gerektirdiği
seçimlerdir: `saha` ekibinin taban imgesi, `sayac okuma` ekibinin gizli değer deposu ve ağ kuralı
biçimi, `faturalama` ekibinin dil sürümü. Zorunluluk bunları engellediğinde ekip işini yapmaz
değildir — **dolambaç kurar** ve dolambacın bedeli bir sonraki tablodadır.

#### Korkuluk mu, Duvar mı

**PY23 — bedeller: engellenen her meşru gereksinim 8 iş günü, engellenen her alışkanlık 1 iş günü,
bir kalemde ilk seçenekten sonraki her seçenek 4 iş günü ortak bakım.** Gerekçe: bir alışkanlığı
engellemek sürtünme yaratır, meşru bir gereksinimi engellemek iş yaratır; ikisi aynı sayıyla
yazılamaz. **PY24 — beşinci bir düzen, karma, her kalem için dört kipin net değerini ayrı ayrı
hesaplar ve en yükseğini seçer; eşitlikte daha serbest kip yeğlenir.**

```js
// duzen.mjs — bes duzen, korkuluk ile duvarin farki ve kalem basina en iyi kip
import { readFileSync } from "node:fs";
const { KALEM } = JSON.parse(readFileSync("kip.json", "utf8"));

// PY23 — bedeller: engellenen her mesru gereksinim 8 is gunu (ekip dolambac kurar),
// engellenen her aliskanlik 1 is gunu (surtunme), bir kalemde ilk secenekten sonraki her
// secenek 4 is gunu ortak bakim. PY24 — besinci duzen karma: her kalem icin dort kipin net
// degeri ayri ayri hesaplanir, en yuksek olan secilir, esitlikte daha serbest kip yeglenir.
const MESRU = 8, ALISKANLIK = 1, SECENEK = 4;
const KIP = { duvar: (t) => 1, korkuluk: (t) => (t && t.mesru ? t.secenek : 1),
  ontanimli: (t) => (t ? t.secenek : 1), serbest: (t, i) => (t ? t.secenek : 100 + i) };
const KIPLER = ["duvar", "korkuluk", "ontanimli", "serbest"];
const cesit = (k, x) => new Set(k.tercih.map((t, i) => KIP[x](t, i))).size;
const uyum = (k, x) => { const c = cesit(k, x);
  return c === 1 ? k.ortak : c === 2 ? Math.floor(k.ortak / 2) : 0; };
const engel = (k, x, m) => k.tercih.filter((t, i) =>
  t && t.mesru === m && KIP[x](t, i) !== t.secenek).length;
const net = (k, x) => uyum(k, x) - MESRU * engel(k, x, true) -
  ALISKANLIK * engel(k, x, false) - SECENEK * (cesit(k, x) - 1);

const enIyi = KALEM.map((k) => {
  const s = KIPLER.map((x) => ({ x, n: net(k, x) }));
  const ust = Math.max(...s.map((y) => y.n));
  return { ...k, kip: s.filter((y) => y.n === ust).pop().x, n: ust };
});
const DUZEN = [...KIPLER.map((x) => ({ ad: x, kip: () => x })),
  { ad: "karma", kip: (k) => enIyi.find((y) => y.ad === k.ad).kip }];

const T = (f) => KALEM.reduce((t, k) => t + f(k), 0);
console.log("duzen".padEnd(12) + "cesitlilik".padStart(11) + "ortak arac".padStart(11) +
  "ise yaramaz".padStart(13) + "uyum".padStart(6) + "engel mesru".padStart(13) +
  "engel alisk.".padStart(14) + "secenek bakimi".padStart(16) + "net".padStart(6));
for (const d of DUZEN) {
  const c = (k) => cesit(k, d.kip(k));
  console.log(d.ad.padEnd(12) + `${T(c)}`.padStart(11) +
    `${KALEM.filter((k) => c(k) <= 2).length}/10`.padStart(11) +
    `${KALEM.filter((k) => c(k) >= 3).length}`.padStart(13) +
    `${T((k) => uyum(k, d.kip(k)))}`.padStart(6) +
    `${T((k) => engel(k, d.kip(k), true))}`.padStart(13) +
    `${T((k) => engel(k, d.kip(k), false))}`.padStart(14) +
    `${SECENEK * (T(c) - KALEM.length)}`.padStart(16) +
    `${T((k) => net(k, d.kip(k)))}`.padStart(6));
}

const fark = T((k) => uyum(k, "duvar")) - T((k) => uyum(k, "korkuluk"));
console.log(`\nkorkuluk ile duvarin farki: duvar 10 mesru gereksinimi engelleyip ortak arac ` +
  `degerini ${fark} is gunu artirir — engellenen gereksinim basina ${(fark / 10).toFixed(1)} ` +
  `is gunu, oysa bir gereksinimi engellemenin bedeli ${MESRU} is gunu`);
console.log("kalem basina en iyi kip — " + KIPLER
  .map((x) => `${x}: ${enIyi.filter((y) => y.kip === x).length}`).join(", "));
for (const x of KIPLER) {
  const g = enIyi.filter((y) => y.kip === x);
  if (g.length) console.log(`  ${x}: ` + g.map((y) => `${y.ad} (${y.n})`).join(", "));
}
```

```
duzen        cesitlilik ortak arac  ise yaramaz  uyum  engel mesru  engel alisk.  secenek bakimi   net
duvar                10      10/10            0    80           10             6               0    -6
korkuluk             19       9/10            1    49            0             6              36     7
ontanimli            25       6/10            4    35            0             0              60   -25
serbest              49       0/10           10     0            0             0             156  -156
karma                17       9/10            1    60            2             6              28    10

korkuluk ile duvarin farki: duvar 10 mesru gereksinimi engelleyip ortak arac degerini 31 is gunu artirir — engellenen gereksinim basina 3.1 is gunu, oysa bir gereksinimi engellemenin bedeli 8 is gunu
kalem basina en iyi kip — duvar: 2, korkuluk: 5, ontanimli: 3, serbest: 0
  duvar: taban imge (3), gizli deger deposu (2)
  korkuluk: gosterge adlandirmasi (11), dagitim adimi sirasi (-1), sinama esigi (-2), veri deposu surumu (-9), yedek araligi (-5)
  ontanimli: gunluk bicimi (14), dil surumu (-1), ag kurali bicimi (-2)
```

Tekdüze düzenlerin hepsi ya zarar eder ya çok az kazanır. Duvar **−6**, öntanımlı **−25**, serbest
**−156** iş günü verir; tek pozitif tekdüze düzen korkuluktur (**+7**). Serbest düzenin sayısı
tartışma bırakmaz: on kalemin **hepsinde** ortak araç işe yaramaz hâle gelir ve 156 iş günü yalnız
seçenek bakımına gider.

Öntanımlı kipin sonucu daha şaşırtıcıdır. Hiçbir meşru gereksinimi, hiçbir alışkanlığı engellemez —
ve buna rağmen duvardan **19 iş günü daha kötüdür**. Nedeni ortadaki iki sütundur: çeşitliliği
25'e çıkarır, ortak aracı dört kalemde bitirir ve 60 iş günü seçenek bakımı ödettirir. **Hiçbir
şeyi engellememek bedava değildir.**

Korkuluk ile duvarın farkı tek bir satırda sayılır. Duvar, korkuluğun izin verdiği on meşru
gereksinimi engelleyerek ortak araç değerini 49'dan 80'e, yani **31 iş günü** yükseltir. Engellenen
gereksinim başına bu **3,1 iş günü**dür; oysa bir meşru gereksinimi engellemenin bedeli 8 iş
günüdür. **Duvar, aldığının iki buçuk katından fazlasını ödemektedir.** İki kipin engellediği
alışkanlık sayısı ise aynıdır (6): korkuluk da alışkanlığa istisna vermez. Korkuluğun duvardan
farkı yalnız meşru gereksinimlerdedir ve bunun karşılığında çeşitliliği 10'dan 19'a çıkarma
bedelini (36 iş günü) öder.

Karma düzen kararı kalem başına verir ve **+10** ile en yükseğidir. Dağılım şudur: iki kalemde
duvar, beş kalemde korkuluk, üç kalemde öntanımlı, **hiçbir kalemde serbest**. Duvarın kazandığı
iki kalem `taban imge` (11) ve `gizli deger deposu` (10) — ortak araç değeri en yüksek olanlardan
ikisi. Bu iki kalemde zorunluluk **bir meşru gereksinimi engellemeye değer**, çünkü ortak aracın
tam değeri engelleme bedelini aşar. Kalan sekiz kalemde değmez. Kip seçimi bir yönetim tercihi
değil, kalemin ortak araç değeri ile engellenen gereksinim sayısı arasındaki bir hesaptır.

#### Özet

- On kalem dört kipte koşturuldu: çeşitlilik duvarda 10, korkulukta 19, öntanımlıda 25, serbestte
  49; ortak aracın verdiği değer sırasıyla 80, 49, 35 ve 0 iş günüdür.
- Serbest kipte ortak araç on kalemin hepsinde işe yaramaz hâle gelir; öntanımlı kipte dört
  kalemde, korkulukta bir kalemde, duvarda hiç.
- Duvar on meşru gereksinimi ve altı alışkanlığı engeller; korkuluk aynı altı alışkanlığı engeller
  ama meşru gereksinimlerin hiçbirini engellemez.
- Duvarın korkuluktan aldığı fark 31 iş günü ek ortak araç değeridir, engellenen gereksinim başına
  3,1 iş günü — bir gereksinimi engellemenin 8 iş günlük bedelinin altında.
- Tekdüze düzenlerde net: duvar −6, korkuluk +7, öntanımlı −25, serbest −156 iş günü. Hiçbir şeyi
  engellemeyen öntanımlı düzen duvardan 19 iş günü daha kötüdür.
- Kalem başına en iyi kip seçildiğinde net +10 olur: iki kalemde duvar, beş kalemde korkuluk, üç
  kalemde öntanımlı, hiçbir kalemde serbest.

#### Sonraki Adım

Dört derste platform bir maliyet hesabı, bir işletme biçimi, bir kapsam ve bir kip seçimi olarak
ölçüldü. Dördünde de ortak bir varsayım vardı: bir ekip bir şey istediğinde **platform ekibinden
biri onu yapıyor**. Kip tablosunda öntanımlı bir seçeneği değiştirmek, kapsam tablosunda yola
girmek, istek tablosunda bir yeteneği almak — hepsi bir insanın elinden geçiyordu. Sonraki ders bu
varsayımı kaldırır: aynı istek kümesi bir talep kuyruğunda ve kendi kendine hizmet düzeninde
koşturulur; bekleme süresi, platform ekibinin kesintisi ve kendi kendine hizmetin kendi bedeli —
arayüz yazma işi, yanlış kullanım ve geri alınamayan işlem — sayılır.

### Kendi Kendine Hizmet

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/kendi-kendine-hizmet

Talep kuyruğunun ortadan kaldırılmasının ölçülmesi: aynı istek kümesi bir talep kuyruğunda ve kendi kendine hizmet düzeninde koşturulur, bekleme süresi ile platform ekibinin kesintisi sayılır, arayüz yazma işi, yanlış kullanım ve geri alınamayan işlem bedelleri çıkarılır ve otomatikleştirmenin karşılığını vermediği istek türü adıyla yazılır.

Dört derste platform bir maliyet hesabı, bir işletme biçimi, bir kapsam ve bir kip seçimi olarak
ölçüldü. Dördünde de ortak bir varsayım vardı: bir ekip bir şey istediğinde **platform ekibinden
biri onu yapıyor**. Öntanımlı bir seçeneği değiştirmek, yola girmek, bir yeteneği almak — hepsi bir
insanın elinden geçiyordu. O insan bir kuyruğun arkasındadır.

Bu ders kuyruğu ölçer ve kaldırmayı dener. Kendi kendine hizmet, isteği platform ekibinin elinden
alıp isteği açan ekibin eline verir. Bunun kazancı bekleme süresi ve kesintidir; bedeli ise
arayüzü yazma işi, arayüzün bakımı, yanlış kullanım ve **geri alınamayan işlem**dir. Sayılar
otomatikleştirmenin nerede karşılığını vermediğini de gösterir. Through-line bölgesel ölçüm ağı ve
onun beş ekibidir; ağ da ekipler de kurgudur.

#### Talep Kuyruğu

**PY25 — on iki istek türü vardır; her tür yılda kaç kez geldiğiyle, elle yapılışının kaç saat
sürdüğüyle ve değişkenliğiyle yazılır.** Değişkenlik sıfırsa istek her seferinde birebir aynıdır,
bire yakınsa her seferinde farklıdır. Gerekçe: bir isteğin otomatikleştirilebilirliği sıklığından
değil, seferden sefere ne kadar değiştiğinden gelir; iki sayı ayrılmadan eşik çıkmaz.

**PY26 — talep kuyruğunda istek platform ekibine gider; ekip günde 4 saatini isteklere ayırır ve
sırayla işler. Her istek elle işinin üstüne 0,25 saat kesinti getirir.** Gerekçe: elle yapılan
işin bedeli yalnız o işin süresi değildir; ekip başka bir işten çıkıp isteğe döner ve geri döndüğü
işi yeniden kurar. Pencere üç yıl, yıl 250 iş günü, gün 8 saattir.

```js
// kuyruk.mjs — ayni istek kumesi bir talep kuyrugunda kosturulur (model)
import { writeFileSync } from "node:fs";

// PY25 — on iki istek turu: ad, yilda kac kez geldigi, elle yapilisinin isi (saat) ve
// degiskenlik (0 = her seferinde birebir ayni, 1 = her seferinde farkli). Sayilar kurgudur.
const TUR = [
  ["hat degiskeni degistirme", 150, 0.3, 0.05], ["yetki verme", 120, 0.4, 0.05],
  ["gizli deger ekleme", 90, 0.5, 0.05], ["yeni ortam acma", 40, 3, 0.10],
  ["gosterge panosu ekleme", 30, 2, 0.30], ["veri tabani kopyasi", 24, 4, 0.20],
  ["alan adi baglama", 20, 1.5, 0.15], ["yeni servis iskeleti", 18, 6, 0.25],
  ["denetim kaydi cikarma", 12, 2.5, 0.40], ["yedekten geri donme", 6, 8, 0.60],
  ["kume surum yukseltme", 4, 20, 0.50], ["bolge tasima", 3, 40, 0.90],
].map(([ad, yilda, saat, degisken]) => ({ ad, yilda, saat, degisken }));

// PY26 — talep kuyrugu: istek platform ekibine gider, ekip gunde 4 saatini isteklere ayirir
// ve sirayla isler. Her istek elle isinin ustune 0.25 saat kesinti getirir: ekip baska bir
// isten cikip istege doner. Pencere uc yil, yil 250 is gunu, gun 8 saattir.
const GUNLUK = 4, YIL = 250, PENCERE = 3, KESINTI = 0.25, SAAT = 8;

function kuyruk(pay) {
  const gelis = TUR.flatMap((t, i) => {
    const n = t.yilda * PENCERE, is = t.saat * (pay ? pay(t) : 1);
    return Array.from({ length: n }, (_, j) => ({ tur: i, gun: (j + 0.5) * YIL * PENCERE / n,
      is: is + KESINTI }));
  }).sort((a, b) => a.gun - b.gun);
  let bos = 0, toplam = 0;
  for (const g of gelis) {
    bos = Math.max(bos, g.gun * GUNLUK) + g.is;
    g.bekleme = bos / GUNLUK - g.gun;
    toplam += g.is;
  }
  const b = gelis.map((g) => g.bekleme).sort((x, y) => x - y);
  return { gelis, sayi: gelis.length, toplam,
    ort: b.reduce((x, y) => x + y, 0) / b.length, ortanca: b[b.length >> 1], enUzun: b.at(-1),
    doluluk: toplam / (YIL * PENCERE * GUNLUK) };
}
const K = kuyruk(null);
writeFileSync("kuyruk.json", JSON.stringify({ TUR, temel: {
  ort: K.ort, ortanca: K.ortanca, enUzun: K.enUzun, toplam: K.toplam, sayi: K.sayi } }));

console.log("tur".padEnd(26) + "yilda".padStart(6) + "saat".padStart(6) +
  "degisken".padStart(10) + "3 yilda istek".padStart(14) + "elle is (gun)".padStart(14) +
  "ort. bekleme (gun)".padStart(20));
for (let i = 0; i < TUR.length; i++) {
  const g = K.gelis.filter((x) => x.tur === i);
  console.log(TUR[i].ad.padEnd(26) + `${TUR[i].yilda}`.padStart(6) +
    `${TUR[i].saat}`.padStart(6) + `${TUR[i].degisken.toFixed(2)}`.padStart(10) +
    `${g.length}`.padStart(14) +
    `${(g.length * TUR[i].saat / SAAT).toFixed(1)}`.padStart(14) +
    `${(g.reduce((t, x) => t + x.bekleme, 0) / g.length).toFixed(1)}`.padStart(20));
}
const kesinti = K.sayi * KESINTI / SAAT;
console.log(`\nuc yilda ${K.sayi} istek, ${(K.toplam / SAAT).toFixed(1)} is gunu ` +
  `(bunun ${kesinti.toFixed(1)} is gunu yalniz kesinti), doluluk %` +
  `${(100 * K.doluluk).toFixed(1)}`);
console.log(`bekleme: ortalama ${K.ort.toFixed(1)} gun, ortanca ${K.ortanca.toFixed(1)} gun, ` +
  `en uzun ${K.enUzun.toFixed(1)} gun`);
```

```
tur                        yilda  saat  degisken 3 yilda istek elle is (gun)  ort. bekleme (gun)
hat degiskeni degistirme     150   0.3      0.05           450          16.9                 4.8
yetki verme                  120   0.4      0.05           360          18.0                 4.7
gizli deger ekleme            90   0.5      0.05           270          16.9                 4.7
yeni ortam acma               40     3      0.10           120          45.0                 5.3
gosterge panosu ekleme        30     2      0.30            90          22.5                 5.0
veri tabani kopyasi           24     4      0.20            72          36.0                 5.6
alan adi baglama              20   1.5      0.15            60          11.3                 4.5
yeni servis iskeleti          18     6      0.25            54          40.5                 5.7
denetim kaydi cikarma         12   2.5      0.40            36          11.3                 4.4
yedekten geri donme            6     8      0.60            18          18.0                 7.4
kume surum yukseltme           4    20      0.50            12          30.0                 8.4
bolge tasima                   3    40      0.90             9          45.0                11.1

uc yilda 1551 istek, 359.7 is gunu (bunun 48.5 is gunu yalniz kesinti), doluluk %95.9
bekleme: ortalama 5.0 gun, ortanca 4.5 gun, en uzun 13.0 gun
```

Kuyruk üç yılda **1551 istek** görür ve **359,7 iş günü** harcar. Bunun **48,5 iş günü** hiçbir
isteği ilerletmez: yalnız bağlam değiştirme bedeli, harcanan işin **%13,5**'i. Doluluk **%95,9**'dur
ve bu oran beklemenin neden bu kadar uzun olduğunu açıklar: ortalama bekleme **5 gün**, en uzunu
**13 gün**.

Bekleme türlere eşit dağılmaz. Bir hat değişkeni değişikliği ortalama 4,8 gün, kırk saatlik bir
bölge taşıma 11,1 gün bekler; küçük işler büyük olanların arkasında bekler. Ortancanın (4,5)
ortalamanın (5,0) altında kalması bunu gösterir — birkaç uzun iş dağılımı yukarı çeker.

#### Kendi Kendine Hizmetin Bedeli

**PY27 — bir tür için arayüz yazma işi 4 + 20 × değişkenlik iş günüdür, yıllık bakımı bu işin beşte
biridir ve arayüz isteklerin ancak (1 − değişkenlik) kadarını karşılar; kalanı yine elle yapılır.**
Gerekçe: her seferinde farklı olan bir isteği bir arayüzün arkasına almak, o isteğin ancak
değişmeyen kısmını alır.

**PY28 — kendi kendine hizmette isteklerin 0,02 + 0,10 × değişkenlik kadarı yanlış kullanılır;
bunların %85'i geri alınabilir (0,5 iş günü düzeltme), %15'i geri alınamaz (6 iş günü kurtarma).**
Gerekçe: arayüzün arkasındaki işlemi yapan kişi o işi ilk kez yapıyordur ve kimse omzunun üstünden
bakmamaktadır. **PY29 — bir tür için arayüz, üç yıllık penceredeki toplamı elle düzenin toplamını
aşmazsa kendini öder.** **PY30 — karma düzen yalnız kendini ödeyen türler için arayüz yazar;
geri kalanlar ve otomatikleştirilenin elle kalan payı kuyrukta durur.**

```js
// hizmet.mjs — kendi kendine hizmetin bedeli, tur basina esik ve karma duzende kuyruk
import { readFileSync } from "node:fs";
const { TUR, temel } = JSON.parse(readFileSync("kuyruk.json", "utf8"));

// PY27 — bir tur icin arayuz yazma isi 4 + 20 x degiskenlik is gunudur, yillik bakim bu isin
// beste biridir ve arayuz isteklerin ancak (1 - degiskenlik) kadarini karsilar; kalani yine
// elle yapilir. PY28 — kendi kendine hizmette isteklerin 0.02 + 0.10 x degiskenlik kadari
// yanlis kullanilir; bunlarin %85'i geri alinabilir (0.5 is gunu duzeltme), %15'i geri
// alinamaz (6 is gunu kurtarma). PY29 — bir tur icin arayuz, uc yillik penceredeki toplami
// elle duzenin toplamini asmazsa kendini oder.
const GUNLUK = 4, YIL = 250, PENCERE = 3, KESINTI = 0.25, SAAT = 8;
const GERI_ALINABILIR = 0.5, GERI_ALINAMAZ = 6;

const hesap = TUR.map((t) => {
  const n = t.yilda * PENCERE, elle = n * (t.saat + KESINTI) / SAAT;
  const arayuz = 4 + 20 * t.degisken, bakim = PENCERE * arayuz / 5;
  const yanlis = n * (0.02 + 0.10 * t.degisken);
  const zarar = yanlis * 0.85 * GERI_ALINABILIR + yanlis * 0.15 * GERI_ALINAMAZ;
  const kendi = arayuz + bakim + t.degisken * elle + zarar;
  return { ...t, n, elle, arayuz, bakim, yanlis, zarar, kendi, fark: elle - kendi };
});

console.log("tur".padEnd(26) + "elle".padStart(7) + "arayuz".padStart(8) + "bakim".padStart(7) +
  "kalan elle".padStart(12) + "yanlis".padStart(8) + "geri alinamaz".padStart(15) +
  "zarar".padStart(7) + "kendi".padStart(7) + "fark".padStart(7));
for (const h of hesap)
  console.log(h.ad.padEnd(26) + h.elle.toFixed(1).padStart(7) + h.arayuz.toFixed(1).padStart(8) +
    h.bakim.toFixed(1).padStart(7) + (h.degisken * h.elle).toFixed(1).padStart(12) +
    h.yanlis.toFixed(1).padStart(8) + (h.yanlis * 0.15).toFixed(2).padStart(15) +
    h.zarar.toFixed(1).padStart(7) + h.kendi.toFixed(1).padStart(7) +
    ((h.fark >= 0 ? "+" : "") + h.fark.toFixed(1)).padStart(7));
const oden = hesap.filter((h) => h.fark > 0), odemez = hesap.filter((h) => h.fark <= 0);
console.log(`\nkendini odeyen tur: ${oden.length} / ${TUR.length}, ` +
  `toplam kazanc ${oden.reduce((t, h) => t + h.fark, 0).toFixed(1)} is gunu`);
console.log("odemeyenler — " + odemez.map((h) => `${h.ad} (${h.fark.toFixed(1)})`).join(", "));

// PY30 — karma duzen: yalniz kendini odeyen turler icin arayuz yazilir, geri kalanlar ve
// otomatiklestirilenin elle kalan payi kuyrukta durur. Kuyruk yeniden kosturulur.
const kuyruk = (pay) => {
  const gelis = TUR.flatMap((t, i) => {
    const n = Math.round(t.yilda * PENCERE * pay(hesap[i]));
    return Array.from({ length: n }, (_, j) => ({ gun: (j + 0.5) * YIL * PENCERE / n,
      is: t.saat + KESINTI }));
  }).sort((a, b) => a.gun - b.gun);
  let bos = 0, toplam = 0;
  for (const g of gelis) {
    bos = Math.max(bos, g.gun * GUNLUK) + g.is;
    g.bekleme = bos / GUNLUK - g.gun;
    toplam += g.is;
  }
  const b = gelis.map((g) => g.bekleme).sort((x, y) => x - y);
  return { sayi: gelis.length, gun: toplam / SAAT,
    ort: b.reduce((x, y) => x + y, 0) / b.length, enUzun: b.at(-1),
    doluluk: toplam / (YIL * PENCERE * GUNLUK) };
};
const K2 = kuyruk((h) => (h.fark > 0 ? h.degisken : 1));
const K3 = kuyruk((h) => h.degisken);
console.log("\n" + "duzen".padEnd(30) + "kuyruga giren".padStart(14) + "elle is".padStart(9) +
  "doluluk".padStart(9) + "ort. bekleme".padStart(14) + "en uzun".padStart(9));
console.log("talep kuyrugu (hepsi elle)".padEnd(30) + `${temel.sayi}`.padStart(14) +
  (temel.toplam / SAAT).toFixed(1).padStart(9) +
  `%${(100 * temel.toplam / (YIL * PENCERE * GUNLUK)).toFixed(1)}`.padStart(9) +
  temel.ort.toFixed(1).padStart(14) + temel.enUzun.toFixed(1).padStart(9));
for (const [ad, K] of [["karma (6 turde arayuz)", K2], ["hepsinde arayuz", K3]])
  console.log(ad.padEnd(30) + `${K.sayi}`.padStart(14) + K.gun.toFixed(1).padStart(9) +
    `%${(100 * K.doluluk).toFixed(1)}`.padStart(9) + K.ort.toFixed(1).padStart(14) +
    K.enUzun.toFixed(1).padStart(9));
const arayuzIsi = (H) => H.reduce((t, h) => t + h.arayuz + h.bakim + h.zarar, 0);
console.log(`\narayuz + bakim + zarar: karma duzende ${arayuzIsi(oden).toFixed(1)}, ` +
  `hepsinde ${arayuzIsi(hesap).toFixed(1)} is gunu`);
```

```
tur                          elle  arayuz  bakim  kalan elle  yanlis  geri alinamaz  zarar  kendi   fark
hat degiskeni degistirme     30.9     5.0    3.0         1.5    11.3           1.69   14.9   24.5   +6.5
yetki verme                  29.3     5.0    3.0         1.5     9.0           1.35   11.9   21.4   +7.9
gizli deger ekleme           25.3     5.0    3.0         1.3     6.8           1.01    8.9   18.2   +7.1
yeni ortam acma              48.8     6.0    3.6         4.9     3.6           0.54    4.8   19.2  +29.5
gosterge panosu ekleme       25.3    10.0    6.0         7.6     4.5           0.67    6.0   29.6   -4.2
veri tabani kopyasi          38.3     8.0    4.8         7.7     2.9           0.43    3.8   24.3  +14.0
alan adi baglama             13.1     7.0    4.2         2.0     2.1           0.32    2.8   16.0   -2.8
yeni servis iskeleti         42.2     9.0    5.4        10.5     2.4           0.36    3.2   28.2  +14.0
denetim kaydi cikarma        12.4    12.0    7.2         5.0     2.2           0.32    2.9   27.0  -14.6
yedekten geri donme          18.6    16.0    9.6        11.1     1.4           0.22    1.9   38.6  -20.1
kume surum yukseltme         30.4    14.0    8.4        15.2     0.8           0.13    1.1   38.7   -8.3
bolge tasima                 45.3    22.0   13.2        40.8     1.0           0.15    1.3   77.3  -32.0

kendini odeyen tur: 6 / 12, toplam kazanc 79.0 is gunu
odemeyenler — gosterge panosu ekleme (-4.2), alan adi baglama (-2.8), denetim kaydi cikarma (-14.6), yedekten geri donme (-20.1), kume surum yukseltme (-8.3), bolge tasima (-32.0)

duzen                          kuyruga giren  elle is  doluluk  ort. bekleme  en uzun
talep kuyrugu (hepsi elle)              1551    359.7    %95.9           5.0     13.0
karma (6 turde arayuz)                   320    172.6    %46.0           2.1     10.3
hepsinde arayuz                          170    108.8    %29.0           2.3     10.1

arayuz + bakim + zarar: karma duzende 108.4, hepsinde 253.9 is gunu
```

#### Otomatikleştirmenin Karşılığını Vermediği Yer

On iki türün **altısı** kendini öder ve toplam kazanç **79 iş günü**dür. Altısı ödemez ve listenin
sonu dersin adını koyduğu durumdur: **`bolge tasima` — yılda üç kez gelen, her seferinde farklı
olan istek.** Elle yapılması üç yılda 45,3 iş günü tutar; arayüzün arkasına alınması **77,3 iş
günü**, yani **32 iş günü daha fazla**. Hesap üç kalemden çıkar: arayüz 22 iş günü, üç yıllık bakım
13,2 iş günü ve — asıl olan — arayüz işin ancak onda birini karşıladığı için **40,8 iş günü elle iş
yerinde kalır**. Aynı biçim `yedekten geri donme` ve `kume surum yukseltme` türlerinde tekrarlanır.

İkinci bir bedel tablonun ortasındadır. `hat degiskeni degistirme` türünde arayüz kendini öder ama
kazancı yalnız 6,5 iş günüdür; oysa üç yılda **11,3 yanlış kullanım** doğar ve bunların **1,69'u
geri alınamaz** — toplam 14,9 iş günlük zarar, arayüz ve bakım işinin toplamından (8 iş günü) daha
büyüktür. **En sık gelen istek, arayüzün en çok yanlış kullanıldığı istektir**, çünkü yanlış
kullanım sayısı sıklıkla çarpılır. Elle düzende bu kalem hiç yoktu: bir insan işlemi yapmadan önce
bakıyordu.

Son tablo kuyruğun ne olduğunu gösterir. Karma düzende kuyruğa giren istek **1551'den 320'ye**,
elle iş **359,7'den 172,6 iş gününe**, doluluk **%95,9'dan %46'ya** iner; ortalama bekleme **5,0
günden 2,1 güne** düşer. **Altı türü otomatikleştirmek, kuyrukta kalan altı türün beklemesini de
kısaltır** — kuyruk boşaldığı için.

Hepsini otomatikleştirmek buradan öteye gitmez. Kuyruğa giren istek 170'e, elle iş 108,8 iş gününe
iner ama ortalama bekleme **2,3 güne çıkar**: kuyrukta kalan artık yalnız uzun ve değişken iştir ve
tek bir bölge taşıma sırayı günlerce kapatır. Bunun için ödenen arayüz, bakım ve zarar toplamı
**253,9 iş günü**, karma düzenin **108,4 iş gününün** iki katından fazladır. Kuyruğun tamamını
kaldırmak, kuyruğu kısaltmaktan **145 iş günü pahalı** ve beklemede karşılıksızdır.

#### Özet

- On iki istek türü üç yıllık pencerede kuyruğa girdi: 1551 istek, 359,7 iş günü elle iş, bunun
  48,5 iş günü (%13,5) yalnız kesinti; doluluk %95,9, ortalama bekleme 5,0 gün, en uzun 13,0 gün.
- Bekleme türlere eşit dağılmaz: hat değişkeni değiştirme 4,8 gün, bölge taşıma 11,1 gün bekler;
  ortanca (4,5) ortalamanın (5,0) altındadır.
- On iki türün altısı kendini öder ve 79 iş günü kazandırır; altısı ödemez.
- Otomatikleştirmenin karşılığını vermediği tür `bolge tasima`dır: yılda üç kez, her seferinde
  farklı. Elle 45,3 iş günü, arayüzle 77,3 iş günü — 32 iş günü kayıp, çünkü 40,8 iş günü elle iş
  yerinde kalır.
- Kendi kendine hizmetin ikinci bedeli yanlış kullanımdır: `hat degiskeni degistirme` türünde üç
  yılda 11,3 yanlış kullanım, 1,69'u geri alınamaz, toplam 14,9 iş günü — arayüz ve bakımın
  toplamından büyük.
- Karma düzende kuyruğa giren istek 1551'den 320'ye, doluluk %95,9'dan %46'ya, ortalama bekleme
  5,0'dan 2,1 güne iner. Hepsini otomatikleştirmek beklemeyi 2,3 güne çıkarır ve 145 iş günü daha
  pahalıdır.

#### Sonraki Adım

Bu beş derste platform bir yaklaşım olarak tanımlandı ve sınırları çizildi: hangi ekip sayısından
sonra kendini ödediği, iki işletme biçiminin benimseme ve ölü yetenek sayıları, yolun kapsamı ve
dışında kalanın kaybı, zorunluluğun üç kipi, kuyruğun bedeli ve kendi kendine hizmetin nerede
karşılığını vermediği. Hepsi platformun **nasıl** işletileceğine dair sayılardı.

Söylenmemiş olan şey **ne sunduğu**dur. Beş derste "yetenek", "kalem", "istek türü" adları geçti
ama hiçbiri açılmadı: ortamın istek üzerine nasıl geldiği, iskeletin neyi üretip neyi üretmediği,
kataloğun sahipliği nasıl tuttuğu, politikanın hatta nasıl gömüldüğü, maliyetin nasıl
bölüştürüldüğü, göçün nasıl yürüdüğü ve platformun etkisinin hangi ölçütle sayıldığı. Sonraki konu
bu yetenekleri tek tek açar ve her birini aynı ölçüyle — gizlenen katman, geri sızan kısım, dışına
çıkanlar — sayar.

## Platform Yetenekleri

Platformun sunduğu somut yetenekler ve etkilerinin ölçülmesi: istek üzerine ortam üretimi, yeni servis başlatan şablon ve iskelet üretimi, sahiplik ile bağımlılık görünürlüğü veren geliştirici portalı ve servis kataloğu, kuralların hatta gömülerek otomatikleştirilmesi, ekip bazlı kaynak muhasebesiyle maliyet görünürlüğü, platform geçişlerinin aşamalandırılması ve benimseme, teslimat hızı ile kararlılık göstergeleri.

### İstek Üzerine Ortam Sağlama

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/ortam-saglama

Aynı doksan günlük talep akışı iki yoldan geçirilir: insanın kurduğu talep kuyruğu ve istek üzerine üretilen ortam. Bekleme süresi, ortam ömrü, boşta duran ortam-günü ve unutulan ortam sayılır; ömür sınırı taranarak kısa ömrün yeniden kurma ve veri kaybı karşılığı çıkarılır.

Önceki konu platformun ne olduğunu tanımladı ve sınırlarını çizdi: hangi kararın devralındığı, hangisinin
ekipte kaldığı, iç müşterinin kim olduğu. Tanım yerinde duruyor, ama bir ekip sabah işe başladığında
platformdan somut olarak ne isteyeceği hâlâ söylenmedi. İstenecek ilk şey neredeyse her zaman aynıdır:
üzerinde çalışılacak bir ortam.

**İstek üzerine ortam**, bir ekibin ortam kurulumunu bir talep formuna yazıp beklemek yerine kendi
başlattığı ve kendi bitirdiği ortamdır. Ortamın nasıl sağlandığı — bildirimden gerçeğe giden yol, kayıt
ile gerçek arasındaki sapma — M22/K01'in ortam sağlama dersinde ve M22/K05'te ölçüldü; burada
tekrarlanmaz. Bu dersin ölçtüğü şey sağlama mekaniği değil, ortamın **yaşam döngüsüdür**: ne kadar
beklendiği, ne kadar yaşadığı ve yaşadığı sürenin ne kadarında kullanılmadığı.

Ölçüm **bölgesel ölçüm ağı** üzerindedir: su sayacı okumalarını toplayan, doğrulayan ve saha iş emri
açan **kurgu** yazılım. Gerçek altyapı kurulmaz; ölçülen şey `node` ile yazılmış bir **modeldir**.

**PT1.** Ağın yazılımını beş ekip üretir: sayaç okuma, doğrulama, faturalama, saha, raporlama. Ekipler
ve talep oranları kurgudur.
**PT2.** Gözlem penceresi 90 gündür. Talep akışı kendi yazılan bir üreteçle çıkarılır; tohum görünürdür.
**PT3.** Elle ortam kurmak 6 saat insan emeğidir ve platform ekibinin elle kurma kapasitesi günde bir
ortamdır.
**PT4.** İstek üzerine yolda üretim 0,5 saat sürer; eş zamanlı açık ortam havuzu 16'dır.
**PT5.** Kuyruk yolunda teslim edilen ortam kapatılmaz — yeniden beklemek pahalıdır. İstek üzerine yolda
ekip kullanımı bitince kapatır; kapatmayı unuttuğu durumlar **önceden yazılıdır**, rastgelelik yoktur.
**PT6.** Platform iki ortam biçimi sunar: küçük ve orta. Alan donanımlı biçim sunulmaz. **Unutulan
ortam**, son kullanım gününden sonra en az yedi gün açık kalan ortamdır.

#### Talep Kuyruğu ve İstek Üzerine

```js
// veri.mjs — bes ekibin doksan gunluk ortam talebi; model, uretec kendi yazildi, tohum gorunur.
export const EKIP = ["sayac-okuma", "dogrulama", "faturalama", "saha", "raporlama"];
export const GUN = 90, TOHUM = 20260801;
export const uretec = (t) => () => ((t = (t * 1103515245 + 12345) % 2147483648) / 2147483648);

const ORAN = { "sayac-okuma": 0.24, dogrulama: 0.16, faturalama: 0.10, saha: 0.30, raporlama: 0.06 };
const BICIM = { "sayac-okuma": "kucuk", dogrulama: "orta", faturalama: "orta",
  saha: "alan-donanimli", raporlama: "orta" };      // platform yalniz kucuk ve orta sunuyor
export const SUNULAN = ["kucuk", "orta"];

export const talepler = () => {                     // her ekip icin gun gun bagimsiz cekilis
  const r = uretec(TOHUM), t = [];
  for (let g = 0; g < GUN; g++)
    for (const e of EKIP) {
      const [a, b, c] = [r(), r(), r()];
      if (a < ORAN[e]) t.push({ ekip: e, gun: g, bicim: BICIM[e],
        kullanim: 1 + Math.floor(b * 9),            // fiilen kac gun kullanilacak
        durumlu: c < 0.45 });                       // ortamda uretilmis veri kaliyor mu
    }
  return t;
};
```

Aynı talep akışı iki yoldan geçirilir. Kuyruk yolunda her talebi insan karşılar. Platform yolunda
sunulan biçimdeki talepler istek üzerine üretilir; sunulmayan biçimdekiler altın yolun dışında kalır ve
o ekip ortamını kendi kurar.

```js
// yol.mjs — ayni talep akisi iki yoldan gecirilir: talep kuyrugu ve istek uzerine ortam.
import { talepler, GUN, EKIP, SUNULAN } from "./veri.mjs";

const KAPASITE = 1, HAVUZ = 16, URETIM_SAAT = 0.5, ELLE_SAAT = 6, UNUT = 7;
const T = talepler();
const ort = (d) => (d.length ? d.reduce((a, b) => a + b, 0) / d.length : 0).toFixed(1);

const kuyruk = (liste) => {                         // insan kurar: gunde en cok bir ortam
  const bekleyen = [], ortam = [];
  for (let g = 0; g < GUN; g++) {
    bekleyen.push(...liste.filter((t) => t.gun === g));
    for (let k = 0; k < KAPASITE && bekleyen.length; k++) {
      const t = bekleyen.shift();
      ortam.push({ ...t, acilis: g, bekleme: (g - t.gun) * 24 + ELLE_SAAT, kapanis: GUN });
    }                                               // kuyruk yolunda ortam biraktirilmaz
  }
  return { ortam, teslimsiz: bekleyen.length, dolu: 0 };
};

const istekUzerine = (liste) => {                   // bir istekle uretilir, havuz sinirli
  const bekleyen = [], ortam = [], acik = [];
  let dolu = 0;
  for (let g = 0; g < GUN; g++) {
    for (let i = acik.length - 1; i >= 0; i--) if (acik[i].kapanis <= g) acik.splice(i, 1);
    bekleyen.push(...liste.filter((t) => t.gun === g));
    while (bekleyen.length && acik.length < HAVUZ) {
      const t = bekleyen.shift();
      const unutuldu = (t.gun * 7 + t.kullanim) % 4 === 0;  // onceden yazili, rastgele degil
      const o = { ...t, acilis: g, bekleme: (g - t.gun) * 24 + URETIM_SAAT, unutuldu,
        kapanis: unutuldu ? GUN : Math.min(GUN, g + t.kullanim) };
      ortam.push(o); acik.push(o);
    }
    if (acik.length >= HAVUZ) dolu++;
  }
  return { ortam, teslimsiz: bekleyen.length, dolu };
};

const kendiKuran = (liste) => ({ dolu: 0, teslimsiz: 0,   // dis yolda ekip kendi kurar, kapatmaz
  ortam: liste.map((t) => ({ ...t, acilis: t.gun, bekleme: ELLE_SAAT, kapanis: GUN })) });

const olc = (ad, { ortam, teslimsiz, dolu }) => {
  const gun = ortam.reduce((a, o) => a + (o.kapanis - o.acilis), 0);
  const kullanilan = ortam.reduce((a, o) => a + Math.min(o.kullanim, o.kapanis - o.acilis), 0);
  const unutulan = ortam.filter((o) => o.kapanis - o.acilis - o.kullanim >= UNUT).length;
  console.log(`${ad.padEnd(20)} teslim ${String(ortam.length).padStart(2)}` +
    `  teslimsiz ${teslimsiz}  bekleme ${ort(ortam.map((o) => o.bekleme)).padStart(5)} saat` +
    `  ortam-gun ${String(gun).padStart(4)}  bosta ${String(gun - kullanilan).padStart(4)}` +
    ` (%${String(Math.round((gun - kullanilan) / gun * 100)).padStart(2)})  unutulan ${unutulan}`);
  return { gun, kullanilan, unutulan, dolu, n: ortam.length };
};

const ic = T.filter((t) => SUNULAN.includes(t.bicim));
const dis = T.filter((t) => !SUNULAN.includes(t.bicim));
console.log(`talep ${T.length}  pencere ${GUN} gun  ekip ${EKIP.length}  elle kurulum ` +
  `${ELLE_SAAT} saat, ${KAPASITE}/gun  havuz ${HAVUZ} es zamanli  uretim ${URETIM_SAAT} saat`);
const A = olc("talep kuyrugu (hep)", kuyruk(T));
const B = olc("istek uzerine (ic)", istekUzerine(ic));
const C = olc("altin yol disinda", kendiKuran(dis));
console.log(`havuzun dolu oldugu gun ${B.dolu}/${GUN}; havuz doluyken gelen talep bekliyor,` +
  ` ${B.dolu ? "gizlenen kapasite geri siziyor" : "sizma yok"}`);
console.log(`altin yol disinda ${dis.length}/${T.length} talep, tek gerekce alan-donanimli bicim` +
  ` (${[...new Set(dis.map((t) => t.ekip))].join(", ")}); platform hizmetinden hicbiri yararlanmiyor`);
console.log(`insan emegi: kuyruk ${A.n * ELLE_SAAT} saat   platform ${C.n * ELLE_SAAT} saat` +
  ` (yalnizca dis yol)   kurtulan ${(A.n - C.n) * ELLE_SAAT} saat`);
```

```
talep 90  pencere 90 gun  ekip 5  elle kurulum 6 saat, 1/gun  havuz 16 es zamanli  uretim 0.5 saat
talep kuyrugu (hep)  teslim 83  teslimsiz 7  bekleme  83.2 saat  ortam-gun 3528  bosta 3133 (%89)  unutulan 73
istek uzerine (ic)   teslim 60  teslimsiz 3  bekleme  10.1 saat  ortam-gun  877  bosta  580 (%66)  unutulan 12
altin yol disinda    teslim 27  teslimsiz 0  bekleme   6.0 saat  ortam-gun 1212  bosta 1090 (%90)  unutulan 22
havuzun dolu oldugu gun 16/90; havuz doluyken gelen talep bekliyor, gizlenen kapasite geri siziyor
altin yol disinda 27/90 talep, tek gerekce alan-donanimli bicim (saha); platform hizmetinden hicbiri yararlanmiyor
insan emegi: kuyruk 498 saat   platform 162 saat (yalnizca dis yol)   kurtulan 336 saat
```

Bekleme farkı en görünür sayıdır: kuyruk yolunda ortalama 83,2 saat, istek üzerine yolda 10,1 saat.
Kuyruk yolunda 90 talebin 7'si pencere kapandığında hâlâ sıradadır. Ama beklemeyi düşüren şey tek başına
otomasyon değildir; kuyruk yolunun kapasitesi günde bir ortamdır ve talep günde bir taleptir, yani kuyruk
zaten doygunluk sınırında çalışır. Devredilen karar şudur: **ortamın ne zaman var olacağına ve ne zaman
yok olacağına insan değil, ekip kendi karar verir.**

İkinci sayı ilkinden daha ilginçtir. Kuyruk yolunda 3.528 ortam-günün 3.133'ü boştadır, yani ortamlar
ömürlerinin yüzde 89'unda kullanılmamaktadır. Nedeni beklemededir: ortam almak günler sürdüğü için kimse
aldığı ortamı geri vermez ve 83 ortamın 73'ü unutulan ortama dönüşür. Bekleme süresi ile boşta duran
kaynak birbirinden bağımsız iki sorun değildir; **biri diğerini üretir**.

#### Ömür Sınırı: Kısa Ömrün Karşılığı

```js
// omur.mjs — omur siniri taranir: maliyet, yeniden kurma, veri kaybi; sonra esik hesaplanir.
import { talepler, GUN, EKIP, SUNULAN } from "./veri.mjs";

const HAVUZ = 16, ELLE_SAAT = 6, UNUT = 7, KURULUM = 320, ISLETME_AY = 8, AY = 3;
const T = talepler(), ic = T.filter((t) => SUNULAN.includes(t.bicim));

const tara = (omur) => {                   // omur dolunca ortam silinir, is bitmediyse geri istenir
  const bekleyen = [], acik = [];
  let gunToplam = 0, uretilen = 0, yeniden = 0, kayip = 0, unutulan = 0;
  for (let g = 0; g < GUN; g++) {
    for (let i = acik.length - 1; i >= 0; i--) {
      const o = acik[i], yas = g - o.acilis, bitti = o.kalan === 0 && !o.unutuldu;
      if (!bitti && yas < omur) continue;
      acik.splice(i, 1);
      gunToplam += yas;
      if (yas - (o.kullanim - o.kalan) >= UNUT) unutulan++;
      if (o.kalan > 0) { yeniden++; kayip += o.durumlu ? 1 : 0; bekleyen.push(o); }
    }
    bekleyen.push(...ic.filter((t) => t.gun === g).map((t) => ({ ...t, kalan: t.kullanim,
      unutuldu: (t.gun * 7 + t.kullanim) % 4 === 0 })));
    while (bekleyen.length && acik.length < HAVUZ) {
      acik.push({ ...bekleyen.shift(), acilis: g }); uretilen++;
    }
    for (const o of acik) if (o.kalan > 0) o.kalan--;
  }
  for (const o of acik) {                           // pencere sonunda hala acik olanlar
    gunToplam += GUN - o.acilis;
    if (GUN - o.acilis - (o.kullanim - o.kalan) >= UNUT) unutulan++;
  }
  return { gunToplam, uretilen, yeniden, kayip, unutulan, teslimsiz: bekleyen.length };
};

console.log("omur   ortam-gun  uretilen  yeniden kurma  veri kaybi  unutulan  teslimsiz");
for (const s of [1, 2, 3, 5, 7, 14, 90]) {
  const r = tara(s);
  console.log(`${(s === 90 ? "yok" : s + " gun").padEnd(7)}${String(r.gunToplam).padStart(6)}` +
    `${String(r.uretilen).padStart(10)}${String(r.yeniden).padStart(15)}` +
    `${String(r.kayip).padStart(12)}${String(r.unutulan).padStart(10)}${String(r.teslimsiz).padStart(11)}`);
}

const fayda = Object.fromEntries(EKIP.map((e) =>               // ekip basina kurtulan insan-saat
  [e, ic.filter((t) => t.ekip === e).length * ELLE_SAAT]));
const bedel = KURULUM + ISLETME_AY * AY;
let k = 0, esik = 0;
const yigin = EKIP.map((e) => { k += fayda[e]; if (k >= bedel && !esik) esik = EKIP.indexOf(e) + 1;
  return `${e} ${fayda[e]} (${k})`; });
console.log(`\nplatform bedeli ${bedel} insan-saat (kurulum ${KURULUM} + ${AY} ay isletme)` +
  `   bes ekibin toplam kazanci ${k} insan-saat`);
console.log(`ekip basina kurtulan (yigisik): ${yigin.join("  ")}`);
console.log(`esik ${esik ? esik + ". ekipte asiliyor" : "bu donemde asilmiyor"}` +
  `; katki veren ekip ${EKIP.filter((e) => fayda[e] > 0).length}/${EKIP.length}`);
```

```
omur   ortam-gun  uretilen  yeniden kurma  veri kaybi  unutulan  teslimsiz
1 gun     314       314            251         113         0          0
2 gun     322       175            112          50         0          0
3 gun     331       127             64          27         0          0
5 gun     343        90             27          12         0          0
7 gun     355        76             13           8         0          0
14 gun    425        63              0           0        10          0
yok       877        60              0           0        12          3

platform bedeli 344 insan-saat (kurulum 320 + 3 ay isletme)   bes ekibin toplam kazanci 378 insan-saat
ekip basina kurtulan (yigisik): sayac-okuma 174 (174)  dogrulama 78 (252)  faturalama 90 (342)  saha 0 (342)  raporlama 36 (378)
esik 5. ekipte asiliyor; katki veren ekip 4/5
```

Tarama iki eğrinin farklı hızda gittiğini gösterir. Ömür sınırı yokken 877 ortam-gün harcanır; sınır
on dört güne çekildiğinde bu sayı 425'e, yani yarısının altına iner ve karşılığında **hiçbir yeniden
kurma doğmaz**. Buradan sonrası aynı ucuz değildir: on dört günden yedi güne inmek maliyeti yalnızca 425'ten
355'e çeker, ama 13 yeniden kurma ve 8 veri kaybı olayı üretir. Bir güne inmek maliyeti 314'e indirir —
yedi güne göre yüzde on iki kazanç — ve karşılığında 251 yeniden kurma ile 113 veri kaybı doğurur.
Maliyet eğrisi düzleşirken yeniden kurma eğrisi dikleşir.

Sınırın görülmeyen bir yararı da vardır. Ömür sınırı yokken 3 talep hiç karşılanamaz, çünkü unutulan
ortamlar havuzu doldurur; sınır konduğu anda teslimsiz talep sıfırlanır. **Kullanılmayan ortamın maliyeti
yalnız hesapta değil, başka ekiplerin beklemesinde ödenir.**

#### Gizlenen Katmanın Bedeli

| Ölçü | Talep kuyruğu | İstek üzerine | Altın yol dışında |
|---|---|---|---|
| ortalama bekleme | 83,2 saat | 10,1 saat | 6,0 saat |
| teslim / teslimsiz | 83 / 7 | 60 / 3 | 27 / 0 |
| ortam-gün | 3.528 | 877 | 1.212 |
| boşta ortam-günü | 3.133 (%89) | 580 (%66) | 1.090 (%90) |
| unutulan ortam | 73 | 12 | 22 |
| ortam başına insan emeği | 6 saat | 0 saat | 6 saat |

Gizlenen katman ortamın kurulum adımlarıdır ve kazanç 336 insan-saattir: kuyruk yolunda 498 saat
harcanan iş, platform yolunda 162 saate iner. Eşik de aynı hesaptan çıkar. Platformun bir çeyrekteki
bedeli 344 insan-saat ve beş ekibin toplam kazancı 378 insan-saattir; **eşik ancak beşinci ekipte
aşılır** ve o eşiği aşan ekip yıllık talebi en düşük olan raporlama ekibidir. Üç ekiple aynı platform
kendini ödemez. Sayı tek yöne bakmaz: aynı model, az sayıda ekibin çalıştığı bir ağda platformun
kurulmaması gerektiğini de söyler.

Soyutlama iki noktada sızar. Birincisi havuzdur: 90 günün 16'sında havuz doludur ve o günlerde bekleme
kuyruk yolundaki gibi geri gelir — ekip istediği anda ortam alacağını sanır, gerçekte alt katmanın
kapasitesine çarpar. İkincisi ömür sınırıdır: ortamın kalıcı olmadığı bilgisi ekibe ancak veri kaybı
olayında görünür ve o bilgi belge okuyarak değil, çalışma kaybederek öğrenilir.

Dışına çıkanlar tek bir gerekçeyle çıkar. Alan donanımlı ortam isteyen 27 talebin tamamı saha ekibindendir
ve bu ekip platform hizmetinin **hiçbirinden** yararlanmaz: ortamını kendi kurar, ömür sınırı işlemez,
ortam-gününün yüzde 90'ı boşta durur ve 22 ortamı unutulur. Kısmi yararlanma yoktur; bir talebin biçimi
sunulan iki biçime oturmuyorsa o talep bütün yaşam döngüsünü platformun dışında geçirir.

#### Özet

- Aynı 90 talep kuyruk yolunda ortalama 83,2 saat, istek üzerine yolda 10,1 saat bekledi; kuyruk yolunda
  7 talep pencere kapanana kadar hiç karşılanmadı.
- Bekleme boşta duran kaynağı üretti: kuyruk yolunda 3.528 ortam-gününün %89'u kullanılmadı ve 83 ortamın
  73'ü unutulan ortama dönüştü.
- Ömür sınırı 14 güne çekilince maliyet 877 ortam-gününden 425'e indi ve hiç yeniden kurma doğmadı;
  1 güne çekilince maliyet yalnız 314'e indi ama 251 yeniden kurma ve 113 veri kaybı olayı çıktı.
- Ömür sınırı havuzu da boşalttı: sınırsız yolda karşılanamayan 3 talep, sınır konduğunda sıfırlandı.
- Platformun çeyreklik bedeli 344 insan-saat, beş ekibin kazancı 378 insan-saat; eşik ancak beşinci
  ekipte aşıldı ve saha ekibi bu kazanca hiç katkı vermedi.
- Soyutlama iki yerden sızdı: 90 günün 16'sında havuz doldu ve bekleme geri geldi; ömür sınırının varlığı
  ekibe ancak veri kaybıyla göründü.

#### Sonraki Adım

Ortam artık istendiği anda var oluyor, ama içine konacak şey hâlâ elle yazılıyor. Ölçüm ağına altıncı bir
servis eklenmesi gerektiğinde ekip boş bir dizinle başlıyor ve kütük biçiminden sağlık ucuna, derleme
adımından ölçüt yayınına kadar her kararı yeniden veriyor — üstelik beş ekip bu kararları birbirinden
habersiz veriyor. Bir sonraki ders yeni servis başlatma akışını ele alır: gerçek dosyalar üretilir,
elle yazılanla üretilen karşılaştırılır ve üretimden sonra şablon güncellendiğinde kaç servisin geride
kaldığı sayılır.

### Şablon ve İskelet Üretimi

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/sablon-ve-iskelet-uretimi

Yeni bir servis başlatmak elle kaç dosya, kaç satır ve kaç karar demek; iskelet üretimiyle bunların kaçı kalıyor. Beş servis gerçek dosyalarla üretilir, elle yazılmış bir servisle satır satır karşılaştırılır, sonra şablon güncellenince kaç servisin geride kaldığı ve geride kalanı yakalamanın neye mal olduğu ölçülür.

Önceki ders ortamı istendiği anda var eden yolu ölçtü: bekleme on saate indi, boşta duran ortam-günü
yarıya yakın düştü. Ortam artık hazır, ama içine konacak şey hâlâ boş bir dizinden başlıyor. Ölçüm ağına
altıncı bir servis eklemek gerektiğinde ekip kütük biçiminden sağlık ucuna, hat adımlarından yayınlanacak
ölçütlere kadar her kararı yeniden veriyor — ve beş ekip bu kararları birbirinden habersiz veriyor.

**İskelet üretimi**, yeni bir servisin başlangıç dosyalarını bir şablon deposundan üreten akıştır.
Şablonun kendi bedeli — değişken sayısı, koşullu dal, kopyalar arasındaki sürüklenme — M22/K03'ün
paketleme ve şablonlama dersinde ölçüldü ve burada tekrarlanmaz. Bu dersin ölçtüğü iki şey vardır:
**başlatma anında** neyin yazılmadığı ve **üretimden sonra** şablonun ardında ne bıraktığı.

Ölçüm **bölgesel ölçüm ağı** üzerindedir: su sayacı okumalarını toplayan, doğrulayan ve saha iş emri
açan **kurgu** yazılım. Bu dersteki dosyalar gerçekten diske yazılır ve diskten okunarak sayılır; dosya
biçimleri ürün adı taşımaz, ders içinde tanımlanan **kendi küçük biçimimizdir**.

**PT7.** Ölçüm ağına eklenen bir servis altı dosyayla başlar: servis tanımı, hat tanımı, ölçüt tanımı,
kütük tanımı, duman sınaması ve belge.
**PT8.** Şablon deposu sürüm 1'de üç soru sorar: ad, sahip, kapı.
**PT9.** Sayaç okuma ekibi kendi servisini iskeletten önce elle yazmıştır; o dosyalar modelde birebir
durur ve karşılaştırma onların üzerinden yapılır.
**PT10.** Üretim gerçekten koşar; sayılan dosya ve satırlar diskten okunur.
**PT11.** Üretimden sonraki yerel düzenlemeler **önceden yazılıdır**, rastgelelik yoktur.
**PT12.** Şablon sürüm 2 üç değişiklik getirir ve bir yeni soru ekler. Üretilmiş dosyalar şablona bağlı
değildir; şablon değişince kendiliklerinden değişmezler.

#### Şablon Deposu ve Üç Soru

```js
// sablon.mjs — sablon deposu (surum 1), bes servisin cevaplari, elle yazilmis bir servis. Model.
export const SURUM = 1;
export const SABLON = {
  "servis.tanim": `servis {{ad}}
  sahip {{sahip}}
  kapi {{kapi}}
  saglik-ucu /saglik
  kutuk-bicimi satir-json
  kutuk-duzeyi ozet`,
  "hat.tanim": `hat {{ad}}
  adim derle
  adim birim-sinama
  adim paket
  adim dagit-sinama
  adim duman-sinama
  adim dagit-uretim`,
  "olcut.tanim": `olcut {{ad}}
  sayac islenen_kayit
  sayac hatali_kayit
  olcek istek_suresi_ms`,
  "kutuk.tanim": `kutuk {{ad}}
  alan zaman
  alan duzey
  alan istek-kimligi`,
  "duman.tanim": `duman {{ad}}
  cagri /saglik bekle 200
  cagri /olcut bekle 200`,
  "BELGE.md": `# {{ad}}
sahip {{sahip}}, kapi {{kapi}}`,
};

export const CEVAP = [                              // surum 1 uc soru sorar
  { ad: "okuma-toplayici", sahip: "sayac-okuma", kapi: 8080 },
  { ad: "dogrulama-akisi", sahip: "dogrulama", kapi: 8081 },
  { ad: "fatura-hesaplayici", sahip: "faturalama", kapi: 8082 },
  { ad: "saha-emir", sahip: "saha", kapi: 8083 },
  { ad: "rapor-derleyici", sahip: "raporlama", kapi: 8084 }];

export const uret = (s, c) => s.replace(/\{\{([\w-]+)\}\}/g, (_, a) => String(c[a] ?? `<eksik:${a}>`));
export const satir = (m) => m.split("\n").filter((s) => s.trim()).length;

export const ELLE = {                               // sayac-okuma ekibi iskeletten once elle yazdi
  "servis.tanim": `servis okuma-toplayici
  sahip sayac-okuma
  kapi 8080
  saglik-ucu /durum
  kutuk-bicimi duz-metin`,
  "hat.tanim": `hat okuma-toplayici
  adim derle
  adim birim-sinama
  adim paket
  adim elle-onay
  adim dagit-uretim`,
  "olcut.tanim": `olcut okuma-toplayici
  sayac kayit_sayisi
  olcek istek_suresi_ms`,
  "kutuk.tanim": `kutuk okuma-toplayici
  alan zaman
  alan duzey`,
  "BELGE.md": `# okuma-toplayici`,
};
```

Şablonun içindeki değerlerin çoğu soru olarak sorulmaz. Sağlık ucunun yolu, kütük biçimi, hattaki altı
adımın sırası ve yayınlanacak üç ölçütün adı şablonda sabittir; ekibe sorulan yalnız üç şeydir. Bu ayrım
dersin ölçtüğü şeyin ta kendisidir: **sorulmayan her alan, bir ekibin vermediği bir karardır** — ve aynı
zamanda o ekibin artık göremediği bir karardır.

#### Üretilen ile Elle Yazılan

```js
// uret.mjs — bes servis gercek dosyalarla uretilir, elle yazilanla karsilastirilir.
import { mkdirSync, writeFileSync, readFileSync, readdirSync } from "node:fs";
import { SABLON, CEVAP, ELLE, SURUM, uret, satir } from "./sablon.mjs";

const DOSYA = Object.keys(SABLON), baslangic = process.hrtime.bigint();
for (const c of CEVAP) {
  mkdirSync(`servisler/${c.ad}`, { recursive: true });
  for (const d of DOSYA)
    writeFileSync(`servisler/${c.ad}/${d}`, `# uretici ${SURUM}\n${uret(SABLON[d], c)}\n`);
}
const gecen = Number(process.hrtime.bigint() - baslangic) / 1e6;

const diskte = readdirSync("servisler").flatMap((s) =>            // gercekten yazildi mi
  readdirSync(`servisler/${s}`).map((d) => `servisler/${s}/${d}`));
const diskSatir = diskte.reduce((a, y) => a + satir(readFileSync(y, "utf8")), 0);
const alan = Object.values(SABLON).join("\n").split("\n").filter((s) => s.startsWith("  ")).length;
const degisken = new Set(Object.values(SABLON).join("\n").match(/\{\{([\w-]+)\}\}/g)).size;
const bandUst = DOSYA.length * CEVAP.length * 20;                 // beklenen ust sinir girdiden turer

console.log(`sablon ${DOSYA.length} dosya, ${satir(Object.values(SABLON).join("\n"))} satir,` +
  ` ${alan} alan, ${degisken} degisken`);
console.log(`elle baslatma : servis basina ${DOSYA.length} dosya, ` +
  `${satir(Object.values(SABLON).join("\n"))} satir, ${alan} karar` +
  `   bes servis icin ${alan * CEVAP.length} karar`);
console.log(`iskeletle     : servis basina 0 dosya, 0 satir, ${degisken} cevap` +
  `   bes servis icin ${degisken * CEVAP.length} cevap`);
console.log(`diske yazilan ${diskte.length} dosya, ${diskSatir} satir` +
  `   uretim suresi ${0}-${bandUst} ms bandinda: ${gecen <= bandUst ? "evet" : "hayir"}`);

const anahtar = (s) => s.trim().split(" ")[0];                    // uretilen ile elle yazilan
const tek = (l, k) => l.filter((x) => anahtar(x) === k).length === 1;
let ortak = 0, farkli = 0, eksik = 0, fazla = 0;
console.log(`\nelle yazilan okuma-toplayici ${Object.keys(ELLE).length} dosya ` +
  `${satir(Object.values(ELLE).join("\n"))} satir  |  uretilen ${DOSYA.length} dosya ` +
  `${satir(Object.values(SABLON).join("\n"))} satir`);
for (const d of DOSYA) {
  const g = uret(SABLON[d], CEVAP[0]).split("\n").filter((s) => s.trim());
  const e = (ELLE[d] ?? "").split("\n").filter((s) => s.trim());
  const sap = [];
  let o = 0, f = 0, k = 0;
  for (const s of g) {
    if (e.some((x) => x.trim() === s.trim())) o++;
    else if (tek(g, anahtar(s)) && tek(e, anahtar(s))) {
      f++; sap.push(`${s.trim()} -> ${e.find((x) => anahtar(x) === anahtar(s)).trim()}`);
    } else k++;
  }
  const z = e.filter((x) => !g.some((s) => s.trim() === x.trim()) &&
    !sap.some((p) => anahtar(p) === anahtar(x))).length;
  [ortak, farkli, eksik, fazla] = [ortak + o, farkli + f, eksik + k, fazla + z];
  console.log(`  ${d.padEnd(13)} ortak ${o}  farkli ${f}  eksik ${k}  fazladan ${z}` +
    `${ELLE[d] === undefined ? "  (dosya hic yazilmamis)" : ""}` +
    `${sap.length ? "  [" + sap.join("; ") + "]" : ""}`);
}
console.log(`toplam: ortak ${ortak}  farkli deger ${farkli}  eksik ${eksik}  fazladan ${fazla}`);
```

```
sablon 6 dosya, 26 satir, 19 alan, 3 degisken
elle baslatma : servis basina 6 dosya, 26 satir, 19 karar   bes servis icin 95 karar
iskeletle     : servis basina 0 dosya, 0 satir, 3 cevap   bes servis icin 15 cevap
diske yazilan 30 dosya, 160 satir   uretim suresi 0-600 ms bandinda: evet

elle yazilan okuma-toplayici 5 dosya 18 satir  |  uretilen 6 dosya 26 satir
  servis.tanim  ortak 3  farkli 2  eksik 1  fazladan 0  [saglik-ucu /saglik -> saglik-ucu /durum; kutuk-bicimi satir-json -> kutuk-bicimi duz-metin]
  hat.tanim     ortak 5  farkli 0  eksik 2  fazladan 1
  olcut.tanim   ortak 2  farkli 0  eksik 2  fazladan 1
  kutuk.tanim   ortak 3  farkli 0  eksik 1  fazladan 0
  duman.tanim   ortak 0  farkli 0  eksik 3  fazladan 0  (dosya hic yazilmamis)
  BELGE.md      ortak 1  farkli 0  eksik 1  fazladan 0
toplam: ortak 14  farkli deger 2  eksik 10  fazladan 2
```

Başlatma bedeli üç sayıdadır ve üçü de aynı yöne gitmez. Dosya ve satır sayısı gözle görülür kazançtır:
servis başına altı dosya ve yirmi altı satır artık yazılmaz, beş servis için yüz otuz satır düşer.
Asıl kalem üçüncüsüdür — **on dokuz karar üç cevaba iner**. Beş servis için doksan beş karar yerine on
beş cevap verilir; geri kalan seksen karar bir kez şablonda verilmiş ve bir daha sorulmamıştır.

Elle yazılan servisle karşılaştırma bu seksen kararın ne demek olduğunu gösterir. Sayaç okuma
ekibinin kendi yazdığı servis on sekiz satırdır ve üretilenin yirmi altı satırıyla yalnız **on
dört satırda** örtüşür. İki alanda değer farklıdır — sağlık ucu `/saglik` yerine `/durum`, kütük
biçimi satır-json yerine düz metin — ve bu iki fark hiçbir hata üretmez, yalnız ortak araçların o
servisi tanımamasına yol açar. On satır eksiktir: hattaki iki adım, ölçüt tanımındaki iki sayaç,
kütükteki istek kimliği alanı, duman sınaması dosyasının tamamı, servis tanımındaki bir satır ve
belge dosyasındaki bir satır. İki satır da fazladandır ve şablonda karşılığı yoktur: hattaki elle
onay adımı ve kendi adıyla yazılmış bir sayaç.

Bu ekibin altın yola geçmesi için on iki satır düzeltmesi ve bir dosya eklemesi gerekir; fazladan iki
satırın ise şablonda yeri yoktur, yani ya onlardan vazgeçecek ya da dışarıda kalacaktır. **Dışına
çıkmanın bedeli servis başına on iki satır düzeltme ve iki alışkanlıktan vazgeçmedir.**

#### Şablon Güncellenince Ne Oluyor

```js
// suruklenme.mjs — uretimden sonra sablon guncellenir; geride kalan servisler diskten sayilir.
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
import { SABLON, CEVAP, uret, satir } from "./sablon.mjs";

const YEREL = {                                     // uretimden sonraki yerel duzenleme, onceden yazili
  "okuma-toplayici": { "hat.tanim": ["  adim sema-denetimi", "  adim yuk-sinamasi"],
    "olcut.tanim": ["  sayac atlanan_kayit"] },
  "dogrulama-akisi": { "kutuk.tanim": ["  alan kaynak-sayac"] },
  "fatura-hesaplayici": { "hat.tanim": ["  adim mutabakat"], "olcut.tanim": ["  olcek fatura_tutari"],
    "duman.tanim": ["  cagri /mutabakat bekle 200"] },
  "saha-emir": {},
  "rapor-derleyici": { "duman.tanim": ["  cagri /rapor bekle 200"], "BELGE.md": ["kosum notu gecelik"] } };

let yerel = 0;
for (const [s, d] of Object.entries(YEREL))
  for (const [dosya, satirlar] of Object.entries(d)) {
    writeFileSync(`servisler/${s}/${dosya}`,
      readFileSync(`servisler/${s}/${dosya}`, "utf8") + satirlar.join("\n") + "\n");
    yerel += satirlar.length;
  }
const y = `servisler/dogrulama-akisi/servis.tanim`;  // dogrulama ekibi duyuruyu gorup elle yamaladi
writeFileSync(y, readFileSync(y, "utf8").replace("saglik-ucu /saglik",
  "saglik-ucu /durum/saglik\n  veri-sinifi olcum"));
writeFileSync("servisler/dogrulama-akisi/hat.tanim",
  readFileSync("servisler/dogrulama-akisi/hat.tanim", "utf8") + "  adim imzalama\n");

const SABLON2 = { ...SABLON, "servis.tanim": SABLON["servis.tanim"]
  .replace("saglik-ucu /saglik", "saglik-ucu /durum/saglik\n  veri-sinifi {{veri-sinifi}}"),
  "hat.tanim": SABLON["hat.tanim"] + "\n  adim imzalama" };
const KURAL = [["servis.tanim", "saglik-ucu /durum/saglik"], ["servis.tanim", "veri-sinifi "],
  ["hat.tanim", "  adim imzalama"]];

const marker = CEVAP.filter((c) =>                  // birinci tarama: uretici surum satiri
  readFileSync(`servisler/${c.ad}/servis.tanim`, "utf8").startsWith("# uretici 1"));
let eksikSatir = 0, okunan = 0;
const icerik = CEVAP.filter((c) => {
  const eksik = KURAL.filter(([d, k]) => !readFileSync(`servisler/${c.ad}/${d}`, "utf8").includes(k));
  okunan += new Set(KURAL.map(([d]) => d)).size;
  eksikSatir += eksik.length;
  return eksik.length > 0;
});

mkdirSync("deneme", { recursive: true });           // cevapsiz yeniden uretim denemesi
let bosluk = 0;
for (const c of CEVAP) {
  const m = uret(SABLON2["servis.tanim"], c);
  writeFileSync(`deneme/${c.ad}.tanim`, m);
  bosluk += (m.match(/<eksik:/g) ?? []).length;
}
const yeniCevap = CEVAP.filter((c) => c["veri-sinifi"] === undefined).length;

console.log(`yerel duzenleme ${yerel} satir, ${Object.values(YEREL).filter((d) =>
  Object.keys(d).length).length}/${CEVAP.length} serviste`);
console.log(`sablon surum 2: ${KURAL.length} degisiklik, ${satir(SABLON2["servis.tanim"] +
  "\n" + SABLON2["hat.tanim"]) - satir(SABLON["servis.tanim"] + "\n" + SABLON["hat.tanim"])}` +
  ` yeni satir, 1 yeni soru; uretilmis servislerin hicbiri kendiliginden degismiyor`);
console.log(`marker taramasi : geride ${marker.length}/${CEVAP.length} servis,` +
  ` okunan dosya ${CEVAP.length}, yanlis pozitif ${marker.length - icerik.length}`);
console.log(`icerik taramasi : geride ${icerik.length}/${CEVAP.length} servis,` +
  ` eksik satir ${eksikSatir}, okunan dosya ${okunan}` +
  `   (${icerik.map((c) => c.ad).join(", ")})`);
console.log(`yeniden uretim  : ${CEVAP.length * Object.keys(SABLON).length} dosya yeniden yazilir,` +
  ` kaybolan yerel satir ${yerel}, once toplanacak yeni cevap ${yeniCevap}` +
  `; cevapsiz denemede ${bosluk} bosluk`);
console.log(`elle yama       : ${eksikSatir} dokunus, kaybolan yerel satir 0,` +
  ` sonraki surumde ayni is yeniden gerekir`);
```

```
yerel duzenleme 9 satir, 4/5 serviste
sablon surum 2: 3 degisiklik, 2 yeni satir, 1 yeni soru; uretilmis servislerin hicbiri kendiliginden degismiyor
marker taramasi : geride 5/5 servis, okunan dosya 5, yanlis pozitif 1
icerik taramasi : geride 4/5 servis, eksik satir 12, okunan dosya 10   (okuma-toplayici, fatura-hesaplayici, saha-emir, rapor-derleyici)
yeniden uretim  : 30 dosya yeniden yazilir, kaybolan yerel satir 9, once toplanacak yeni cevap 5; cevapsiz denemede 5 bosluk
elle yama       : 12 dokunus, kaybolan yerel satir 0, sonraki surumde ayni is yeniden gerekir
```

Şablonun sürüm 2'si sağlık ucunu değiştirir, veri sınıfı alanını zorunlu kılar ve hatta bir imzalama adımı
ekler. Diskteki beş servisin hiçbiri bundan haberdar olmaz, çünkü **üretilen dosya üreticiye bağlı
değildir**. Şablon bir kez okundu, çıktı yazıldı ve bağ orada koptu. Bu, önceki dersteki ortam
soyutlamasının tam tersi bir sızmadır: orada gizlenen katman geri sızıyordu; burada gizleme hiç sürmüyor.

Geride kalanı bulmanın iki yolu vardır ve ikisi farklı sayı verir. Üretici sürümünü okumak beş dosya
okumakla biter ve beş servisin beşini de geride gösterir; oysa doğrulama ekibi duyuruyu görüp üç
değişikliği elle yapmıştır, yani bu tarama **bir yanlış pozitif** üretir. İçeriği denetlemek on dosya
okumayı gerektirir, geride kalanı dört servis olarak verir ve toplam on iki eksik satırı adlarıyla
gösterir. Doğru sonuç iki kat okuma maliyetindedir.

Yakalamanın da iki yolu vardır. Yeniden üretim otuz dosyayı yeniden yazar ve tek hamlede bitirir, ama iki
bedeli vardır: dokuz yerel satır kaybolur — hat adımları, ölçütler, duman çağrıları — ve yeni sorunun
cevabı hiçbir yerde kayıtlı olmadığı için beş servis için beş yeni cevap toplanması gerekir. Cevapsız
koşulan deneme bunu doğrudan gösterir: beş dosyada `<eksik:veri-sinifi>` boşluğu kalır. Elle yama ise on
iki dokunuşla biter ve hiçbir yerel satır kaybetmez, ama şablonla bağ yine kurulmadığı için sürüm 3
geldiğinde aynı iş baştan gerekir.

Kazanç ile bedelin tek cümlelik bilançosu şudur: iskelet **başlatma anındaki** doksan beş kararı on beş
cevaba indirdi, **başlatmadan sonraki** hiçbir kararı devralmadı. Yerel düzenleme yapan dört servis
şablonun dışına yerel satır sayısı kadar çıkmış oldu; hiç düzenleme yapmayan tek servis olan saha-emir
ise yeniden üretimden hiçbir şey kaybetmez.

#### Özet

- Yeni servis elle başlatmak servis başına 6 dosya, 26 satır ve 19 karar demektir; beş servis için 95
  karar çıkar, iskeletle bunun yerine 15 cevap verilir.
- Beş servis gerçekten üretildi: diske 30 dosya ve 160 satır yazıldı, üretim süresi girdiden türetilen
  bant içinde kaldı.
- Elle yazılan servis üretilenle 26 satırın yalnız 14'ünde örtüştü: 2 alanda değer farklı, 10 satır
  eksik, 2 satır fazladan; altın yola geçmenin bedeli 12 satır düzeltme ve 2 alışkanlıktan vazgeçme.
- Şablon sürüm 2'ye çıkınca üretilmiş servislerin hiçbiri kendiliğinden değişmedi; üretici sürümüne
  bakan tarama 5/5 geride dedi ve 1 yanlış pozitif verdi, içerik taraması 4/5 geride ve 12 eksik satır
  buldu, karşılığında iki kat dosya okudu.
- Yakalamanın iki yolu da bedelliydi: yeniden üretim 9 yerel satırı sildi ve 5 yeni cevap istedi, elle
  yama 12 dokunuşla bitti ama bağ kurmadığı için sonraki sürümde aynı iş yeniden gerekti.

#### Sonraki Adım

Beş servis üretildi, dosyaları diskte duruyor ve her birinin tanımında bir sahip satırı var. O satır
yazıldığı gün doğruydu; bugün doğru olup olmadığını kimse bilmiyor. Gece yarısı fatura hesaplayıcı
durduğunda arayanın önce şunu bulması gerekiyor: bu servisin sahibi kim, kime bağlı ve kim ona bağlı.
Bir sonraki ders katalog kayıtlarından sahiplik ve bağımlılık grafiği kurar; sahipsiz servis, var olmayan
bir servise bağlanan öksüz bağımlılık ve doğru kişiye ulaşma süresi katalogla ve katalogsuz sayılır.
Kaydın kendi bedeli de ölçülür: kaç kayıt elle güncelleniyor ve kaç kayıt gerçekle uyuşmuyor.

### Geliştirici Portalı ve Servis Kataloğu

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/gelistirici-portali-ve-servis-katalogu

On iki katalog kaydından sahiplik ve bağımlılık grafiği kurulur; sahipsiz servis, öksüz bağımlılık ve kayıtlı olmayan servis sayılır. Beş olayda doğru nöbet listesine ulaşma süresi katalogla ve katalogsuz ölçülür, sonra kaydın kendi bedeli çıkarılır: kaç alan elle yazılıyor ve kaç kayıt gerçekle uyuşmuyor.

Önceki ders beş servisi gerçek dosyalarla üretti; her birinin tanımında bir sahip satırı var. O satır
yazıldığı gün doğruydu. Gece yarısı fatura hesaplayıcı durduğunda arayan kişinin sorduğu üç soru ise
başkadır: bu servisin nöbetçisi kim, bu servis neye bağlı ve bu servis durursa kim etkilenir. Üçüncü
sorunun cevabı hiçbir servisin kendi dosyasında yazılı değildir, çünkü ters kenarı kimse kendi deposunda
tutmaz.

**Servis kataloğu**, çalışan servislerin sahiplik ve bağımlılık kayıtlarını tek yerde tutan listedir;
**geliştirici portalı** o listeyi sorulabilir hâle getiren yüzeydir. Bu dersin ölçtüğü şey portalın
görünüşü değil, kataloğun cevapladığı sorular ve **cevabın ne kadar doğru olduğudur**.

Ölçüm **bölgesel ölçüm ağı** üzerindedir: su sayacı okumalarını toplayan, doğrulayan ve saha iş emri
açan **kurgu** yazılım. Katalog kayıtları ve yer gerçeği `node` ile yazılmış bir **modeldir**.

**PT13.** Katalog on iki kayıt tutar. Kayıt beş alanlıdır: ad, sahip ekip, nöbet listesi, bağımlılık
listesi, son elle güncellemeden bu yana geçen gün.
**PT14.** Yer gerçeği son doksan günün koşum kayıtlarından çıkarılır — gözlenen çağrı kenarları ve hattı
koşturan ekip — ve modelde ayrı bir yapı olarak durur.
**PT15.** Kişi adı geçmez; ulaşılan şey bir **nöbet listesidir**.
**PT16.** Beş olay ve her adımın dakikası **önceden yazılıdır**, rastgelelik yoktur.
**PT17.** Sahip alanı iskeletin ürettiği servis tanımından okunabilir; nöbet listesi ile bağımlılık
listesi elle yazılır.
**PT18.** **Sahipsiz servis**, sahip alanı boş olan ya da var olmayan bir ekibi gösteren kayıttır.
**Öksüz bağımlılık**, katalogda kaydı olmayan bir servise bağlanan kenardır.

#### Kayıttan Grafiğe

Katalog düz bir listedir; sorulabilir olan şey listenin kendisi değil, ondan kurulan grafiktir. Her kayıt
bir düğüm, her bağımlılık bir kenar verir; sahiplik alanı düğümü bir ekibe bağlar. Grafiğin değeri iki
yerden gelir: kenarın **ters yönü** ve kayıtla gerçeğin **farkı**. İkisi de tek tek kayıtlara bakarak
görülemez.

```js
// katalog.mjs — servis katalogu kayitlari ve kosumdan cikarilan yer gercegi. Model, elle yazildi.
// kayit: [ad, sahip ekip, nobet listesi, bagimliliklar, son elle guncellemenin uzerinden gecen gun]
export const KAYIT = [
  ["okuma-toplayici", "sayac-okuma", "nobet-sayac", ["olcum-deposu", "kimlik-ucu"], 9],
  ["okuma-cozumleyici", "sayac-okuma", "nobet-sayac", ["okuma-toplayici"], 21],
  ["dogrulama-akisi", "dogrulama", "nobet-dogrulama", ["okuma-toplayici", "kural-deposu"], 14],
  ["kural-deposu", "dogrulama", "nobet-dogrulama", [], 27],
  ["fatura-hesaplayici", "faturalama", "nobet-fatura", ["dogrulama-akisi", "tarife-servisi"], 24],
  ["tarife-servisi", "faturalama", "nobet-fatura", [], 210],
  ["fatura-yazici", "faturalama", "nobet-fatura", ["fatura-hesaplayici"], 33],
  ["saha-emir", "saha", "nobet-saha", ["dogrulama-akisi", "harita-ucu"], 150],
  ["harita-ucu", "", "", [], 260],
  ["rapor-derleyici", "raporlama", "nobet-rapor",
    ["olcum-deposu", "arsiv-deposu", "fatura-yazici"], 120],
  ["gosterge-ucu", "raporlama", "nobet-rapor", ["rapor-derleyici"], 19],
  ["olcum-deposu", "dagitilmis-ekip", "nobet-eski", [], 180]];

export const GERCEK_BAG = {                         // son doksan gunde gozlenen cagri kenarlari
  "okuma-toplayici": ["olcum-deposu", "kimlik-ucu"], "okuma-cozumleyici": ["okuma-toplayici"],
  "dogrulama-akisi": ["okuma-toplayici", "kural-deposu"], "kural-deposu": [],
  "fatura-hesaplayici": ["dogrulama-akisi", "tarife-servisi", "kimlik-ucu"], "tarife-servisi": [],
  "fatura-yazici": ["fatura-hesaplayici"], "saha-emir": ["dogrulama-akisi"],
  "harita-ucu": ["kimlik-ucu"], "rapor-derleyici": ["olcum-deposu", "fatura-yazici"],
  "gosterge-ucu": ["rapor-derleyici"], "olcum-deposu": [], "kimlik-ucu": [] };

export const GERCEK_SAHIP = {                       // son doksan gunde hatti kosturan ekip
  "okuma-toplayici": "sayac-okuma", "okuma-cozumleyici": "sayac-okuma",
  "dogrulama-akisi": "dogrulama", "kural-deposu": "dogrulama", "fatura-hesaplayici": "faturalama",
  "tarife-servisi": "raporlama", "fatura-yazici": "faturalama", "saha-emir": "saha",
  "harita-ucu": "saha", "rapor-derleyici": "raporlama", "gosterge-ucu": "raporlama",
  "olcum-deposu": "sayac-okuma", "kimlik-ucu": "dogrulama" };

export const COK_EKIP = ["olcum-deposu", "harita-ucu"];   // birden cok ekibin dokundugu servis
export const EKIP = ["sayac-okuma", "dogrulama", "faturalama", "saha", "raporlama"];
```

```js
// graf.mjs — katalog kayitlarindan sahiplik ve bagimlilik grafigi kurulur, gercekle karsilastirilir.
import { KAYIT, GERCEK_BAG, GERCEK_SAHIP, EKIP } from "./katalog.mjs";

const kayitli = new Set(KAYIT.map((k) => k[0]));
const ters = {};                                    // kim bana bagli: ters kenari katalog kuruyor
for (const [ad, , , bag] of KAYIT) for (const b of bag) (ters[b] ??= []).push(ad);

const kayitsiz = Object.keys(GERCEK_BAG).filter((s) => !kayitli.has(s));
const sahipsiz = KAYIT.filter(([, s]) => !s || !EKIP.includes(s));
const oksuz = KAYIT.flatMap(([ad, , , bag]) => bag.filter((b) => !kayitli.has(b)).map((b) => [ad, b]));
console.log(`katalog ${KAYIT.length} kayit, ${KAYIT.reduce((a, k) => a + k[3].length, 0)} bagimlilik` +
  ` kenari, ${Object.keys(ters).length} servis icin ters kenar cikarilabiliyor`);
console.log(`gercekte kosan ama hic kayitli olmayan servis ${kayitsiz.length}: ${kayitsiz.join(", ")}`);
console.log(`sahipsiz servis ${sahipsiz.length}: ` +
  sahipsiz.map(([a, s]) => `${a} (${s || "alan bos"})`).join(", "));
console.log(`oksuz bagimlilik ${oksuz.length}: ` + oksuz.map(([a, b]) =>
  `${a} -> ${b} [${b in GERCEK_BAG ? "servis var, kayit yok" : "servis yok, kayit eski"}]`).join("; "));
const etkilenenKayitsiz = Object.entries(GERCEK_BAG)
  .filter(([, b]) => b.some((x) => kayitsiz.includes(x))).length;
console.log(`kayitsiz servise gercekte baglanan ${etkilenenKayitsiz} servis var;` +
  ` portalin bu ${etkilenenKayitsiz} servis icin verdigi bagimlilik cevabi eksik`);

let alan = 0, kayitUyusmaz = 0, bagFark = 0, sahipToplam = 0;   // kaydin eskimesi: kayit ile gercek
const yas = { genc: [0, 0], eski: [0, 0] };
for (const [ad, sahip, , bag, gun] of KAYIT) {
  const g = GERCEK_BAG[ad] ?? [];
  const eksik = g.filter((b) => !bag.includes(b)).length;
  const fazla = bag.filter((b) => !g.includes(b)).length;
  const sahipFark = GERCEK_SAHIP[ad] !== sahip ? 1 : 0;
  const fark = eksik + fazla + sahipFark;
  alan += fark; bagFark += eksik + fazla; sahipToplam += sahipFark;
  kayitUyusmaz += fark > 0 ? 1 : 0;
  const kova = gun <= 30 ? "genc" : "eski";
  yas[kova][0]++; yas[kova][1] += fark > 0 ? 1 : 0;
}
const elle = KAYIT.length * 2, uretilen = KAYIT.length * 2;     // nobetci ve bagimlilik elle yazilir
console.log(`\nkayit alani ${elle + uretilen}: ${uretilen} tanesi iskeletin urettigi servis` +
  ` tanimindan okunuyor, ${elle} tanesi (nobet listesi, bagimlilik) elle yaziliyor`);
console.log(`gercekle uyusmayan kayit ${kayitUyusmaz}/${KAYIT.length}, uyusmayan alan ${alan}`);
console.log(`kayit yasi <= 30 gun: ${yas.genc[1]}/${yas.genc[0]} uyusmuyor` +
  `   > 30 gun: ${yas.eski[1]}/${yas.eski[0]} uyusmuyor`);
console.log(`uyusmazligin kaynagi: bagimlilik ${bagFark}, sahiplik ${sahipToplam};` +
  ` ikisi de kosumdan cikarilabilir, nobet listesi cikarilamaz`);

const etkilenen = (s) => {                          // ters kenarda gezinti
  const yigin = [s], sonuc = new Set();
  while (yigin.length) for (const u of ters[yigin.pop()] ?? [])
    if (!sonuc.has(u)) { sonuc.add(u); yigin.push(u); }
  return [...sonuc];
};
console.log(`\n"fatura-hesaplayici durursa kim etkilenir" — katalogla ${etkilenen("fatura-hesaplayici")
  .length} servis (${etkilenen("fatura-hesaplayici").join(", ")}), 1 grafik gezintisi`);
console.log(`ayni soru katalogsuz: ${KAYIT.length} servisin bagimlilik listesi elle taranir,` +
  ` ters kenar hicbir dosyada yazili degil`);
```

```
katalog 12 kayit, 14 bagimlilik kenari, 11 servis icin ters kenar cikarilabiliyor
gercekte kosan ama hic kayitli olmayan servis 1: kimlik-ucu
sahipsiz servis 2: harita-ucu (alan bos), olcum-deposu (dagitilmis-ekip)
oksuz bagimlilik 2: okuma-toplayici -> kimlik-ucu [servis var, kayit yok]; rapor-derleyici -> arsiv-deposu [servis yok, kayit eski]
kayitsiz servise gercekte baglanan 3 servis var; portalin bu 3 servis icin verdigi bagimlilik cevabi eksik

kayit alani 48: 24 tanesi iskeletin urettigi servis tanimindan okunuyor, 24 tanesi (nobet listesi, bagimlilik) elle yaziliyor
gercekle uyusmayan kayit 6/12, uyusmayan alan 7
kayit yasi <= 30 gun: 1/6 uyusmuyor   > 30 gun: 5/6 uyusmuyor
uyusmazligin kaynagi: bagimlilik 4, sahiplik 3; ikisi de kosumdan cikarilabilir, nobet listesi cikarilamaz

"fatura-hesaplayici durursa kim etkilenir" — katalogla 3 servis (fatura-yazici, rapor-derleyici, gosterge-ucu), 1 grafik gezintisi
ayni soru katalogsuz: 12 servisin bagimlilik listesi elle taranir, ters kenar hicbir dosyada yazili degil
```

Grafiğin kurulması üç boşluğu bir arada gösterir. **Sahipsiz servis iki tanedir** ve ikisi farklı
biçimde sahipsizdir: harita ucunun sahip alanı boştur, ölçüm deposunun sahibi ise artık var olmayan bir
ekiptir. İkincisi daha tehlikelidir, çünkü kayıt dolu görünür ve hiçbir boşluk taraması onu yakalamaz.
**Öksüz bağımlılık da iki tanedir** ve nedenleri birbirinin tersidir: kimlik ucu gerçekten koşan ama
katalogda hiç kaydı olmayan bir servistir, arşiv deposu ise kayıtta duran ama gerçekte olmayan bir
servistir. Biri kaydın eksikliğidir; öteki kaydın eskimesi.

Ters kenar kataloğun tek başına verdiği cevaptır. Fatura hesaplayıcı durduğunda etkilenen üç servis
tek bir grafik gezintisiyle çıkar; aynı soruyu katalogsuz cevaplamak on iki servisin bağımlılık
listesini tek tek taramayı gerektirir, çünkü hiçbir servis kendisine kimin bağlı olduğunu bilmez.

#### Bir Olayda Doğru Nöbet Listesi

```js
// olay.mjs — bes olayda dogru nobet listesine ulasma suresi: katalogla ve katalogsuz.
import { KAYIT, GERCEK_SAHIP, COK_EKIP } from "./katalog.mjs";

const ADIM = { depo: 6, ilkMesaj: 8, ekipKanali: 15, nobetBul: 12, katalogOku: 2, cagri: 3,
  yanlisListe: 10, gozdenGecirme: 4 };              // dakika, onceden yazili; rastgelelik yok
const OLAY = ["fatura-hesaplayici", "harita-ucu", "tarife-servisi", "saha-emir", "olcum-deposu"];

const katalogsuz = (s) => ADIM.depo + ADIM.ilkMesaj + ADIM.nobetBul +
  (COK_EKIP.includes(s) ? ADIM.ekipKanali : 0);     // depo gecmisi, mesaj, gerekirse ekip kanali
const katalogla = (s) => {
  const k = KAYIT.find(([a]) => a === s);
  if (!k || !k[2]) return [ADIM.katalogOku + katalogsuz(s), k ? "nobet alani bos" : "kayit yok"];
  if (GERCEK_SAHIP[s] !== k[1])
    return [ADIM.katalogOku + ADIM.yanlisListe + katalogsuz(s), "kayit yanlis listeye yonlendirdi"];
  return [ADIM.katalogOku + ADIM.cagri, "kayit guncel"];
};

console.log("olay                 katalogsuz  katalogla  fark  durum");
let a = 0, b = 0, kazanan = 0;
for (const s of OLAY) {
  const x = katalogsuz(s), [y, not] = katalogla(s);
  a += x; b += y; kazanan += y < x ? 1 : 0;
  console.log(`${s.padEnd(20)}${String(x).padStart(8)} dk${String(y).padStart(8)} dk` +
    `${String(y - x).padStart(6)}  ${not}`);
}
const guncel = OLAY.length * (ADIM.katalogOku + ADIM.cagri);
console.log(`toplam ${a} dk -> ${b} dk   ortalama ${(a / OLAY.length).toFixed(1)} dk -> ` +
  `${(b / OLAY.length).toFixed(1)} dk   sureyi kisaltan olay ${kazanan}/${OLAY.length}`);
console.log(`butun kayitlar guncel olsaydi: ${guncel} dk, ortalama ` +
  `${(guncel / OLAY.length).toFixed(1)} dk; su anki kazanc ${a - b} dk, olabilecek ${a - guncel} dk`);

const bakim = KAYIT.length * ADIM.gozdenGecirme;    // aylik gozden gecirme: kayit basina dort dakika
const olayBasi = (a - guncel) / OLAY.length;
console.log(`\naylik gozden gecirme ${bakim} dk (${KAYIT.length} kayit x ${ADIM.gozdenGecirme} dk);` +
  ` guncel kaydin olay basina kazanci ${olayBasi} dk`);
console.log(`esik: ayda ${Math.ceil(bakim / olayBasi)} olaydan sonra gozden gecirme kendini oduyor;` +
  ` ${Math.ceil(bakim / olayBasi) - 1} olayda odemiyor`);
```

```
olay                 katalogsuz  katalogla  fark  durum
fatura-hesaplayici        26 dk       5 dk   -21  kayit guncel
harita-ucu                41 dk      43 dk     2  nobet alani bos
tarife-servisi            26 dk      38 dk    12  kayit yanlis listeye yonlendirdi
saha-emir                 26 dk       5 dk   -21  kayit guncel
olcum-deposu              41 dk      53 dk    12  kayit yanlis listeye yonlendirdi
toplam 160 dk -> 144 dk   ortalama 32.0 dk -> 28.8 dk   sureyi kisaltan olay 2/5
butun kayitlar guncel olsaydi: 25 dk, ortalama 5.0 dk; su anki kazanc 16 dk, olabilecek 135 dk

aylik gozden gecirme 48 dk (12 kayit x 4 dk); guncel kaydin olay basina kazanci 27 dk
esik: ayda 2 olaydan sonra gozden gecirme kendini oduyor; 1 olayda odemiyor
```

Katalogun kazandırdığı yer nettir: kaydı güncel olan iki serviste ulaşma süresi yirmi altı dakikadan
beş dakikaya iner. Kazandırmadığı yer daha öğreticidir. Beş olayın üçünde katalog süreyi **uzatmıştır**.
Nöbet alanı boş olan kayıt iki dakika okuma masrafı ekler ve hiçbir şey söylemez; yanlış sahip yazan iki
kayıt ise on iki dakika ekler, çünkü arayan kişi önce yanlış nöbet listesine yazar, yanıt bekler ve
ancak sonra katalogsuz yola döner. **Yanlış kayıt, kayıtsızlıktan pahalıdır** — kayıtsızlık kimseyi
yanıltmaz.

Toplamda ortalama 32 dakikadan 28,8 dakikaya iner; ölçülen kazanç on altı dakikadır. Bütün kayıtlar
gerçekle uyuşsaydı aynı beş olay yirmi beş dakikada biterdi ve kazanç yüz otuz beş dakika olurdu.
Kataloğun sunduğu değerin **yüzde on ikisi** alınmaktadır ve eksik olan şey portal değil, kaydın
doğruluğudur.

#### Kaydın Kendi Bedeli

Kayıt bedeli iki sayıda toplanır. Kırk sekiz kayıt alanının yarısı iskeletin ürettiği servis tanımından
okunur ve bedelsizdir; öteki yarısı — nöbet listesi ve bağımlılık listesi — elle yazılır. Elle yazılan
alan eskir: on iki kaydın altısı gerçekle uyuşmaz ve yedi alan yanlıştır. Eskime yaşla birlikte
gider; otuz günden genç altı kaydın biri, otuz günden eski altı kaydın beşi gerçekle uyuşmamaktadır.

Bakımın hesabı da buradan çıkar. Aylık gözden geçirme kayıt başına dört dakikadan kırk sekiz dakikadır;
güncel kaydın olay başına kazancı yirmi yedi dakikadır. **Eşik ayda iki olaydır**: ayda tek olay yaşayan
bir ağda gözden geçirme kendini ödemez, iki olaydan sonra öder. Ölçüm ağı gibi az sayıda servisin olduğu
bir yerde bu eşik yakındır ve katalog bakımının kâğıt üstünde iyi görünüp pratikte yapılmamasının nedeni
tam olarak budur.

Kataloğun gizlediği katman şudur: her ekip artık öteki ekiplerin depolarını, kanal geçmişini ve dağıtım
kayıtlarını okumak zorunda değildir, tek bir kaydı okur. Sızma da tam bu noktadadır — kayıt tek kaynak
gibi davranır ama tek kaynak değildir ve sızdığında bunu belli etmez. Dışına çıkanlar sayılıdır:
kayıtsız tek servise gerçekte üç servis bağlanmakta, yani portalın o üç servis için verdiği bağımlılık
cevabı eksik kalmaktadır. Bu üç servisin ekipleri kataloğa bakıp yanlış bir bütünlük görürler; katalogsuz
çalışan bir ekip en azından eksik baktığını bilir.

Üçüncü bir yol daha vardır ve sayıyı temelden değiştirir. Yedi uyuşmazlığın dördü bağımlılık, üçü
sahiplik kaynaklıdır; bağımlılık kenarları koşum kayıtlarından, sahiplik ise hat koşumlarından
çıkarılabilir. İkisi de çıkarılırsa uyuşmazlık sıfırlanır ve elle yazılan alan yirmi dörtten on ikiye
iner. Geriye kalan tek alan **nöbet listesidir** ve o hiçbir koşumdan çıkarılamaz, çünkü nöbet bir
gözlem değil, bir karardır.

#### Özet

- On iki kayıttan kurulan grafik üç boşluk gösterdi: 2 sahipsiz servis, 2 öksüz bağımlılık ve gerçekte
  koşup katalogda hiç kaydı olmayan 1 servis.
- İki sahipsizlik ve iki öksüzlük farklı türdendi: biri boş alan, öteki var olmayan ekip; biri kaydın
  eksikliği, öteki kaydın eskimesi.
- Ters kenar kataloğun tek başına verdiği cevaptı: fatura hesaplayıcı durunca etkilenen 3 servis tek
  gezintiyle çıktı, aynı soru katalogsuz 12 bağımlılık listesinin taranmasını gerektirirdi.
- Beş olayda ulaşma süresi ortalama 32 dakikadan 28,8 dakikaya indi, ama 5 olayın 3'ünde katalog süreyi
  uzattı; yanlış kayıt 12 dakika, boş alan 2 dakika ekledi.
- Kayıtlar güncel olsaydı aynı beş olay 25 dakikada biterdi: ölçülen kazanç 16 dakika, olabilecek kazanç
  135 dakika.
- 48 kayıt alanının 24'ü elle yazılıyor ve 6/12 kayıt gerçekle uyuşmuyor; 7 uyuşmazlığın 7'si koşumdan
  çıkarılarak kapanabilir, kapanamayan tek alan nöbet listesidir.

#### Sonraki Adım

Katalog kimin sorumlu olduğunu söyler, ama kimsenin uymak zorunda olduğu bir kural koymaz. Ölçüm ağının
kişisel veri taşıyan üç servisi için saklama süresi, kütük maskeleme ve imzalı paket zorunludur; bu
kurallar bugün bir belgede yazılıdır ve her ekibin okuyup uygulaması beklenir. Bir sonraki ders aynı
kural kümesini iki biçimde karşılaştırır: belge olarak yayımlamak ve hatta gömmek. Ölçülen şey uyum
oranı, ihlal sayısı ve ekiplerin harcadığı zamandır — ve asıl sayı kuralı hiç görmeden uyan ekip
sayısıdır.

### Politika ve Uyumluluk Otomasyonu

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/politika-ve-uyumluluk-otomasyonu

Aynı altı kural aynı on iki servis tanımında iki düzende koşturulur: kuralı belge olarak yayımlamak ve kuralı hatta gömmek. Uyum oranı, ihlal sayısı ve ekiplerin harcadığı zaman karşılaştırılır; asıl ölçü görünmezliktir — kaç ekip kuralı hiç görmeden uyuyor, kaçı muafiyet istiyor ve muafiyetin ömrü ne kadar.

Katalog kimin sorumlu olduğunu söyler, ama kimsenin uymak zorunda olduğu bir kural koymaz. Ölçüm ağının
kişisel veri taşıyan servisleri için kütük maskeleme, saklama süresi ve imzalı paket zorunludur. Bu
kurallar bugün bir belgede yazılıdır ve her ekibin okuyup uygulaması beklenir. Beklemek bir mekanizma
değildir; bu dersin sorusu kuralın nerede durduğudur.

**Politika otomasyonu**, kuralı okunacak bir metin olmaktan çıkarıp bildirim kabul eden bir kapıya
taşımaktır. Kuralların nasıl tarandığı — uygunluk işlevi, tarama sırası, yakalanan ve kaçan ihlal —
M20/K04'te ve M22/K05'in doğrulama dersinde ölçüldü ve burada tekrarlanmaz. Buranın ölçü birimi
**görünmezliktir**: kural hatta gömülünce kaç ekip onu hiç görmeden uyar.

Ölçüm **bölgesel ölçüm ağı** üzerindedir: su sayacı okumalarını toplayan, doğrulayan ve saha iş emri
açan **kurgu** yazılım. Kural kümesi de tanım kümesi de `node` ile yazılmış bir **modeldir**.

**PT19.** Kural kümesi altı kuraldır ve ders içinde **kendi küçük biçimimizle** tanımlanır. Tanım
kümesi on iki servistir; her tanım sekiz alan taşır.
**PT20.** Belge düzeninde ekip belgeyi okur ve kendi servislerine uygular. Süreler önceden yazılıdır:
belge okuma ekip başına 20 dakika, servis başına gözden geçirme 15 dakika, denetimde yakalanan ihlalin
düzeltilmesi 25 dakika.
**PT21.** Hatta gömülü düzende dört kural hattın kendi düzelttiği türdendir, iki kural ret üretir. Ret
düzeltmesi 8 dakika, muafiyet başvurusu 30 dakikadır.
**PT22.** Muafiyet kayıtları, verilen süreler ve gerekçeler önceden yazılıdır; bugün, veriliş gününden
geçen gün sayısıyla anılır.
**PT23.** Kuralları hatta gömmenin bir kerelik bedeli kural başına 90 dakikadır.
**PT24.** Bir ekibin kuralı **görmesi**, ya ret iletisi alması ya da muafiyet başvurusu yapmasıdır;
hattın sessizce düzelttiği ihlal ekibe hiç görünmez.

#### İki Düzen, Aynı Kural Kümesi

```js
// kural.mjs — alti kural ve on iki servis tanimi; ikisi de ders icinde tanimli. Model.
export const ALAN = ["ekip", "veri-sinifi", "maskeleme", "imzalama", "saglik-ucu",
  "kutuk-duzeyi", "saklama-gun", "duman"];
const HAM = {
  "okuma-toplayici":    ["sayac-okuma", "olcum", "kapali", "var", "/saglik", "ozet", 365, "var"],
  "okuma-cozumleyici":  ["sayac-okuma", "olcum", "kapali", "var", "/saglik", "ozet", 365, "var"],
  "dogrulama-akisi":    ["dogrulama", "olcum", "kapali", "var", "/saglik", "ozet", 400, "var"],
  "kural-deposu":       ["dogrulama", "olcum", "kapali", "yok", "/saglik", "ozet", 365, "var"],
  "fatura-hesaplayici": ["faturalama", "kisisel", "acik", "var", "/saglik", "ozet", 400, "var"],
  "tarife-servisi":     ["faturalama", "ozet", "kapali", "yok", "yok", "ayrinti", 700, "yok"],
  "fatura-yazici":      ["faturalama", "kisisel", "kapali", "yok", "/saglik", "ozet", 500, "yok"],
  "saha-emir":          ["saha", "kisisel", "kapali", "yok", "yok", "ayrinti", 800, "yok"],
  "harita-ucu":         ["saha", "ozet", "kapali", "yok", "yok", "ozet", 365, "yok"],
  "rapor-derleyici":    ["raporlama", "ozet", "kapali", "var", "/saglik", "ozet", 365, "var"],
  "gosterge-ucu":       ["raporlama", "ozet", "kapali", "yok", "/saglik", "ozet", 365, "yok"],
  "olcum-deposu":       ["sayac-okuma", "kisisel", "kapali", "var", "/saglik", "ozet", 400, "var"] };
export const TANIM = Object.fromEntries(Object.entries(HAM).map(([a, d]) =>
  [a, Object.fromEntries(ALAN.map((x, i) => [x, d[i]]))]));

// kural: [ad, olcut, tur, duzeltme]  — tur "otomatik" ise hat kendi duzeltir, "ret" ise ekip duzeltir
export const KURAL = [
  ["K1 maskeleme", (t) => t["veri-sinifi"] !== "kisisel" || t.maskeleme === "acik", "ret",
    (t) => ({ ...t, maskeleme: "acik" })],
  ["K2 imzali paket", (t) => t.imzalama === "var", "otomatik", (t) => ({ ...t, imzalama: "var" })],
  ["K3 saglik ucu", (t) => t["saglik-ucu"] !== "yok", "otomatik",
    (t) => ({ ...t, "saglik-ucu": "/saglik" })],
  ["K4 kutuk duzeyi", (t) => t["kutuk-duzeyi"] !== "ayrinti", "otomatik",
    (t) => ({ ...t, "kutuk-duzeyi": "ozet" })],
  ["K5 saklama suresi", (t) => t["saklama-gun"] <= 400, "ret", (t) => ({ ...t, "saklama-gun": 400 })],
  ["K6 duman sinamasi", (t) => t.duman === "var", "otomatik", (t) => ({ ...t, duman: "var" })]];

// muafiyet: [servis, kural, verilis gunu (bugunden geriye), verilen sure (gun), gerekce]
export const MUAFIYET = [
  ["olcum-deposu", "K1 maskeleme", 210, 30, "ham olcum maskelenirse dogrulama kiriliyor"],
  ["saha-emir", "K5 saklama suresi", 120, 90, "saha kayitlari 800 gun tutulmak zorunda"],
  ["tarife-servisi", "K4 kutuk duzeyi", 240, 14, "acik hata arayisi surduruluyor"],
  ["harita-ucu", "K6 duman sinamasi", 45, 60, "dis ucun sinama kosumu yok"]];

export const EKIP = ["sayac-okuma", "dogrulama", "faturalama", "saha", "raporlama"];
export const SURE = { okuma: 20, gozden: 15, duzeltme: 25, ret: 8, basvuru: 30, gomme: 90 };
```

Kural kümesi iki düzende de aynıdır; değişen tek şey kuralın nerede durduğudur. Belge düzeninde kural
metindedir ve uygulama ekibin dikkatine bağlıdır. Hatta gömülü düzende kural bir kapıdadır ve dört kural
için kapı düzeltmeyi kendi yapar, iki kural için ret verir. Kuralın ayrımı teknik değil bilgiseldir:
sağlık ucunun yolunu platform bilir, ama saklama süresini yalnız servisin ekibi bilir.

```js
// duzen.mjs — ayni kural kumesi iki duzende kosturulur: belge olarak yayimlamak ve hatta gommek.
import { TANIM, KURAL, MUAFIYET, EKIP, SURE } from "./kural.mjs";

const SERVIS = Object.keys(TANIM), cift = SERVIS.length * KURAL.length;
const muaf = (s, k) => MUAFIYET.some(([a, b]) => a === s && b === k);

const belge = () => {                               // kural belgede yazili, ekip okuyup uyguluyor
  let ihlal = 0;
  const ekipIhlal = Object.fromEntries(EKIP.map((e) => [e, 0]));
  for (const s of SERVIS) for (const [ad, olcut] of KURAL)
    if (!olcut(TANIM[s])) { ihlal++; ekipIhlal[TANIM[s].ekip]++; }
  const zaman = EKIP.length * SURE.okuma + SERVIS.length * SURE.gozden + ihlal * SURE.duzeltme;
  return { ihlal, uyum: cift - ihlal, zaman, ekipIhlal, gorulen: cift };
};

const hat = () => {                                 // kural hatta gomulu: otomatik duzeltme ya da ret
  let otomatik = 0, ret = 0, kalan = 0;
  const goren = new Set();
  for (const s of SERVIS) {
    let t = TANIM[s];
    for (const [ad, olcut, tur, duzelt] of KURAL) {
      if (olcut(t)) continue;
      if (muaf(s, ad)) { kalan++; goren.add(t.ekip); continue; }   // muafiyet kurali gorunur kilar
      if (tur === "otomatik") { t = duzelt(t); otomatik++; }
      else { t = duzelt(t); ret++; goren.add(t.ekip); }
    }
  }
  const zaman = ret * SURE.ret + MUAFIYET.length * SURE.basvuru;
  return { ihlal: kalan, uyum: cift - kalan, zaman, otomatik, ret, goren,
    gorulen: ret + MUAFIYET.length };
};

const B = belge(), H = hat();
console.log(`kural ${KURAL.length}  servis ${SERVIS.length}  denetlenen cift ${cift}` +
  `  ekip ${EKIP.length}`);
console.log(`belge duzeni : uyum ${B.uyum}/${cift} (%${(B.uyum / cift * 100).toFixed(0)})` +
  `  ihlal ${B.ihlal}  ekiplerin harcadigi ${B.zaman} dk`);
console.log(`hatta gomulu : uyum ${H.uyum}/${cift} (%${(H.uyum / cift * 100).toFixed(0)})` +
  `  kayitli istisna ${H.ihlal}  ekiplerin harcadigi ${H.zaman} dk`);
console.log(`hat ${H.otomatik} ihlali ekibe hic sormadan duzeltti, ${H.ret} ihlalde ret verdi`);
console.log(`ekip basina ihlal (belge duzeni): ` +
  EKIP.map((e) => `${e} ${B.ekipIhlal[e]}`).join("  "));

const hicGormeyen = EKIP.filter((e) => !H.goren.has(e));
console.log(`\ngorunmezlik: ${cift - H.gorulen}/${cift} cift kural hic gorunmeden uyumlu` +
  `  (ekibin gordugu ${H.gorulen}: ${H.ret} ret + ${MUAFIYET.length} muafiyet)`);
console.log(`kurali hic gormeyen ekip ${hicGormeyen.length}/${EKIP.length}: ${hicGormeyen.join(", ")}` +
  `   belge duzeninde bes ekibin besi de ${KURAL.length} kuralin tamamini okudu`);
const gomme = KURAL.length * SURE.gomme;
console.log(`hatta gomme bedeli ${gomme} dk (bir kerelik, ${KURAL.length} kural x ${SURE.gomme} dk);` +
  ` donem basina kazanc ${B.zaman - H.zaman} dk; ${(gomme / (B.zaman - H.zaman)).toFixed(2)} donemde oduyor`);
```

```
kural 6  servis 12  denetlenen cift 72  ekip 5
belge duzeni : uyum 50/72 (%69)  ihlal 22  ekiplerin harcadigi 830 dk
hatta gomulu : uyum 68/72 (%94)  kayitli istisna 4  ekiplerin harcadigi 152 dk
hat 14 ihlali ekibe hic sormadan duzeltti, 4 ihlalde ret verdi
ekip basina ihlal (belge duzeni): sayac-okuma 1  dogrulama 1  faturalama 9  saha 9  raporlama 2

gorunmezlik: 64/72 cift kural hic gorunmeden uyumlu  (ekibin gordugu 8: 4 ret + 4 muafiyet)
kurali hic gormeyen ekip 2/5: dogrulama, raporlama   belge duzeninde bes ekibin besi de 6 kuralin tamamini okudu
hatta gomme bedeli 540 dk (bir kerelik, 6 kural x 90 dk); donem basina kazanc 678 dk; 0.80 donemde oduyor
```

Üç sayı aynı yöne gider. Uyum oranı yüzde 69'dan yüzde 94'e çıkar, ihlal 22'den 4 kayıtlı istisnaya iner,
ekiplerin harcadığı zaman 830 dakikadan 152 dakikaya düşer. Kuralları hatta gömmenin bir kerelik bedeli
540 dakikadır ve tek bir denetim döneminin kazancı bunu karşılar.

Asıl sayı dördüncü satırdadır: **hat on dört ihlali ekibe hiç sormadan düzeltti.** Yetmiş iki çiftin
altmış dördünde kural hiç görünmeden karşılandı; ekiplerin gördüğü yalnız sekiz çifttir ve bunların
dördü ret, dördü muafiyettir. Beş ekibin ikisi — doğrulama ve raporlama — bu dönemde kuralların
hiçbirini görmedi, oysa belge düzeninde beşi de altı kuralın tamamını okumak zorundaydı.

İhlallerin ekiplere dağılımı bir başka şeyi gösterir. Belge düzenindeki 22 ihlalin 18'i iki ekipten
gelir: faturalama 9, saha 9. Belge herkese eşit yazılmıştı ve herkes eşit okumadı. Hatta gömülü düzende
bu eşitsizlik ortadan kalkmaz, **görünmez olur** — hat sessizce düzelttiği için hangi ekibin dikkatsiz
olduğu artık hiçbir yerde yazılı değildir. Gizlenen katman burada yalnız kuralı değil, kuralın kimin
elinde ihlal edildiği bilgisini de gizler.

Gizlenen katman bir yerde geri sızar. Hattın sessizce yaptığı düzeltme ekibin beklediği davranışı
değiştirdiğinde, ekip bunu kural metninden değil sonuçtan öğrenir: kütük düzeyi ayrıntıdan özete
çekilince açık bir hata arayışı elindeki ayrıntıyı kaybeder. Sızma tam olarak muafiyet başvurusuna yol
açan şeydir; tarife servisinin muafiyeti bu yüzden istenmiştir. Sessiz düzeltme uyum oranını yükseltir
ve aynı anda ekibin kendi sisteminde neyin neden değiştiğini bilmediği bir alan açar.

#### Muafiyetin Ömrü

```js
// muafiyet.mjs — muafiyetlerin omru: verilen sure, gecen sure, suresi dolmus ve hala acik olanlar.
import { TANIM, KURAL, MUAFIYET, SURE } from "./kural.mjs";

const otomatik = new Set(KURAL.filter(([, , t]) => t === "otomatik").map(([a]) => a));
console.log("servis            kural               verilen  gecen  gecikme  durum");
let verilenT = 0, gecenT = 0, acikDolmus = 0;
for (const [s, k, gecen, sure] of MUAFIYET) {
  const gecikme = gecen - sure;
  verilenT += sure; gecenT += gecen; acikDolmus += gecikme > 0 ? 1 : 0;
  console.log(`${s.padEnd(18)}${k.padEnd(20)}${String(sure).padStart(5)} g${String(gecen).padStart(7)}` +
    `${String(Math.max(0, gecikme)).padStart(9)}  ${gecikme > 0 ? "suresi dolmus, hala acik" : "suresi icinde"}`);
}
const n = MUAFIYET.length;
console.log(`ortalama verilen sure ${(verilenT / n).toFixed(1)} gun, ortalama gecen ` +
  `${(gecenT / n).toFixed(1)} gun -> omur verilen surenin ${(gecenT / verilenT).toFixed(1)} kati`);
console.log(`suresi dolmus ve hala acik ${acikDolmus}/${n}`);

const otoMuaf = MUAFIYET.filter(([, k]) => otomatik.has(k));
const ekipler = [...new Set(MUAFIYET.map(([s]) => TANIM[s].ekip))];
console.log(`otomatik kural uzerindeki muafiyet ${otoMuaf.length}/${n}` +
  ` (${otoMuaf.map(([s, k]) => `${s}/${k.split(" ")[0]}`).join(", ")});` +
  ` bu kurallar ilgili ekibe yalnizca muafiyet yuzunden gorundu`);
console.log(`muafiyetsiz duzende hattan gecemeyecek servis ${n}/${Object.keys(TANIM).length}` +
  ` (%${Math.round(n / Object.keys(TANIM).length * 100)}), ${ekipler.length} ekip: ${ekipler.join(", ")}`);

const cift = Object.keys(TANIM).length * KURAL.length;
console.log(`\nbasvuru zamani ${n * SURE.basvuru} dk; muafiyet kaydi ${n} ihlali gorunur kiliyor,` +
  ` belge duzeninde ayni ${n} ihlal 22 ihlalin icinde ayirt edilemiyordu`);
for (const c of [0, 1, 2, 3, 4]) {                  // ceyrek basina bir yeni muafiyet varsayimi
  const u = cift - (n + c);
  if (c === 0 || c === 4) console.log(`${c === 0 ? "bugun" : c + ". ceyrek"}: acik muafiyet ` +
    `${n + c}, uyum ${u}/${cift} (%${(u / cift * 100).toFixed(0)})`);
}
```

```
servis            kural               verilen  gecen  gecikme  durum
olcum-deposu      K1 maskeleme           30 g    210      180  suresi dolmus, hala acik
saha-emir         K5 saklama suresi      90 g    120       30  suresi dolmus, hala acik
tarife-servisi    K4 kutuk duzeyi        14 g    240      226  suresi dolmus, hala acik
harita-ucu        K6 duman sinamasi      60 g     45        0  suresi icinde
ortalama verilen sure 48.5 gun, ortalama gecen 153.8 gun -> omur verilen surenin 3.2 kati
suresi dolmus ve hala acik 3/4
otomatik kural uzerindeki muafiyet 2/4 (tarife-servisi/K4, harita-ucu/K6); bu kurallar ilgili ekibe yalnizca muafiyet yuzunden gorundu
muafiyetsiz duzende hattan gecemeyecek servis 4/12 (%33), 3 ekip: sayac-okuma, saha, faturalama

basvuru zamani 120 dk; muafiyet kaydi 4 ihlali gorunur kiliyor, belge duzeninde ayni 4 ihlal 22 ihlalin icinde ayirt edilemiyordu
bugun: acik muafiyet 4, uyum 68/72 (%94)
4. ceyrek: acik muafiyet 8, uyum 64/72 (%89)
```

Muafiyet, hattın dışına çıkmanın tek kayıtlı yoludur ve dört serviste kullanılmıştır. Verilen süreler
kısadır — ortalama 48,5 gün — ama üzerinden geçen süre ortalama 153,8 gündür: **muafiyetin ömrü verilen
sürenin üç katıdır** ve dördün üçü süresi dolduğu hâlde hâlâ açıktır. En uzunu iki yüz yirmi altı gün
gecikmiştir ve gerekçesi geçici bir hata arayışıdır.

Muafiyetlerin ikisi hattın kendi düzelttiği kurallar üzerindedir. Bu iki kural ilgili ekiplere
**yalnızca muafiyet yüzünden görünmüştür**: muafiyet, görünmez kuralı görünür kılan tek yoldur. Kuralı
hiç görmeden uyan ekip onu tartışamaz da; kuralın yanlış olduğunu ancak muafiyet isteyen fark eder.

Dışına çıkanların sayısı da buradan okunur. Muafiyet düzeni olmasaydı bu dört servis hattan hiç
geçemezdi: on iki servisin dördü, yani yüzde otuz üçü ve üç ekip altın yolun tamamen dışında kalırdı.
Muafiyetin bedeli 120 dakikalık başvuru zamanıdır ve karşılığında dört ihlal ad ad görünür olur;
belge düzeninde aynı dört ihlal, 22 ihlalin içinde ayırt edilemiyordu. Ama kayıt kendi başına kapanma
üretmez: çeyrek başına bir yeni muafiyet açılıp hiçbiri kapanmazsa dördüncü çeyrekte uyum yüzde 94'ten
yüzde 89'a iner. Kapatma işi hattın değil, muafiyeti verenin üzerindedir.

#### Özet

- Aynı 6 kural aynı 12 servis tanımında koşturuldu: belge düzeninde uyum 50/72 (%69), hatta gömülü
  düzende 68/72 (%94); ihlal 22'den 4 kayıtlı istisnaya indi.
- Ekiplerin harcadığı zaman 830 dakikadan 152 dakikaya düştü; hatta gömmenin 540 dakikalık bir kerelik
  bedeli tek denetim döneminde karşılandı.
- Görünmezlik ölçüldü: 72 çiftin 64'ünde kural hiç görünmeden karşılandı, 5 ekibin 2'si bu dönemde
  kuralların hiçbirini görmedi; belge düzeninde 5 ekibin 5'i 6 kuralın tamamını okumak zorundaydı.
- Belge düzenindeki 22 ihlalin 18'i iki ekipten geliyordu; hat bunu düzeltti ama aynı zamanda hangi
  ekibin dikkatsiz olduğu bilgisini de görünmez kıldı.
- 4 muafiyetin ortalama verilen süresi 48,5 gün, üzerinden geçen süre 153,8 gündü — ömür verilen sürenin
  3,2 katı ve 4'ün 3'ü süresi dolduğu hâlde açık.
- Muafiyet düzeni olmasaydı 12 servisin 4'ü (%33) ve 3 ekip altın yolun tamamen dışında kalırdı;
  muafiyet, hattın gizlediği kuralı ekibe gösteren tek yoldur.

#### Sonraki Adım

Ortam istendiği anda geliyor, iskelet yeni servisi başlatıyor, katalog sahibi gösteriyor ve kurallar
hatta gömülü. Dört yetenek de bir şeyi gizledi ve gizlediği şeyin bedelini birileri ödedi — ama o bedelin
kime yazıldığı henüz sorulmadı. Ölçüm ağında paylaşılan bir depo, paylaşılan bir hat havuzu ve
paylaşılan bir gösterge yığını var; bunların faturası bugün tek bir kaleme yazılıyor ve hiçbir ekip
kendi tükettiğini görmüyor. Bir sonraki ders ekip bazlı muhasebeyi ele alır: paylaşılan kaynağın
bölüştürülmesi, bölüştürülemeyen kalem ve maliyeti görünür kılmanın davranışa etkisi.

### Maliyet Görünürlüğü

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/maliyet-gorunurlugu

Ekip bazlı kaynak muhasebesi: günlük 1.376 kurgu biriminin yalnız %47,5'inin doğrudan atanabilmesi, üç bölüştürme kuralının her birinin başka ekibi başka yönde yanıltması (eşit kural sahayı +79,0 yüklerken istek kuralı sayaç okumayı +140,7 yüklüyor), maliyet gösterildikten sonra faturanın yalnız %15,6'sının düşmesi ve %29,7'sinin hiç kımıldamaması, merkezî muhasebenin üç ekipte kendini ödemesi ama iki ekibin dışına çıkmasıyla beş ekipteki 85 birimlik kazancın 3 birime inmesi.

Önceki ders kuralları hatta gömdü: beş ekip politika motorunu hiç açmadan uydu, muafiyet
sayısı sayıldı ve kuralın görünmezliği bir kazanç olarak yazıldı. Aynı beş ekip için hâlâ
görünmeyen bir şey var — **ne kadar harcadıkları**. Platform kaynağı onların yerine alıyor ve
faturayı onların yerine okuyor.

Birim maliyet, boşta kaynak ve ölçek ekonomisi M22/K06'da ölçüldü; burada o fatura girdidir.
Bu dersin sorusu tek bir bölme işlemidir: aynı tutar **beş ekibe** nasıl bölünür, bölünemeyen
ne kadardır ve bölünen tutar ekibe gösterildiğinde ne değişir.

#### Faturayı Beş Ekibe Bölmek

Örnek yine kurgu **bölgesel ölçüm ağı**dır ve beş ekip kurgudur: sayaç okuma, doğrulama,
faturalama, saha, raporlama. Kalemler, fiyatlar ve kullanım ölçüleri kurgudur; **para birimi de
kurgudur** ve `br` diye anılır, gerçek bir fiyat listesine karşılık gelmez.

**PT25:** dokuz maliyet kalemi vardır ve her kalemin günlük bir bedeli yazılıdır. **PT26:**
kalemler üç türdür — **doğrudan** atanabilen (ekip etiketi taşır), **paylaşılan** (küme denetim
düzlemi, ortak yapı ve dağıtım hattı, izleme yığını) ve **bölüştürülemeyen**; sonuncular hiçbir
ekibin kullanımıyla ilişkili değildir ve ekip olmasa da ödenir. **PT27:** paylaşılan kalemin **gerçek sürücüsü** modelde
bilinir (eş zamanlı iş, yapı dakikası, seri sayısı) ama faturada yoktur. **PT28:** bölüştürme
kuralları yalnız faturadan okunabilen ölçüleri kullanabilir: eşit pay, gözlenen kaynak kullanım
oranı, istek sayısı. **PT29:** maliyet ekibe gösterildikten sonra her kalem kendi **denetim
payı** kadar düşer; bu tek dönemlik bir tepkidir. **PT30:** merkezî muhasebe hattının sabit
günlük bedeli vardır, bir ekibin kendi muhasebesini kurmasının da.

Ekipler, kalemler ve fatura süreç içi bir **modeldir**; gerçek bir fatura yoktur.

```js
// maliyet/kalem.mjs — ekip bazli muhasebe modeli: gercek bir fatura yok. Ekipler, kalemler ve
// fiyatlar bir veri yapisidir; para birimi kurgudur ve `br` diye anilir, gercek bir fiyat
// listesine karsilik gelmez. Paylasilan kalemin *gercek surucusu* modelde bilinir, faturada
// yoktur; bolusturme kurallari yalniz faturadan okunabilen olculeri kullanabilir.

export const EKIP = ["sayac-okuma", "dogrulama", "faturalama", "saha", "raporlama"];
export const N = EKIP.length;

// dogrudan atanabilir: ad, ekip basina gunluk br, gorunurluk sonrasi dusus payi
export const DOGRUDAN = [
  ["servis ornekleri",       [96, 54, 120, 38, 72], 0.18],
  ["blok depolama",          [24, 18,  40, 12, 58], 0.10],
  ["gecici ortam kopyalari", [30, 22,  26, 10, 34], 0.55],
];

// paylasilan: ad, gunluk br, surucu adi, surucu degerleri (modelde bilinir), dusus payi
export const PAYLASILAN = [
  ["kume denetim duzlemi",   210, "es zamanli is",  [34, 12, 28, 6, 9],           0.00],
  ["ortak yapi ve dagitim",  168, "yapi dakikasi",  [220, 180, 260, 40, 610],     0.12],
  ["izleme yigini",          146, "seri sayisi",    [8200, 3100, 5400, 900, 2600], 0.30],
];

// bolusturulemez: hicbir ekibin kullanimiyla iliskisi yok; ekip olmasa da odenir
export const BOLUSTURULEMEZ = [
  ["bolge taban agi", 88], ["denetim kaydi saklama", 46], ["yedek bolge bekleme", 64],
];

// faturadan okunabilen ekip olculeri
export const OLCU = {
  kullanim: [0.31, 0.17, 0.29, 0.08, 0.15],   // gozlenen kaynak kullanim orani
  istek: [412, 96, 138, 21, 33],              // gunluk bin istek
};

export const MERKEZI = 120;   // merkezi muhasebe hattinin sabit gunluk bedeli (br)
export const EKIP_BASI = 41;  // bir ekibin kendi muhasebesini kurmasinin gunluk bedeli (br)

export const topla = (v) => v.reduce((a, b) => a + b, 0);
export const oran = (v) => { const t = topla(v); return v.map((x) => x / t); };

export const KURAL = {
  esit: () => EKIP.map(() => 1 / N),
  kullanim: () => oran(OLCU.kullanim),
  istek: () => oran(OLCU.istek),
};

// paylasilan kalemlerin ekip basina *gercek* payi: her kalem kendi surucusuyle bolusur
export const gercekPay = () => EKIP.map((_, e) =>
  topla(PAYLASILAN.map(([, br, , s]) => br * oran(s)[e])));

// bir kuralin paylasilan kalemlerde urettigi sapma: yuklenen eksi gercek
export const sapma = (ad) => {
  const p = KURAL[ad](), toplamBr = topla(PAYLASILAN.map((x) => x[1])), g = gercekPay();
  return EKIP.map((_, e) => toplamBr * p[e] - g[e]);
};
```

```js
// maliyet/olc.mjs — kalem dokumu, uc bolusturme kuralinin sapmasi, gorunurlugun davranisa
// etkisi ve merkezi muhasebenin esigi. Tum sayilar yukaridaki modelden turer.
import { EKIP, N, DOGRUDAN, PAYLASILAN, BOLUSTURULEMEZ, KURAL, MERKEZI, EKIP_BASI,
  topla, sapma } from "./kalem.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 t0 = process.hrtime.bigint();

const D = topla(DOGRUDAN.map((x) => topla(x[1])));
const P = topla(PAYLASILAN.map((x) => x[1]));
const B = topla(BOLUSTURULEMEZ.map((x) => x[1]));
const T = D + P + B, pay = (a) => `%${(100 * a / T).toFixed(1)}`;

const ADET = DOGRUDAN.length + PAYLASILAN.length + BOLUSTURULEMEZ.length;
console.log(`${N} ekip, ${ADET} kalem, gunluk ${T} br (kurgu para birimi)`);

console.log("\n1. kalem dokumu: ne dogrudan atanir, ne bolusturulur, ne bolusturulemez");
const A = [-24, 17, 11, 9, 18, 9];
yaz(A, "kalem", "tur", "gunluk br", "pay", "gercek surucu", "denetim");
for (const [ad, v, d] of DOGRUDAN)
  yaz(A, ad, "dogrudan", topla(v), pay(topla(v)), "ekip etiketi", `%${(100 * d).toFixed(0)}`);
for (const [ad, br, s, , d] of PAYLASILAN)
  yaz(A, ad, "paylasilan", br, pay(br), s, `%${(100 * d).toFixed(0)}`);
for (const [ad, br] of BOLUSTURULEMEZ)
  yaz(A, ad, "bolusturulemez", br, pay(br), "yok", "%0");
yaz(A, "toplam", "-", T, "%100", "-", "-");
console.log(`  dogrudan ${D} br (${pay(D)}), paylasilan ${P} br (${pay(P)}),`);
console.log(`  bolusturulemez ${B} br (${pay(B)}); dogrudan atanamayan ${pay(P + B)}`);

console.log("\n2. bolusturme kurali taramasi: yuklenen eksi gercek (br/gun, paylasilan)");
const C = [-11, ...EKIP.map(() => 13), 12];
yaz(C, "kural", ...EKIP, "mutlak top.");
const skor = {};
for (const k of Object.keys(KURAL)) {
  const s = sapma(k);
  skor[k] = topla(s.map(Math.abs));
  yaz(C, k, ...s.map((x) => (x >= 0 ? "+" : "") + x.toFixed(1)), skor[k].toFixed(1));
}
const enIyi = Object.keys(skor).reduce((a, b) => (skor[a] <= skor[b] ? a : b));
for (const k of Object.keys(KURAL)) {
  const s = sapma(k), i = s.indexOf(Math.max(...s)), j = s.indexOf(Math.min(...s));
  console.log(`  ${k.padEnd(9)} en cok yuklenen ${EKIP[i]} +${s[i].toFixed(1)}, ` +
    `en cok kurtulan ${EKIP[j]} ${s[j].toFixed(1)}`);
}
console.log(`  en az yanlis kural: ${enIyi}`);
console.log(`  her kural ${B} br bolusturulemez kalemi de dagitir; o tutarin sapmasi`);
console.log("  olculemez, cunku karsilastirilacak bir gercek pay yok");

console.log("\n3. gorunurlugun davranisa etkisi: maliyet ekibe gosterildikten sonra");
const E = [-24, 11, 9, 11, 26];
yaz(E, "kalem", "gunluk br", "denetim", "dusen br", "degismemesinin nedeni");
const kalemler = [
  ...DOGRUDAN.map(([ad, v, d]) => [ad, topla(v), d, "-"]),
  ...PAYLASILAN.map(([ad, br, , , d]) => [ad, br, d, d ? "-" : "platform karari"]),
  ...BOLUSTURULEMEZ.map(([ad, br]) => [ad, br, 0, "ekibin denetiminde degil"]),
];
let dusen = 0, sabitBr = 0, sabitAdet = 0;
for (const [ad, br, d, n] of kalemler) {
  dusen += br * d;
  if (d === 0) { sabitBr += br; sabitAdet++; }
  yaz(E, ad, br, `%${(100 * d).toFixed(0)}`, (br * d).toFixed(1), n);
}
console.log(`  toplam dusus ${dusen.toFixed(1)} br/gun (%${(100 * dusen / T).toFixed(1)})`);
console.log(`  hic degismeyen ${sabitAdet} kalem, ${sabitBr} br/gun (${pay(sabitBr)})`);

console.log("\n4. merkezi muhasebenin esigi ve disina cikanlarin bedeli");
const F = [-8, 13, 15, 11, 18];
yaz(F, "ekip", "merkezi br", "ayri ayri br", "kazanc", "kendini oder mi");
for (const n of [1, 2, 3, 5, 8]) {
  const ayri = n * EKIP_BASI;
  yaz(F, n, MERKEZI, ayri, (ayri - MERKEZI).toFixed(0), ayri > MERKEZI ? "evet" : "hayir");
}
const s = sapma(enIyi), sirali = EKIP.map((e, i) => [e, Math.abs(s[i])])
  .sort((a, b) => b[1] - a[1]).slice(0, 2);
const cikan = sirali.length * EKIP_BASI, brut = N * EKIP_BASI - MERKEZI;
const esik = Math.ceil(MERKEZI / EKIP_BASI);
console.log(`  esik ${esik} ekip; ${N} ekipte brut kazanc ${brut} br/gun`);
console.log(`  ${enIyi} kuralinda en cok sapan ${sirali.map((x) => x[0]).join(" ve ")} kendi`);
console.log(`  olcumunu kurar: ${cikan} br/gun yinelenen olcum, net kazanc ` +
  `${brut - cikan} br/gun`);

const ms = Number(process.hrtime.bigint() - t0) / 1e6;   // ham olcum basilmaz, bant denetlenir
console.log(`\ndort tablo ve kural taramasi 2000 ms bandinda: ${ms < 2000 ? "evet" : "hayir"}`);
```

```
5 ekip, 9 kalem, gunluk 1376 br (kurgu para birimi)

1. kalem dokumu: ne dogrudan atanir, ne bolusturulur, ne bolusturulemez
kalem                                 tur  gunluk br      pay     gercek surucu  denetim
servis ornekleri                 dogrudan        380    %27.6      ekip etiketi      %18
blok depolama                    dogrudan        152    %11.0      ekip etiketi      %10
gecici ortam kopyalari           dogrudan        122     %8.9      ekip etiketi      %55
kume denetim duzlemi           paylasilan        210    %15.3     es zamanli is       %0
ortak yapi ve dagitim          paylasilan        168    %12.2     yapi dakikasi      %12
izleme yigini                  paylasilan        146    %10.6       seri sayisi      %30
bolge taban agi            bolusturulemez         88     %6.4               yok       %0
denetim kaydi saklama      bolusturulemez         46     %3.3               yok       %0
yedek bolge bekleme        bolusturulemez         64     %4.7               yok       %0
toplam                                  -       1376     %100                 -        -
  dogrudan 654 br (%47.5), paylasilan 524 br (%38.1),
  bolusturulemez 198 br (%14.4); dogrudan atanamayan %52.5

2. bolusturme kurali taramasi: yuklenen eksi gercek (br/gun, paylasilan)
kural        sayac-okuma    dogrulama   faturalama         saha    raporlama mutlak top.
esit               -62.9        +31.0        -33.6        +79.0        -13.5       220.0
kullanim            -5.3        +15.3        +13.5        +16.1        -39.7        89.8
istek             +140.7         -1.9        -35.1        -10.1        -93.6       281.4
  esit      en cok yuklenen saha +79.0, en cok kurtulan sayac-okuma -62.9
  kullanim  en cok yuklenen saha +16.1, en cok kurtulan raporlama -39.7
  istek     en cok yuklenen sayac-okuma +140.7, en cok kurtulan raporlama -93.6
  en az yanlis kural: kullanim
  her kural 198 br bolusturulemez kalemi de dagitir; o tutarin sapmasi
  olculemez, cunku karsilastirilacak bir gercek pay yok

3. gorunurlugun davranisa etkisi: maliyet ekibe gosterildikten sonra
kalem                     gunluk br  denetim   dusen br     degismemesinin nedeni
servis ornekleri                380      %18       68.4                         -
blok depolama                   152      %10       15.2                         -
gecici ortam kopyalari          122      %55       67.1                         -
kume denetim duzlemi            210       %0        0.0           platform karari
ortak yapi ve dagitim           168      %12       20.2                         -
izleme yigini                   146      %30       43.8                         -
bolge taban agi                  88       %0        0.0  ekibin denetiminde degil
denetim kaydi saklama            46       %0        0.0  ekibin denetiminde degil
yedek bolge bekleme              64       %0        0.0  ekibin denetiminde degil
  toplam dusus 214.7 br/gun (%15.6)
  hic degismeyen 4 kalem, 408 br/gun (%29.7)

4. merkezi muhasebenin esigi ve disina cikanlarin bedeli
ekip       merkezi br   ayri ayri br     kazanc   kendini oder mi
1                 120             41        -79             hayir
2                 120             82        -38             hayir
3                 120            123          3              evet
5                 120            205         85              evet
8                 120            328        208              evet
  esik 3 ekip; 5 ekipte brut kazanc 85 br/gun
  kullanim kuralinda en cok sapan raporlama ve saha kendi
  olcumunu kurar: 82 br/gun yinelenen olcum, net kazanc 3 br/gun

dort tablo ve kural taramasi 2000 ms bandinda: evet
```

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

#### Faturanın Yarısı Doğrudan Atanamıyor

Birinci tablo günlük 1.376 birimi üç türe ayırır. Doğrudan atanabilen kalemler 654 birim
(%47,5) tutar: servis örnekleri, blok depolama ve geçici ortam kopyaları ekip etiketi taşır ve
hangi ekibin ne kadar kullandığı faturadan okunur. Kalan **%52,5** okunmaz.

Bunun 524 birimi (%38,1) **paylaşılan** kalemdir. Küme denetim düzlemi, ortak yapı ve dağıtım
hattı ile izleme yığını beş ekip için tek bir kez işletilir; tam da platformun devraldığı
katman budur. Tekil bir tutar olarak görünür ve kimseye ait değildir.

Geriye 198 birim (%14,4) **bölüştürülemeyen** kalem kalır. Bölge taban ağı, denetim kaydı
saklama ve yedek bölge bekleme üç ekiple de beş ekiple de aynı tutar; hiçbir ekip çekildiği
için azalmaz. Bu kalemin bir sahibi yoktur, bir
sürücüsü de yoktur — bölüştürme kuralı ona uygulandığında üretilen sayı bir **ölçüm** değil, bir
**karardır**.

#### Her Kural Başka Ekibi Başka Yönde Yanıltıyor

İkinci tablo üç kuralı paylaşılan 524 birim üzerinde tarar. Karşılaştırma noktası modelde
bilinen **gerçek pay**dır: her paylaşılan kalem kendi sürücüsüyle bölüşülür. Sapma, kuralın
yüklediği tutar eksi gerçek paydır; artı işareti ekibin fazla yüklendiğini, eksi işareti
kurtulduğunu gösterir.

**Eşit pay** en kaba sonucu verir (mutlak toplam 220,0). Saha ekibi **+79,0 birim** fazla
yüklenir: beş ekibin en küçüğüdür, eş zamanlı işi altıdır, yapı dakikası kırktır, serisi
dokuz yüzdür — ama beşte bir öder. Sayaç okuma **−62,9 birim** kurtulur; küme denetim
düzleminin en ağır kullanıcısıdır ama bunu faturasında görmez.

**Kullanım oranı** en az yanlış kuraldır (89,8) ama tek yönlü değildir: raporlama **−39,7**
kurtulur, çünkü kaynak kullanımı düşük olsa da yapı dakikasının %46,6'sını tek başına harcar.
Gözlenen kullanım oranı yapı hattının sürücüsünü hiç görmez.

**İstek sayısı** en yanıltıcı kuraldır (281,4). Sayaç okuma **+140,7 birim** yüklenir çünkü
günlük 412 bin istekle en yüksek sayıya sahiptir; oysa istek başına maliyeti düşüktür.
Raporlama **−93,6** kurtulur: gecelik toplu iş isteğe dönüşmez.

Üç kural üç farklı ekibi üç farklı yönde yanıltır ve hiçbiri diğerinin hatasını düzeltmez.
Bunun üstüne 198 birimlik bölüştürülemeyen kalem her kuralda yine dağıtılır ve o tutarın
sapması **ölçülemez** — karşılaştırılacak bir gerçek pay yoktur. **Maliyet görünürlüğünde** bu
katlanılabilir bir yanlıştır: sayı gösterilir, kimse ödemez. **Maliyet yansıtmasında** aynı sayı
bir bütçeden düşer ve tartışma kuralın kendisine kayar.

#### Görünürlük Neyi Kımıldatıyor

Üçüncü tablo maliyeti ekibe gösterir ve ne düştüğünü sayar. Toplam düşüş **214,7 birim**
(%15,6). Düşüşün geldiği yer beklenen yer değildir: en yüksek tepki oranı **geçici ortam
kopyalarındadır** (%55, 67,1 birim) — ekip kullanılmayan ortamı kendi silebilir. Servis
örnekleri büyüklüğü sayesinde yakın bir tutar düşürür (68,4 birim) ama oranı %18'dir; boyut
değiştirmek dağıtım gerektirir. İzleme yığını %30 düşer, çünkü ekip kendi etiketlerini
seyreltebilir.

Dört kalem **hiç kımıldamaz**: 408 birim, faturanın **%29,7'si**. Küme denetim düzlemi bir
platform kararıdır; bölge taban ağı, denetim kaydı saklama ve yedek bölge bekleme hiçbir ekibin
denetiminde değildir — denetim kaydı saklama üstelik önceki dersteki politika kuralının kendi
bedelidir. Bu kalemleri ekibin faturasında göstermek düşüş üretmez, yalnız **soru** üretir.

Soyutlamanın sızdığı yer burasıdır. Ekip platformu kullanmaya kendi altyapı katmanını görmemek
için başladı; şimdi faturasında dört kalem duruyor ve tutarını değiştirmek için o katmanı
öğrenmek zorunda. **Denetimi olmayan bir kalemi göstermek görünürlük değil, gürültüdür.**

#### Merkezî Muhasebenin Eşiği

Dördüncü tablo platformun kazandırıp kazandırmadığını sorar. Merkezî muhasebe hattı günlük 120
birim sabit tutar; ekip kendi muhasebesini kurarsa 41 birim öder. Eşik **üç ekiptir**: tek
ekipte merkezî hat 79 birim, iki ekipte 38 birim **pahalıdır**. Az ekiple platform muhasebesi
kendini ödemez ve bunun bir tercih değil, bir aritmetik olduğu tablodadır.

Beş ekipte brüt kazanç 85 birimdir. Buna dışına çıkanlar eklenir: kullanım kuralında en çok
sapan raporlama (−39,7) ve saha (+16,1) sonuca güvenmez ve kendi ölçümünü kurar. İkisinin
yinelenen ölçümü **82 birim** tutar; brüt 85 birimlik kazanç **3 birime** iner. Beş ekip
merkezî muhasebeyi neredeyse hiç kazandırmayan bir noktada işletir ve nedeni maliyetin
kendisi değil, **bölüştürme kuralına duyulan güvensizliktir**.

#### Özet

- Günlük 1.376 kurgu biriminin yalnız %47,5'i doğrudan atanır; %38,1 paylaşılan, %14,4
  bölüştürülemeyen kalemdir — faturanın **%52,5'i** bir kural olmadan ekibe yazılamaz.
- Üç bölüştürme kuralı üç ayrı ekibi ters yönde yanıltır: eşit pay sahayı +79,0 yükler, istek
  sayısı sayaç okumayı +140,7 yükler ve raporlamayı −93,6 kurtarır; en az yanlış kural olan
  kullanım oranında bile mutlak sapma 89,8 birimdir.
- 198 birimlik bölüştürülemeyen kalem her kuralda dağıtılır ama sapması ölçülemez;
  görünürlükte katlanılabilir olan bu yanlış, yansıtmada bütçeden düşer.
- Maliyet gösterildikten sonra fatura %15,6 düşer; en yüksek tepki geçici ortam kopyalarındadır
  (%55). Dört kalem hiç kımıldamaz — 408 birim, %29,7 — çünkü ekibin denetiminde değildir.
- Merkezî muhasebe üç ekipten sonra kendini öder; iki ekipte 38 birim pahalıdır. Beş ekipte
  brüt kazanç 85 birimken, kurala güvenmeyen iki ekibin kendi ölçümünü kurması kazancı 3 birime
  indirir.

#### Sonraki Adım

Bu dersin sayıları platformun ne kadar tuttuğunu söylüyor ama kime yaradığını söylemiyor.
Sıradaki ders soruyu zamana yayar: beş ekip yeni düzene aynı anda geçmez, dalgalar hâlinde
taşınır ve dalganın büyüklüğü hem iki düzenin birlikte işletileceği süreyi hem geride kalanların
sayısını belirler. Geride kalan ekibin bedeli bu dersin tablosunda hiç görünmeyen bir kalemdir.

### Göç Stratejileri

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/goc-stratejileri

Platform geçişinin dalgalara bölünmesi: beş kurgu ekip tek dalgada taşındığında program 65 günden 15 güne inerken taşınan sayısının 4'ten 2'ye düşmesi, geride kalanın üç nedeninin (uyumsuz gereksinim, kritik dönem, sahipsiz servis) sırayla devreye girmesi, çift işletim yükünün 105,3'ten 0'a inmesine karşılık tepe destek yükünün yalnız tek ekiplik dalgada 6 birimlik bütçenin altında kalması ve hiç taşınmayan tek ekip yüzünden eski düzenin süresiz açık kalarak 1.095 günde 41.610 kurgu birim tutması.

Önceki ders faturayı beş ekibe böldü ve bölünemeyen kalemi saydı. O tablonun sessiz varsayımı
şuydu: beş ekip de zaten platformun üstünde. Gerçekte hiçbiri orada doğmadı — hepsi bir yerden
taşındı ya da hâlâ taşınmadı. Bu dersin ölçtüğü şey o taşımanın kendisidir.

Aşamalı geçiş kalıbının kendisi — eski düzenin çevresine sarılıp parça parça yerini alan
**boğucu incir** — M16/K06 ve M20/K03'te ölçüldü; burada tekrarlanmaz. Buradaki soru kalıbın
değil, **takvimin** sorusudur: beş ekip kaçarlı gruplar hâlinde taşınırsa ne olur.

#### Programı Dalgalara Bölmek

Örnek yine kurgu **bölgesel ölçüm ağı**dır ve beş ekip kurgudur. Yükler, engeller ve bedeller
kurgudur; **para birimi de kurgudur** ve `br` diye anılır.

**PT31:** her ekibin bir **taşıma yükü** vardır, destek-birimi cinsinden. **PT32:** program
`ceil(5 / dalga)` dalga olarak planlanır; her dalga 5 gün hazırlık ve 8 gün kesim-doğrulama
sürer. Dalgasını kaçıran ekip bir sonrakine kalır, son dalgayı da kaçırırsa **geride kalır**.
**PT33:** platform ekibinin günlük destek bütçesi 6 birimdir; bir dalganın yükü sekiz günlük
bütçeyi aşarsa aşan kısım dalgayı uzatır. **PT34:** üç engel vardır — **kritik dönem** (0–30.
günler arasında taşınamaz), **uyumsuz gereksinim** (hiç taşınamaz; uyumsuzluk doğrulama
sırasında ortaya çıkar ve yükün %40'ı boşa gider), **sahipsiz servis** (yük 1,6 katına çıkar ve
ekip yalnız dalgada boşluk varsa taşınır). **PT35:** taşınmış her ekip son kesime kadar günlük
0,9 birim **çift işletim yükü** üretir. **PT36:** eski düzenin sabit günlük işletim bedeli ve
eksik yeteneği platforma eklemenin tek seferlik bedeli yazılıdır.

Plan ve takvim süreç içi bir **modeldir**; gerçek bir geçiş yoktur ve rastgelelik yoktur.

```js
// goc/dalga.mjs — goc dalgasi modeli: gercek bir gecis yok. Bes ekip, engelleri ve platform
// ekibinin destek butcesi bir veri yapisidir. Rastgelelik yoktur, plan tumuyle belirlenimlidir.
// Program `ceil(N/w)` dalga olarak planlanir; dalgasini kaciran ekip bir sonrakine kalir,
// son dalgayi da kacirirsa geride kalir. Para birimi kurgudur ve `br` diye anilir.

export const HAZIRLIK = 5;      // her dalganin sabit hazirlik suresi (gun)
export const TABAN = 8;         // her dalganin kesim ve dogrulama suresi (gun)
export const KAPASITE = 6;      // platform ekibinin gunluk destek butcesi (destek-birimi)
export const CIFT = 0.9;        // tasinmis ekip basina gunluk cift isletim yuku
export const BOSA = 0.4;        // basarisiz denemede harcanan yuk orani
export const ADIM = 14;         // ekip kendi tasisa yeniden yazacagi altyapi adimi
export const KALAN_ADIM = 4;    // platform devraldiktan sonra ekibe kalan adim
export const ESKI_SABIT = 38;   // eski duzenin gunluk sabit isletim bedeli (br)
export const YETENEK = 2400;    // eksik yetenegi platforma eklemenin tek seferlik bedeli (br)

// ekip: ad, tasima yuku (destek-birimi), engel, kritik donem penceresi (gun araligi)
export const EKIP = [
  { ad: "sayac-okuma", yuk: 18, engel: null, pencere: null },
  { ad: "dogrulama", yuk: 14, engel: null, pencere: null },
  { ad: "faturalama", yuk: 22, engel: "kritik donem", pencere: [0, 30] },
  { ad: "saha", yuk: 26, engel: "uyumsuz gereksinim", pencere: null },
  { ad: "raporlama", yuk: 16, engel: "sahipsiz servis", pencere: null },
];
export const N = EKIP.length;
export const etkinYuk = (e) => (e.engel === "sahipsiz servis" ? e.yuk * 1.6 : e.yuk);
const cakisir = (p, a, b) => p !== null && !(b < p[0] || a > p[1]);

export function planla(w) {
  const sayi = Math.ceil(N / w), dalgalar = [], tasinan = [], geride = [];
  let t = 0, kalan = EKIP.map((_, i) => i), bosa = 0;
  for (let d = 0; d < sayi && kalan.length; d++) {
    const bas = t + HAZIRLIK, son = bas + TABAN - 1, secilen = [];
    let yuk = 0;
    for (const i of kalan) {
      if (secilen.length >= w) break;
      const e = EKIP[i], ey = etkinYuk(e);
      if (cakisir(e.pencere, bas, son)) continue;     // kritik donem: sonraki dalgaya kalir
      if (e.engel === "sahipsiz servis" && yuk + ey > KAPASITE * TABAN) continue;  // slack yok
      secilen.push(i); yuk += ey;
    }
    if (!secilen.length) { t += HAZIRLIK + TABAN; continue; }
    const gecikme = Math.max(0, Math.ceil((yuk - KAPASITE * TABAN) / KAPASITE));
    const sure = HAZIRLIK + TABAN + gecikme, kesim = t + sure - 1;
    for (const i of secilen) {
      if (EKIP[i].engel === "uyumsuz gereksinim") {   // uyumsuzluk dogrulamada ortaya cikar
        geride.push([i, "uyumsuz gereksinim"]); bosa += EKIP[i].yuk * BOSA;
      } else tasinan.push([i, kesim]);
    }
    dalgalar.push({ bas, son, sure, yuk, secilen });
    kalan = kalan.filter((i) => !secilen.includes(i));
    t += sure;
  }
  for (const i of kalan) geride.push([i, EKIP[i].engel ?? "dalga kalmadi"]);

  const kesimler = tasinan.map((x) => x[1]);
  const ilk = kesimler.length ? Math.min(...kesimler) : 0;
  const bitis = kesimler.length ? Math.max(...kesimler) : 0;
  const gun = new Array(t + 1).fill(0);
  for (const x of dalgalar) for (let g = x.bas; g <= x.son; g++) gun[g] += x.yuk / TABAN;
  for (const [, k] of tasinan) for (let g = k + 1; g <= bitis; g++) gun[g] += CIFT;
  return { w, dalga: dalgalar.length, program: t, tasinan, geride, bosa, birlikte: bitis - ilk,
    tepe: Math.max(...gun), cift: tasinan.reduce((a, [, k]) => a + CIFT * (bitis - k), 0),
    adim: tasinan.length * (ADIM - KALAN_ADIM) };
}
```

```js
// goc/olc.mjs — dalga buyuklugu taramasi, geride kalanin nedeni ve hic tasinmayanin bedeli.
import { EKIP, N, KAPASITE, ESKI_SABIT, YETENEK, ADIM, KALAN_ADIM, planla } from "./dalga.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 t0 = process.hrtime.bigint();

const W = [1, 2, 3, 5], AYAR = W.map(planla);
console.log(`${N} ekip, platform destek butcesi ${KAPASITE} birim/gun`);

console.log("\n1. dalga buyuklugu taramasi");
const A = [-7, 8, 10, 10, 9, 15, 10, 10];
yaz(A, "dalga", "sayisi", "program", "tasinan", "geride", "kesim araligi", "tepe yuk",
  "cift yuk");
for (const r of AYAR)
  yaz(A, r.w, r.dalga, `${r.program} gun`, `${r.tasinan.length}/${N}`, r.geride.length,
    `${r.birlikte} gun`, r.tepe.toFixed(2), r.cift.toFixed(1));
console.log(`  destek butcesini asan ayar: ` +
  AYAR.filter((r) => r.tepe > KAPASITE).map((r) => `dalga=${r.w}`).join(", "));
console.log("  kesim araligi: ilk kesimden son kesime — iki duzenin birlikte isletildigi");
console.log("  surenin dalga buyuklugune bagli bolumu; eski duzen hicbir ayarda kapanmaz");

console.log("\n2. geride kalan kim, nedeni ne");
const B = [-16, -20, ...W.map(() => 9)];
yaz(B, "ekip", "neden", ...W.map((w) => `dalga=${w}`));
for (let i = 0; i < N; i++) {
  const satir = AYAR.map((r) => r.geride.find((x) => x[0] === i));
  if (!satir.some(Boolean)) continue;
  yaz(B, EKIP[i].ad, satir.find(Boolean)[1], ...satir.map((g) => (g ? "geride" : "tasindi")));
}
yaz(B, "kurtarilan adim", `${ADIM} yerine ${KALAN_ADIM}`, ...AYAR.map((r) => r.adim));
console.log(`  uyumsuzluk dogrulamada ortaya cikar: bosa giden destek ` +
  `${AYAR[0].bosa.toFixed(1)} birim (her ayarda ayni)`);

console.log("\n3. hic tasinmayanin uzun vadeli bedeli (kurgu para birimi)");
const kalanEkip = AYAR[0].geride.length, oncePay = ESKI_SABIT / N;
const sonraPay = ESKI_SABIT / kalanEkip, basabas = Math.ceil(YETENEK / ESKI_SABIT);
const C = [-24, 12, 12, 13];
yaz(C, "kalem", "gunluk br", "365 gun", "1095 gun");
yaz(C, "eski duzenin isletimi", ESKI_SABIT, ESKI_SABIT * 365, ESKI_SABIT * 1095);
yaz(C, "eksik yetenegi eklemek", "-", YETENEK, YETENEK);
yaz(C, "fark", "-", ESKI_SABIT * 365 - YETENEK, ESKI_SABIT * 1095 - YETENEK);
console.log(`  basa bas ${basabas}. gun; eski duzen ${kalanEkip} ekip icin acik kalir`);
console.log(`  ekip basina eski duzen bedeli ${oncePay.toFixed(1)} -> ${sonraPay.toFixed(1)} ` +
  `br/gun (${(sonraPay / oncePay).toFixed(1)} kat)`);

const ms = Number(process.hrtime.bigint() - t0) / 1e6;   // ham olcum basilmaz, bant denetlenir
console.log(`\nuc tablo ve dalga taramasi 2000 ms bandinda: ${ms < 2000 ? "evet" : "hayir"}`);
```

```
5 ekip, platform destek butcesi 6 birim/gun

1. dalga buyuklugu taramasi
dalga    sayisi   program   tasinan   geride  kesim araligi  tepe yuk  cift yuk
1             5    65 gun       4/5        1         52 gun      5.95     105.3
2             3    39 gun       4/5        1         26 gun      7.75      46.8
3             2    28 gun       3/5        2         13 gun      7.25      23.4
5             1    15 gun       2/5        3          0 gun      7.25       0.0
  destek butcesini asan ayar: dalga=2, dalga=3, dalga=5
  kesim araligi: ilk kesimden son kesime — iki duzenin birlikte isletildigi
  surenin dalga buyuklugune bagli bolumu; eski duzen hicbir ayarda kapanmaz

2. geride kalan kim, nedeni ne
ekip            neden                 dalga=1  dalga=2  dalga=3  dalga=5
faturalama      kritik donem          tasindi  tasindi   geride   geride
saha            uyumsuz gereksinim     geride   geride   geride   geride
raporlama       sahipsiz servis       tasindi  tasindi  tasindi   geride
kurtarilan adim 14 yerine 4                40       40       30       20
  uyumsuzluk dogrulamada ortaya cikar: bosa giden destek 10.4 birim (her ayarda ayni)

3. hic tasinmayanin uzun vadeli bedeli (kurgu para birimi)
kalem                      gunluk br     365 gun     1095 gun
eski duzenin isletimi             38       13870        41610
eksik yetenegi eklemek             -        2400         2400
fark                               -       11470        39210
  basa bas 64. gun; eski duzen 1 ekip icin acik kalir
  ekip basina eski duzen bedeli 7.6 -> 38.0 br/gun (5.0 kat)

uc tablo ve dalga taramasi 2000 ms bandinda: evet
```

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

#### Dalga Büyüdükçe Takvim Kısalıyor, Kapsam Daralıyor

Birinci tablo dört ayarı yan yana koyar ve iki sütun ters yönde ilerler. Program süresi tek
ekiplik dalgada **65 gün**, beş ekiplik tek dalgada **15 gündür** — dört kattan fazla. Aynı
yönde kesim aralığı 52 günden 0 güne, çift işletim yükü 105,3 birimden 0'a iner. Büyük dalga
takvimi kısaltır ve bunda gizli bir şey yoktur.

Ters yönde ilerleyen sütun taşınan ekip sayısıdır: **4/5'ten 2/5'e** düşer. Beş ekiplik dalga
programı dört kattan fazla kısaltırken kapsamı yarıya indirir. On beş günde biten bir geçiş,
geçişin kendisinin yarısını hiç yapmamış olmakla ölçülür.

Üçüncü bir sütun ikisinden de bağımsız davranır. Tepe destek yükü tek ekiplik dalgada **5,95
birim**, diğer üç ayarda 7,25 ile 7,75 arasındadır; platform ekibinin günlük bütçesi 6 birimdir.
Yalnız `dalga=1` bütçenin içinde kalır. Büyük dalga aynı işi daha kısa bir pencereye sıkıştırır
ve sıkıştırılan iş bir yerde taşar: `dalga=3` ve `dalga=5` ayarlarında ilk dalganın yükü sekiz
günlük bütçeyi aşar ve dalgayı iki gün uzatır.

Bu tablonun okunmayan bir yeri var: kesim aralığı **sıfır** olan ayar iki düzenin birlikte
işletilmediği anlamına gelmez. Sıfır, taşınan iki ekibin aynı gün kesime girdiği anlamına gelir.
Eski düzen dört ayarın hiçbirinde kapanmaz ve nedeni ikinci tablodadır.

#### Geride Kalanın Adı Var

İkinci tablo geride kalanı isimle ve nedenle yazar. Üç neden üç ayrı ayarda devreye girer.

**Uyumsuz gereksinim** her ayarda geride bırakır. Saha ekibinin uç düğümleri çevrimdışı
çalışırken de veri toplar; platform sürekli bağlantı varsayar. Dalga büyüklüğü bu engeli hiç
etkilemez, çünkü engel takvimde değil yetenektedir. Uyumsuzluk kesim doğrulaması sırasında
ortaya çıktığı için ekibin yükünün %40'ı, **10,4 birim** destek, her ayarda boşa gider.

**Kritik dönem** `dalga=3` ve `dalga=5`'te devreye girer. Faturalama ekibi 0–30. günler
arasında taşınamaz; iki ya da bir dalgalık programda o pencerenin dışına düşen bir dalga
kalmaz. Beş dalgalık programda üçüncü dalga 31. günde başlar ve ekip taşınır. **Takvim
esnekliği bir kapasitedir ve yalnız dalga sayısı çoğaldıkça vardır.**

**Sahipsiz servis** yalnız `dalga=5`'te devreye girer. Raporlama ekibinin iki servisinin sahibi
yoktur; işi platform ekibi yapar ve yük 1,6 katına, 25,6 birime çıkar. Tek dalgalık programda
diğer üç ekip sekiz günlük bütçeyi zaten doldurduğu için bu yüke yer kalmaz.

Son satır platformun ne kazandırdığını sayar: taşınan ekip kendi göç adımlarının **14'ünden
10'unu** platforma bırakır, 4 adım kendinde kalır. Kazanç doğrudan taşınan sayısına bağlıdır —
`dalga=1`'de 40 adım, `dalga=5`'te 20. Saha ekibi hiçbir ayarda tek adım kazanmaz.

Soyutlamanın sızdığı yer kesim aralığıdır. O gün sayısı boyunca taşınmış ekipler yeni düzende,
taşınmamışlar eskisinde çalışır ve aradaki her bağlantıyı kuran taraf **iki düzenin de** ayarını
bilmek zorundadır. Platformun kapattığını iddia ettiği katman tam da geçiş sırasında yeniden
açılır ve `dalga=1` ayarında bu 52 gün sürer. En çok ekibi taşıyan ayar, soyutlamanın en uzun
süre sızdığı ayardır.

#### Hiç Taşınmayanın Faturası

Üçüncü tablo tek bir kalemi sorar: hiç taşınmayan ne kadar tutuyor. Eski düzenin sabit işletim
bedeli günlük 38 birimdir ve tek bir ekip orada kaldığı sürece ödenir — 365 günde **13.870**,
1.095 günde **41.610** birim. Eksik yeteneği platforma eklemek tek seferlik 2.400 birimdir ve
başa baş noktası **64. gündür**. Üç yıllık farkın 39.210 birim olması bu kararın bir bütçe
kalemi değil, bir eşik olduğunu gösterir.

İkinci sayı daha keskindir. Eski düzen beş ekip tarafından paylaşılırken ekip başına günlük 7,6
birim düşüyordu; dört ekip taşındıktan sonra aynı 38 birimi tek başına saha ekibi taşır —
**5 kat**. Geçiş, geride kalan için maliyeti azaltmaz, beşe katlar. Platformun kazandırmadığı
durum burada tek bir çarpanla görünür: saha ekibi 0 adım kazanmış, 10,4 birim destek harcatmış
ve işletim payını beş katına çıkarmıştır.

Buradan iki yol çıkar ve ikisi de tablodadır: yeteneği platforma eklemek (2.400 birim, 64 günde
kendini öder) ya da iki düzeni süresiz işletmek. Üçüncü bir yol — "geçiş tamamlandı" demek —
sayıların hiçbirine karşılık gelmez.

#### Özet

- Dalga büyüklüğü 1'den 5'e çıkarken program 65 günden 15 güne, kesim aralığı 52 günden 0'a,
  çift işletim yükü 105,3 birimden 0'a iner; buna karşılık taşınan ekip sayısı 4/5'ten 2/5'e
  düşer ve geride kalan 1'den 3'e çıkar.
- Tepe destek yükü yalnız tek ekiplik dalgada (5,95) günlük 6 birimlik bütçenin altında kalır;
  diğer üç ayarda 7,25–7,75 arasındadır ve `dalga=3` ile `dalga=5`'te ilk dalga iki gün uzar.
- Geride kalmanın üç nedeni ayrı ayarlarda devreye girer: uyumsuz gereksinim her ayarda (saha,
  10,4 birim boşa giden destek), kritik dönem `dalga≥3`'te (faturalama), sahipsiz servis yalnız
  `dalga=5`'te (raporlama).
- Platformun kazancı taşınan sayısıyla orantılıdır — 14 adımın 10'u devredilir, `dalga=1`'de 40
  adım, `dalga=5`'te 20; hiç taşınmayan ekip tek adım kazanmaz.
- Hiç taşınmayan tek ekip yüzünden eski düzen süresiz açık kalır: günlük 38 birim, 1.095 günde
  41.610 birim. Eksik yeteneği eklemek 2.400 birimdir ve 64. günde kendini öder; geride kalanın
  işletim payı 7,6'dan 38,0 birime, beş katına çıkar.

#### Sonraki Adım

Altı ders platformun ne yaptığını saydı: ortam sağladı, iskelet üretti, katalog tuttu, kural
gömdü, maliyeti böldü ve ekipleri dalgalar hâlinde taşıdı. Her derste bir de karşı sayı vardı —
sızan durum, dışına çıkan ekip, kendini ödemeyen eşik. Sıradaki ders bu iki sütunu tek bir
soruya bağlar: platformu benimseyen ekiplerle benimsemeyenler arasındaki fark ölçülebilir mi ve
platformun kendi ölçütleri hangi noktada benimseme sayısını değil, benimsemenin işe yaradığını
göstermeye başlar.

### Platform Ölçütleri

Source: https://academia.sh/tr/kurslar/platform-muhendisligi/platform-olcutleri

Platformun işe yarayıp yaramadığının ölçülmesi: kırk ekip-yetenek çiftinden yalnız yirmi beşinin dolu olması, elli dört iş günlük iki yeteneğin en çok bir ekibe hizmet etmesi, dört teslimat ölçütündeki ham farkın %48-%77'sinin seçim yanlılığından gelmesi ve fark-farkının dördünde de grup içi yayılımdan küçük kalması, aynı 550 dakikalık kesintinin merkezî düzende 2.750 ekip-dakikaya çıkması ve benimsemeyi zorunlu kılmanın ölçütü %60 iyileştirirken kullanım başına işi %18 kötüleştirmesi.

Önceki ders beş ekibi dalgalar hâlinde taşıdı ve geride kalanı adıyla saydı. Bu konu boyunca
her ders platformun **ne yaptığını** saydı; hiçbiri bunların ekiplerin işini gerçekten
hızlandırıp hızlandırmadığını sormadı.

Dört teslimat ölçütü M22/K01'de tanımlandı ve burada tekrarlanmaz, girdidir. Ölçülen şey
ölçütler değil, **ölçütteki farkın nereden geldiğidir**. Through-line yine kurgu **bölgesel
ölçüm ağı** ve onun beş kurgu ekibidir.

#### Benimsemeyi Bir Sayıya Bağlamak

**PT37:** sekiz yeteneğin her birinin kurulum işi, yıllık bakımı, kullanan ekip sayısı ve
kullanım sayısı yazılıdır. **PT38:** beş ekibin dört teslimat ölçütü benimseme öncesi ve sonrası
okunur. **PT39:** üç ekip benimsemiştir; sıra göç dalgasından gelir, yani engeli olmayan ekipler
önce taşınmıştır. **PT40:** platform bir bağımlılıktır; on iki ayda kesintiler, süreleri, o an
platformu kullanan ekip sayısı ve kaynağı yazılıdır. **PT41:** benimseme zorlanırsa her
ekip-yetenek çifti bir uyum işi getirir ve zorlananların yalnız bir bölümü kullanım üretir.
**PT42:** ekip başına yıllık destek isteği ve platform ekibinin kapasitesi yazılıdır.

Yetenekler, ölçütler ve kesintiler süreç içi bir **modeldir**; rastgelelik yoktur.

```js
// olcut/veri.mjs — platform olcutleri modeli: gercek bir olcum hatti yok; yetenekler, ekip
// olcutleri ve kesintiler bir veri yapisidir, rastgelelik yoktur. Olcut *tanimlari* M22/K01'de
// kuruldu ve burada girdidir. Is gunleri kurgudur.

export const EKIP = ["sayac-okuma", "dogrulama", "faturalama", "saha", "raporlama"];
export const BENIMSEYEN = [0, 1, 4];   // goc dalgasindan gelir: engeli olmayan ekipler once
export const BENIMSEMEYEN = [2, 3];    // kritik donem ve uyumsuz gereksinim

// yetenek: ad, kurulum isi, yillik bakim (is gunu), kullanan ekip, donemdeki kullanim
export const YETENEK = [
  ["istek uzerine ortam", 34, 7, 4, 60], ["iskelet uretimi", 22, 5, 5, 5],
  ["servis katalogu", 18, 6, 3, 5], ["politika kapisi", 27, 8, 5, 72],
  ["maliyet gorunurlugu", 15, 4, 3, 30], ["goc araci", 31, 3, 4, 4],
  ["gizli deger dondurme", 19, 5, 0, 0], ["ortak gosterge kitapligi", 24, 6, 1, 3],
];

// olcut: ad, birim, yon (+1 buyuk iyi, -1 kucuk iyi), benimseme oncesi, sonrasi (ekip sirasi)
export const OLCUT = [
  ["dagitim sikligi", "hafta", +1, [4.0, 3.5, 1.6, 1.1, 2.8], [8.4, 4.6, 2.4, 1.5, 5.9]],
  ["oncu sure", "saat", -1, [52, 61, 96, 120, 47], [18, 52, 84, 112, 12]],
  ["basarisizlik orani", "%", -1, [14, 11, 18, 21, 9], [6, 9.5, 15.5, 19, 4]],
  ["onarma suresi", "dk", -1, [190, 145, 240, 310, 160], [95, 130, 215, 300, 70]],
];

// kesinti: ay, sure (dk), o an platformu kullanan ekip sayisi, kaynak
export const KESINTI = [[2, 45, 1, "platform"], [4, 120, 2, "alt katman"],
  [6, 25, 3, "platform"], [8, 210, 3, "platform"], [10, 60, 3, "alt katman"],
  [12, 90, 3, "platform"]];

export const ISTEK_EKIP = 34, KAPASITE = 90;  // ekip basina yillik istek / platform kapasitesi
export const UYUM_ISI = 4, ZORLA_KULLANAN = 4, ZORLA_KULLANIM = 3;   // zorlamanin bedeli

export const topla = (v) => v.reduce((a, b) => a + b, 0);
const ort = (v) => topla(v) / v.length;
const grup = (g, d, y) => ort(g.map((i) => d[i])) * y;

// bir olcut icin ham fark, secim yanliligi, fark-farki ve benimseyen grubun kendi ici yayilimi
export function ayir([, , yon, once, sonra]) {
  const d = (i) => (sonra[i] - once[i]) * yon;         // iyilesme, isareti duzeltilmis
  const bd = BENIMSEYEN.map(d);
  return { sonraFark: grup(BENIMSEYEN, sonra, yon) - grup(BENIMSEMEYEN, sonra, yon),
    onceFark: grup(BENIMSEYEN, once, yon) - grup(BENIMSEMEYEN, once, yon),
    farkFarki: ort(bd) - ort(BENIMSEMEYEN.map(d)),
    yayilim: Math.max(...bd) - Math.min(...bd) };
}
```

```js
// olcut/olc.mjs — benimseme dokumu, dort olcutun ayristirilmasi, platformun kendi olcutu ve
// benimsemeyi zorunlu kilmanin olcute ne yaptigi.
import { EKIP, BENIMSEYEN, YETENEK, OLCUT, KESINTI, ISTEK_EKIP, KAPASITE, UYUM_ISI,
  ZORLA_KULLANAN, ZORLA_KULLANIM, topla, ayir } from "./veri.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 t0 = process.hrtime.bigint();
const IS = topla(YETENEK.map((y) => y[1] + y[2])), KUL = topla(YETENEK.map((y) => y[4]));
const cift = topla(YETENEK.map((y) => y[3])), tumCift = YETENEK.length * EKIP.length;

console.log(`${EKIP.length} ekip, ${YETENEK.length} yetenek, ${BENIMSEYEN.length} benimseyen`);

console.log("\n1. benimseme: yetenek basina ekip ve kullanim");
const A = [-26, 8, 8, 9, 11, 14];
yaz(A, "yetenek", "kurulum", "bakim", "ekip", "kullanim", "kullanim/is");
for (const [ad, k, b, e, u] of YETENEK)
  yaz(A, ad, k, b, `${e}/${EKIP.length}`, u, u ? ((k + b) / u).toFixed(2) : "-");
yaz(A, "toplam", topla(YETENEK.map((y) => y[1])), topla(YETENEK.map((y) => y[2])),
  `${cift}/${tumCift}`, KUL, (IS / KUL).toFixed(2));
const bos = YETENEK.filter((y) => y[3] <= 1), bosIs = topla(bos.map((y) => y[1] + y[2]));
console.log(`  benimseme %${(100 * cift / tumCift).toFixed(1)}, ` +
  `${(cift / YETENEK.length).toFixed(2)} ekip/yetenek; en az kullanilan ` +
  `${bos.length} yetenek ${bosIs} is gunu (%${(100 * bosIs / IS).toFixed(0)})`);

console.log("\n2. dort teslimat olcutu: fark platformdan mi geliyor");
const B = [-24, 11, 17, 12, 10, 10];
yaz(B, "olcut", "ham fark", "secim yanliligi", "fark-farki", "yayilim", "ayrilir");
for (const o of OLCUT) {
  const r = ayir(o);
  yaz(B, `${o[0]} (${o[1]})`, r.sonraFark.toFixed(2), r.onceFark.toFixed(2),
    r.farkFarki.toFixed(2), r.yayilim.toFixed(2),
    Math.abs(r.farkFarki) > r.yayilim ? "evet" : "hayir");
}
const p = OLCUT.map((o) => { const r = ayir(o); return 100 * r.onceFark / r.sonraFark; });
console.log(`  secim yanliligi ham farkin %${Math.min(...p).toFixed(0)}-` +
  `%${Math.max(...p).toFixed(0)}'ini aciklar`);
console.log("  fark-farki dordunde de yayilimdan kucuk: kalan pay ayrilamiyor");

console.log("\n3. platform bir bagimliliktir: ayni kesinti kac ekibi durduruyor");
const sure = topla(KESINTI.map((k) => k[1]));
const gercek = topla(KESINTI.map((k) => k[1] * k[2]));
const pk = KESINTI.filter((k) => k[3] === "platform");
console.log(`  ${KESINTI.length} kesinti ${sure} dk; platform kaynakli ${pk.length} kesinti ` +
  `(${topla(pk.map((k) => k[1]))} dk), alt katman ${KESINTI.length - pk.length} kesinti`);
const C = [-11, 14, 18, 15, 16];
yaz(C, "benimseyen", "dagitilmis", "merkezi ekip-dk", "destek istegi", "kapasite asimi");
for (const n of [1, 3, 5])
  yaz(C, n, `${sure} ekip-dk`, n * sure, n * ISTEK_EKIP,
    n * ISTEK_EKIP > KAPASITE ? `%${(100 * (n * ISTEK_EKIP / KAPASITE - 1)).toFixed(0)}` : "-");
console.log(`  gerceklesen ${gercek} ekip-dk (benimseme donem icinde buyudu), ` +
  `dagitilmisin ${(gercek / sure).toFixed(1)} kati`);

console.log("\n4. benimsemeyi zorunlu kilmak olcute ne yapiyor");
const zorlanan = tumCift - cift, ekIs = zorlanan * UYUM_ISI;
const ekKul = ZORLA_KULLANAN * ZORLA_KULLANIM;
const D = [-22, 14, 13, 20];
yaz(D, "duzen", "benimseme", "kullanim", "kullanim basina is");
yaz(D, "gonullu", `%${(100 * cift / tumCift).toFixed(1)}`, KUL, (IS / KUL).toFixed(2));
yaz(D, "zorunlu", "%100.0", KUL + ekKul, ((IS + ekIs) / (KUL + ekKul)).toFixed(2));
const iyi = (100 * (tumCift / cift - 1)).toFixed(0);
const kotu = (100 * ((IS + ekIs) / (KUL + ekKul) / (IS / KUL) - 1)).toFixed(0);
const uretmez = zorlanan - ZORLA_KULLANAN;
console.log(`  zorlanan ${zorlanan} ciftin ${uretmez} tanesi kullanim uretmez`);
console.log(`  benimseme %${iyi} iyilesirken kullanim basina is %${kotu} kotulesiyor`);

const ms = Number(process.hrtime.bigint() - t0) / 1e6;   // ham olcum basilmaz, bant denetlenir
console.log(`\ndort tablo 2000 ms bandinda: ${ms < 2000 ? "evet" : "hayir"}`);
```

```
5 ekip, 8 yetenek, 3 benimseyen

1. benimseme: yetenek basina ekip ve kullanim
yetenek                    kurulum   bakim     ekip   kullanim   kullanim/is
istek uzerine ortam             34       7      4/5         60          0.68
iskelet uretimi                 22       5      5/5          5          5.40
servis katalogu                 18       6      3/5          5          4.80
politika kapisi                 27       8      5/5         72          0.49
maliyet gorunurlugu             15       4      3/5         30          0.63
goc araci                       31       3      4/5          4          8.50
gizli deger dondurme            19       5      0/5          0             -
ortak gosterge kitapligi        24       6      1/5          3         10.00
toplam                         190      44    25/40        179          1.31
  benimseme %62.5, 3.13 ekip/yetenek; en az kullanilan 2 yetenek 54 is gunu (%23)

2. dort teslimat olcutu: fark platformdan mi geliyor
olcut                      ham fark  secim yanliligi  fark-farki   yayilim   ayrilir
dagitim sikligi (hafta)        4.35             2.08        2.27      3.30     hayir
oncu sure (saat)              70.67            54.67       16.00     26.00     hayir
basarisizlik orani (%)        10.75             8.17        2.58      6.50     hayir
onarma suresi (dk)           159.17           110.00       49.17     80.00     hayir
  secim yanliligi ham farkin %48-%77'ini aciklar
  fark-farki dordunde de yayilimdan kucuk: kalan pay ayrilamiyor

3. platform bir bagimliliktir: ayni kesinti kac ekibi durduruyor
  6 kesinti 550 dk; platform kaynakli 4 kesinti (370 dk), alt katman 2 kesinti
benimseyen     dagitilmis   merkezi ekip-dk  destek istegi  kapasite asimi
1             550 ekip-dk               550             34               -
3             550 ekip-dk              1650            102             %13
5             550 ekip-dk              2750            170             %89
  gerceklesen 1440 ekip-dk (benimseme donem icinde buyudu), dagitilmisin 2.6 kati

4. benimsemeyi zorunlu kilmak olcute ne yapiyor
duzen                      benimseme     kullanim  kullanim basina is
gonullu                        %62.5          179                1.31
zorunlu                       %100.0          191                1.54
  zorlanan 15 ciftin 11 tanesi kullanim uretmez
  benimseme %60 iyilesirken kullanim basina is %18 kotulesiyor

dort tablo 2000 ms bandinda: evet
```

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

#### Benimseme Üç Sayıdır, Bir Değil

Kırk ekip-yetenek çiftinin yirmi beşi doludur (**%62,5**) ve yetenek başına 3,13 ekip düşer.
Üçüncü sütun tabloyu değiştirir: kullanım başına iş `politika kapisi` yeteneğinde 0,49 iş günü,
`ortak gosterge kitapligi` yeteneğinde **10,00 iş günü** tutar — yirmi kat fark.

İki yetenek karşılıksızdır. `gizli deger dondurme` hiç kullanılmaz: 19 iş günü kurulum, 5 iş
günü bakım, sıfır kullanım. `ortak gosterge kitapligi` tek ekibe hizmet eder. İkisi birlikte
**54 iş günü**, toplam yatırımın **%23'ü** — platformun kazandırmadığı durum burada bir sütunda
okunur: iş yapılmış ve karşılığı doğmamıştır.

#### Fark Platformdan mı Geliyor

Ham fark iki grubun benimseme sonrasındaki farkıdır ve dört ölçütte de büyüktür: haftada 4,35
dağıtım, 70,67 saat öncü süre, 10,75 puan başarısızlık oranı, 159,17 dakika onarma süresi.

İkinci sütun bu farkın ne kadarının **benimsemeden önce de var olduğunu** yazar: öncü sürede
70,67 saatlik farkın **54,67'si**, başarısızlık oranında 10,75 puanın 8,17'si. Karıştırıcı
etkenin adı **seçim yanlılığı**dır ve nedeni önceki derste ölçüldü — platforma ilk taşınan
ekipler engeli olmayanlardı, zaten daha hızlıydılar. Ham farkın **%48 ile %77'sini** açıklar.

Üçüncü sütun ikisinin farkını alır. Fark-farkı, benimsemeyen grubun aynı dönemdeki kendi
iyileşmesini de düşer — ikinci karıştırıcı etken olan **ortak eğilimi** temizler. Geriye dağıtım
sıklığında 2,27, öncü sürede 16,00 saat kalır.

Dördüncü sütun kalanı da çürütür. Benimseyen üç ekibin kendi aralarındaki yayılım dağıtım
sıklığında 3,30, öncü sürede 26,00'dır; her ölçütte fark-farkından **büyüktür** ve son sütun
dördünde de `hayır` yazar: **fark vardır ama nereden geldiği ayrılamaz.**

#### Platform Bir Bağımlılıktır

Üçüncü tablo platformun kendi ölçütünü sayar: on iki ayda altı kesinti ve 550 dakika, dördü
platform kaynaklı (370 dakika). Asıl sayı süre değil, **ekip-dakika**dır. Dağıtılmış düzende bir
arıza bir ekibi durdurur: 550 ekip-dakika. Merkezî düzende aynı 550 dakika benimseyen ekip
sayısıyla çarpılır — beş ekipte **2.750 ekip-dakika**. Gerçekleşen 1.440'tır, dağıtılmışın
**2,6 katı**.

Soyutlamanın sızdığı yer budur: tek bir katman gizlendiği için tek bir arıza beş ekibi birden
durdurur. **Platform ne kadar başarılıysa bir kesintisi o kadar pahalıdır.** Destek isteği de
kapasiteyi beş ekipte **%89** aşar.

#### Ölçütün Yanlış Yönlendirdiği Yer

Dördüncü tablo benimseme oranını hedef almanın sonucudur. Zorunlu kılınca oran %62,5'ten
%100'e çıkar; zorlanan on beş çift 60 iş günü uyum işi getirir ve **on biri hiç kullanım
üretmez**. **Ölçüt %60 iyileşirken kullanım başına iş 1,31'den 1,54'e, %18 kötüleşir** — ölçüt
hareket eder, ölçmesi gereken şey etmez.

İkinci yanlış yönlendirme ikinci tablodadır. Kolay ekipleri önce taşımak göç programı için
doğru karardır, ama aynı karar teslimat ölçütlerindeki farkın %48 ile %77'sini üretir: sıralama
bir yerde verimlilik, başka bir yerde yanlılıktır.

#### Özet

- Kırk ekip-yetenek çiftinin 25'i doludur (%62,5); kullanım başına iş 0,49 ile 10,00 iş günü
  arasında değişir ve en az kullanılan iki yetenek yatırımın %23'ünü (54 iş günü) tutar.
- Dört teslimat ölçütünde ham farkın %48-%77'si seçim yanlılığından gelir; fark-farkı ortak
  eğilimi de temizler ama dördünde de grup içi yayılımdan küçük kalır — farkın nereden geldiği
  ayrılamaz.
- Aynı 550 dakikalık kesinti dağıtılmış düzende 550, beş ekipte 2.750 ekip-dakikadır;
  gerçekleşen 1.440, dağıtılmışın 2,6 katı ve destek isteği kapasiteyi %89 aşar.
- Benimsemeyi zorunlu kılmak oranı %100'e çıkarır ve zorlanan 15 çiftin 11'i hiç kullanım
  üretmez; kullanım başına iş %18 kötüleşir.

#### Kurs Kapanışı

| Ders | Gizlenen katman | Kaç ekip, ne kadar kazanç | Sızma ya da dışına çıkma |
|---|---|---|---|
| Platform Mühendisliği Nedir | 18 kalem, 666 iş günü | eşik 7 ekip; 5'te −121 gün | artık %30,6; 9/18'de muafiyet |
| Ürün Olarak Platform | istek→ihtiyaç, 20→14 yetenek | 5 ekip, 132 iş günü | ürün ekiplerine 128 gün (%97) |
| Altın Yollar | 10 destek kalemi, üç eksen | 64 iş günü/yıl; 1/5 sığar | `saha` on kalemi de kaybeder |
| Standart ve Özerklik Dengesi | kip seçimi, 80 iş günü | karma düzen +10 iş günü | duvar 10 meşru gereksinimi tutar |
| Kendi Kendine Hizmet | talep kuyruğu, 1.551 istek | 6/12 tür, 79 iş günü | `bolge tasima` −32 iş günü |
| İstek Üzerine Ortam Sağlama | ortam kurulum adımları | 336 insan-saat; eşik 5 ekip | havuz 16/90 gün dolu; `saha` dışarıda |
| Şablon ve İskelet Üretimi | 19 karar, 3 cevaba iner | 5 servis, 95→15 cevap | sürüm 2'de 4/5 servis geride |
| Geliştirici Portalı ve Servis Kataloğu | ters kenar ve sahiplik | 32→28,8 dk; eşik 2 olay | 6/12 kayıt uyuşmaz |
| Politika ve Uyumluluk Otomasyonu | 6 kuralın metni | 5 ekip, 830→152 dk | 4 muafiyet, ömrü 3,2 kat |
| Maliyet Görünürlüğü | fatura ve muhasebe hattı | 85 br/gün; eşik 3 ekip | 408 br/gün denetim dışı |
| Göç Stratejileri | göçün 14 adımından 10'u | dalga=1'de 4 ekip, 40 adım | 1–3 ekip geride, eski düzen süresiz |
| Platform Ölçütleri | ölçüm hattının kendisi | 3 ekip, 25/40 çift (%62,5) | 1.440 ekip-dk kesinti |

On iki satırın hiçbirinde üçüncü sütun dördüncüsüz değildir. Kazanç her derste bir sayıya
bağlandı ve yanında bir bedel durdu: **soyutlama gizlediği katmanı ortadan kaldırmaz** —
kazancını ekip sayısıyla çarpar, bedelini sızma ve dışına çıkmayla ödetir. Eşik üç derste
açıkça çıktı (7, 5 ve 3 ekip) ve üçünde de altında kalmak platformu zararlı yaptı.

| Kurs | Ölçü ekseni | Ölçü birimi |
|---|---|---|
| K01 DevOps Kültürü ve Temelleri | fark nerede saklı | fark kalemi |
| K02 Konteynerler | yalıtım bir bütçedir | bayt, katman, kaynak |
| K03 Konteyner Orkestrasyonu | kararı devretmenin bedeli | bilgi kalemi |
| K04 Sürekli Tümleştirme ve Teslimat | her kapı neyi tutar, neyi kaçırır | marjinal kapı değeri |
| K05 Kod Olarak Altyapı | kayıt ile gerçek arasındaki fark | kayıt kalemi |
| K06 Gözlemlenebilirlik ve İşletim | veri değil, soru | soru başına maliyet |
| K07 Sunucu, Ağ ve Sertleştirme | varsayılanın kendisi | açık yüzey kalemi |
| K08 Platform Mühendisliği | soyutlamanın bedeli | gizlenen katman |

Sekiz kurs sekiz ayrı konu anlattı ama tek bir biçimde ölçtü. Fark kalemi de, açık yüzey kalemi
de, gizlenen katman da aynı üç şeyi soruyordu: **bir karar, bir sayı ve o sayının karşılığında
ödenen bedel.** K02'de yalıtımın bedeli baytla, K04'te bir kapının değeri yakaladığı ihlalle,
K08'de soyutlamanın değeri kurtardığı ekip sayısıyla ölçüldü. Hiçbirinde "iyidir" tek başına
karar taşımadı.

Ölçmenin kendisi de bedelsiz değildi: K06 ölçen tarafın faturada ayrı bir kalem olduğunu saydı; K08
ölçüm yatırımının %23'ünün karşılıksız kaldığını gösterdi. **Ölçülemeyeni ölçülmüş gibi yazmamak da bir
ölçüm kararıdır** — ve bu müfredatın son satırı odur.

