---
title: 'Süreç, Ekip ve Teslimat'
source: 'https://academia.sh/tr/kurslar/surec-ve-ekip'
language: tr
updated: '2026-08-17T04:42:32+00:00'
license: 'CC BY-SA 4.0'
lessons: 10
outcomes:
    - 'Süreç modellerini bağlamına göre karşılaştırır'
    - 'Ekip yapısının mimariye etkisini ölçer'
    - 'Teslimat sürecini değişiklik ve devir sözleşmesiyle kurar'
---

# Süreç, Ekip ve Teslimat

Mimariyi biçimlendiren insan yapısı: yaşam döngüsü modellerinin geri bildirim gecikmesiyle karşılaştırılması, yinelemeli teslimatın çerçeveleri, iş sınırlama ve akış ölçütleri, çok ekipli eşgüdümün bedeli, sürekli tümleştirme ve eşli çalışma gibi mühendislik pratikleri, iletişim yapısının mimariye yansıması, akış odaklı ekip düzenleri, belirsizlik altında tahmin, kapsam değişiminin denetimi ve geliştirme ile işletim arasındaki sorumluluk sözleşmesi.

## Süreç Modelleri

İşin akış biçiminin seçilmesi: şelale, V, spiral ve artımlı yaşam döngülerinin geri bildirim gecikmesi ve yeniden iş cinsinden karşılaştırılması, yinelemeli teslimat çerçevelerinin ortak yapısı, iş sınırlamanın akış süresine etkisi, çok ekipli eşgüdümün eşgüdüm turu bedeli ve sürekli tümleştirme ile eşli çalışmanın hata bulma gecikmesine etkisi.

### Yaşam Döngüsü Modelleri

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/yasam-dongusu-modelleri

Şelale, V, spiral ve artımlı yaşam döngülerinin aynı on sekiz iş kalemi üzerinde koşturulması: el değiştirme, kapıda bekleme, geri bildirim gecikmesi ve yeniden iş sayılır, her modelin kazandığı yerde neyi kaybettiği yazılır.

Önceki kurs mimari kuralı bir nesneye çevirdi: kural yazıldı, denetime dönüştürüldü, yakaladığı ve
kaçırdığı sayıldı. O ölçümlerin tamamı bir şeyi sessizce dışarıda bıraktı. Kuralı yazan, denetimi
koşturan, yanlış alarm karşısında kuralı devre dışı bırakan ve bir sonraki değişikliği yapan
**insanlardır**; bu kişilerin hangi sırayla çalıştığı, işi kime devrettiği ve bir hatayı ne zaman
öğrendiği mimariye doğrudan yazılır.

Bu kursun ölçü birimi **iş kalemi**dir: bir değişiklik isteğinin doğduğu andan işletime geçtiği ana
kadarki yol. Her ders üçünü sayar — kalemin kaç sınır geçtiği ve her geçişte kaç tur beklediği, kaç
kalemin geri döndüğü ve neden, ekip sınırı ile modül sınırının örtüşmediği yerde bunların ne kadar
büyüdüğü. Through-line **bölgesel kütüphane ağıdır**: şube sistemleri, dışarıdan alınmış katalog,
içeride yazılmış ödünç ve ücretlendirme servisleri, ayrı bir üyelik sistemi ve belediyedeki kimlik
servisi. Kurgudur.

#### Ölçülecek İş Kalemi Kümesi

Aşağıdaki blok bir **modeldir**, ölçüm değil: aynı iş kalemi kümesini dört yaşam döngüsünde
koşturulabilir hâle getiren bir veri yapısıdır.

**SM1 — on sekiz iş kalemi beş adımdan geçer ve tek bir ekip çalışır.** Her kalem her adımda 3 iş
birimi tüketir, ekip tur başına 9 iş birimi işler. Gerekçe: modeller ancak aynı iş yükü ve aynı
kapasite altında karşılaştırılabilir; farkı yaratan şey işin miktarı değil, **partileme** olmalıdır.

**SM2 — on kalemde bir kusur doğar, doğduğu adım ile türü girdi olarak bilinmektedir.** Türler
ayrılır: **eksik bilgi** (bir ayrıntı hiç sorulmamıştır), **yanlış sınır** (iki kalem aynı veriyi
farklı yerde tutar, hata ancak ikincisi yazılınca görünür), **geç öğrenilen kısıt** (kısıt yalnız
işletimde çıkar). Geri bildirim gecikmesi ancak bilinen bir kusur kümesine karşı sayılabilir.

**SM3 — partileme kuralı modelin kendisidir.** Şelale ve V tek parti koşar, spiral risk sırasına
göre üç döngüye, artımlı bağımlılık sırasına göre altı artıma böler.

**SM4 — kusurun bulunduğu adım modele göre değişir.** Eksik bilgi ile yanlış sınır sınamada, geç
öğrenilen kısıt işletimde görünür. V modelinde sınama tasarımı üretim adımıyla birlikte yapıldığı
için eksik bilgi **doğduğu adımda** göze çarpar. Bir kısıt işletimde öğrenildikten sonra **sonraki
partilerde** aynı kısıtı taşıyan kalem kusurlu doğmaz; aynı partidekiler çoktan yazılmıştır.

**SM5 — sabit maliyetler modele bağlıdır.** V modelinde ilk üç adım kalem başına 1 iş birimi daha
tüketir. Her partinin işletime alınması, kalem sayısından bağımsız 6 iş birimi tutar.

```js
// yasam-dongusu.mjs — ayni 18 is kalemini dort yasam dongusunde kosturur (model)
// kusur kodu: e eksik bilgi, s yanlis sinir, k gec ogrenilen kisit; rakam kusurun dogdugu adim
import { writeFileSync } from "node:fs";

const ADIM = ["cozumleme", "tasarim", "gerceklestirme", "sinama", "isletim"];
const BIRIM = 3;      // bir is kaleminin bir adimda tukettigi is birimi
const KAPASITE = 9;   // tur basina is birimi (tek ekip)
const YAYIM = 6;      // her partinin isletime alma yuku, kalem sayisindan bagimsiz

const KALEM = [
  "uye dogrulama ucu    |uyelik |2|e0",
  "katalog arama ucu    |katalog|1|-",
  "odunc kaydi olusturma|odunc  |2|s1 S1",
  "raf durumu sorgusu   |katalog|0|-",
  "gecikme ucreti hesabi|ucret  |2|k0 K1",
  "sube stok devri      |sube   |1|e2",
  "uyelik dondurma      |uyelik |1|s1 S1",
  "ceza bildirimi       |ucret  |0|-",
  "sube raf etiketi     |sube   |0|-",
  "ayirtma kuyrugu      |odunc  |2|s1 S2",
  "kimlik eslestirme    |uyelik |2|k0 K1",
  "katalog ice aktarma  |katalog|1|-",
  "ucret iadesi         |ucret  |1|e2",
  "subeler arasi tasima |sube   |2|s1 S2",
  "odunc uzatma         |odunc  |0|-",
  "gecikme raporu       |ucret  |0|-",
  "uye bildirimi        |uyelik |0|k0 K2",
  "sube gunluk kapanis  |sube   |1|-",
].map((satir, i) => {
  const [ad, birim, risk, kusur] = satir.split("|").map((x) => x.trim());
  const [kod, anahtar = null] = kusur.split(" ");
  const TUR = { e: "eksik bilgi", s: "yanlis sinir", k: "gec kisit" };
  return { ad, birim, risk: +risk, artim: (i / 3) | 0, anahtar,
           tur: kod === "-" ? null : TUR[kod[0]], dogum: kod === "-" ? -1 : +kod[1] };
});

// SM3: partileme kurali modelin kendisidir; selale ve V tek parti, spiral risk sirali uc dongu,
// artimli bagimlilik sirali alti artim.
const riskli = [...KALEM].sort((a, b) => b.risk - a.risk);
const PARTI = {
  selale:  [KALEM],
  V:       [KALEM],
  spiral:  [0, 1, 2].map((c) => riskli.slice(c * 6, c * 6 + 6)),
  artimli: [0, 1, 2, 3, 4, 5].map((a) => KALEM.filter((k) => k.artim === a)),
};
const maliyet = (model, k, s) => (k.yayim ? YAYIM : BIRIM + (model === "V" && s <= 2 ? 1 : 0));
// V'de sinama tasarimi uretim adimiyla birlikte yapilir: eksik bilgi dogdugu adimda goze carpar.
const bulusAdimi = (model, k) =>
  (model === "V" && k.tur === "eksik bilgi") ? k.dogum : (k.tur === "gec kisit" ? 4 : 3);

function kostur(model) {
  const partiler = PARTI[model];
  const durum = new Map(KALEM.map((k) => [k.ad, { adimBitis: new Map(), parti: 0 }]));
  partiler.forEach((p, i) => p.forEach((k) => { durum.get(k.ad).parti = i; }));
  const ogrenilen = new Set(), cozulen = new Set(), bulgu = [];
  let tur = 0, bekleme = 0, elDegistirme = 0, yeniden = 0, toplam = 0;

  const segment = (liste, birimBasi) => {                 // her segment yeni bir turda baslar
    tur += 1;
    let kap = KAPASITE;
    const bitis = new Map();
    for (const k of liste) {
      let kalan = birimBasi(k);
      toplam += kalan;
      while (kalan > 0) {
        if (kap === 0) { tur += 1; kap = KAPASITE; }
        const al = Math.min(kap, kalan); kap -= al; kalan -= al;
      }
      bitis.set(k.ad, tur);
    }
    return bitis;
  };

  partiler.forEach((parti, p) => {
    for (let s = 0; s < ADIM.length; s++) {
      const liste = s === 4 ? [...parti, { ad: "__yayim", yayim: true }] : parti;
      const bitis = segment(liste, (k) => maliyet(model, k, s));
      for (const k of parti) {
        bekleme += tur - bitis.get(k.ad);
        durum.get(k.ad).adimBitis.set(s, bitis.get(k.ad));
      }
      elDegistirme += parti.length;

      const bulunan = KALEM.filter((k) => {               // bu adimda ortaya cikan kusurlar
        if (k.dogum < 0) return false;
        if (k.tur === "eksik bilgi") return parti.includes(k) && s === bulusAdimi(model, k);
        if (k.tur === "gec kisit") return s === 4 && parti.includes(k) && !ogrenilen.has(k.anahtar);
        const grup = KALEM.filter((x) => x.anahtar === k.anahtar);   // yanlis sinir: es kalem
        return s === 3 && !cozulen.has(k.anahtar) &&
          grup.every((x) => durum.get(x.ad).parti <= p) && grup.some((x) => durum.get(x.ad).parti === p);
      });
      for (const k of bulunan) {
        const adimlar = [...Array(s - k.dogum + 1)].map((_, i) => k.dogum + i);
        const bedel = adimlar.reduce((a, x) => a + maliyet(model, k, x), 0);
        const bulusTur = s === k.dogum ? bitis.get(k.ad) : tur;   // ayni adimda bulundu ise kapida degil
        bulgu.push({ model, kalem: k.ad, tur: k.tur, dogum: k.dogum, bulus: s, bedel,
          gecikmeAdim: (p - durum.get(k.ad).parti) * ADIM.length + s - k.dogum,
          gecikmeTur: bulusTur - durum.get(k.ad).adimBitis.get(k.dogum),
          ustune: KALEM.filter((x) => durum.get(x.ad).adimBitis.get(k.dogum) <= bulusTur).length });
        yeniden += bedel;
        elDegistirme += adimlar.length;
        if (k.tur === "yanlis sinir") cozulen.add(k.anahtar);
      }
      if (bulunan.length) segment(bulunan, (k) =>
        [...Array(s - k.dogum + 1)].reduce((a, _, i) => a + maliyet(model, k, k.dogum + i), 0));
      if (s === 4) for (const k of parti) if (k.tur === "gec kisit") ogrenilen.add(k.anahtar);
    }
  });
  return { model, tur, bekleme, elDegistirme, yeniden, toplam, bulgu };
}

const SONUC = ["selale", "V", "spiral", "artimli"].map(kostur);
writeFileSync("bulgu.json", JSON.stringify(SONUC.flatMap((s) => s.bulgu)));

const TUR3 = ["eksik bilgi", "yanlis sinir", "gec kisit"];
const tablo = (basliklar, satirlar, ust) => {             // negatif genislik sola yaslar
  const yaz = (h) => console.log(h.map((c, i) =>
    basliklar[i][1] < 0 ? String(c).padEnd(-basliklar[i][1]) : String(c).padStart(basliklar[i][1])).join(""));
  console.log();
  if (ust) console.log(ust);
  yaz(basliklar.map((b) => b[0]));
  satirlar.forEach(yaz);
};
const ort = (g, f) => (g.length ? (g.reduce((a, b) => a + f(b), 0) / g.length) : null);

console.log(`is kalemi: ${KALEM.length}, adim: ${ADIM.length}, kusurlu kalem: ` +
  `${KALEM.filter((k) => k.dogum >= 0).length} ` +
  `(${TUR3.map((t) => `${KALEM.filter((k) => k.tur === t).length} ${t}`).join(", ")})`);

tablo([["model", -9], ["parti", 7], ["tur", 6], ["bekleme", 9], ["el degistirme", 15], ["toplam is birimi", 18]],
  SONUC.map((s) => [s.model, PARTI[s.model].length, s.tur, s.bekleme, s.elDegistirme, s.toplam]));

tablo([["model", -9], ["bulunan kusur", 14], ["ort. gecikme (adim)", 21], ["ort. gecikme (tur)", 20],
       ["ort. ustune kurulan", 21], ["yeniden is", 12]],
  SONUC.map((s) => [s.model, s.bulgu.length, ort(s.bulgu, (b) => b.gecikmeAdim).toFixed(2),
    ort(s.bulgu, (b) => b.gecikmeTur).toFixed(2), ort(s.bulgu, (b) => b.ustune).toFixed(2), s.yeniden]));

tablo([["model", -9], ["eksik bilgi", 13], ["yanlis sinir", 14], ["gec kisit", 11]],
  SONUC.map((s) => [s.model, ...TUR3.map((t) => {
    const o = ort(s.bulgu.filter((b) => b.tur === t), (b) => b.gecikmeTur);
    return o === null ? "-" : o.toFixed(1);
  })]), "kusur turune gore ortalama gecikme (tur):");
```

```
is kalemi: 18, adim: 5, kusurlu kalem: 10 (3 eksik bilgi, 4 yanlis sinir, 3 gec kisit)

model      parti   tur  bekleme  el degistirme  toplam is birimi
selale         1    43      243            125               381
V              1    50      288            120               440
spiral         3    47       63            125               393
artimli        6    48       18            120               396

model     bulunan kusur  ort. gecikme (adim)  ort. gecikme (tur)  ort. ustune kurulan  yeniden is
selale               10                 2.50               20.10                18.00         105
V                    10                 2.00               19.00                14.70         110
spiral               10                 3.00                8.50                 9.60         105
artimli               9                 4.00                5.22                10.67          90

kusur turune gore ortalama gecikme (tur):
model      eksik bilgi  yanlis sinir  gec kisit
selale            13.3          14.8       34.0
V                  0.0          18.5       38.7
spiral             4.0           9.3       12.0
artimli            1.7           7.8        5.5
```

#### Dört Modelin Okunması

İlk tablo akışı, ikincisi öğrenmeyi ölçer ve ikisi ters yönde hareket eder.

**Şelale** en az turda biter (43) çünkü sabit yükü bir kez öder. Bedeli ikinci sütundadır: **243 tur
bekleme** birikir, çünkü kalem kendi adımını bitirince partinin son kalemini bekler ve her kapıda
yeniden bekler. Öğrenme tarafı daha serttir — gecikme **20,1 tur** ve bir kusur bulunduğunda **on
sekiz kalemin on sekizi** o yanlış varsayımın üstündedir. Geç öğrenilen kısıtta gecikme 34 tura
çıkar, çünkü işletime alma sonda tek seferdir.

**V modeli** tek bir kusur türünde kesin kazanç sağlar: eksik bilginin gecikmesi **13,3 turdan 0
tura** iner, soru cevabın gerekli olduğu adımda sorulur. Bedeli iki yerdedir. Toplam iş gücü
381'den **440 birime** çıkar (270 temel iş, 54 birim sınama tasarımı eki, 6 birim yayım, 110 birim
yeniden iş) ve akış 50 tura uzar. Diğer iki türde ise V hiçbir şey yapmaz — yanlış sınır 14,8'den
18,5 tura, geç öğrenilen kısıt 34'ten 38,7 tura **çıkar**, çünkü koşumun tamamı uzamıştır.

**Spiral** partiyi risk sırasına böler; en riskli altı kalem ilk döngüde işletime kadar gittiği için
geç öğrenilen kısıt 34 turdan **12 tura**, ortalama gecikme 8,5 tura, bekleme 63'e iner. Bedeli üç
kez ödenen yayım yükü (18 birim) ve kaçırılan bir öğrenmedir: risk sırası aynı kısıtı taşıyan iki
kalemi (`gecikme ucreti hesabi` ve `kimlik eslestirme`) **aynı döngüye** koyduğu için kısıt ikisi de
yazıldıktan sonra öğrenilir ve ikisi de yeniden işe girer.

**Artımlı** model bağımlılık sırasına göre altı artıma böler. Bekleme 18 tura, gecikme 5,22 tura
iner ve **bulunan kusur ona değil dokuza** düşer: birinci artımda öğrenilen kısıt üçüncü artımdaki
eş kalemi kusursuz doğurur, yeniden iş 90 birime iner. Bedeli turlardadır — altı yayım yükü akışı
dört modelin en uzunu olan 48 tura çıkarır — ve **adım cinsinden gecikme en yüksek burada**dır
(4,00): artım sınırını kesen yanlış sınır ancak ikinci artımda görünür, birincinin teslim edilmiş
kalemi geri açılır.

#### Gecikme Yeniden İşe Nasıl Dönüşür

**SM6 — yeniden işin bedeli iki çarpandan gelir:** yeniden yapılan adım sayısı ve aynı varsayımın
üstüne kurulmuş kalem sayısı. Aşağıdaki blok dört koşumun otuz dokuz bulgusunu tek havuzda toplar
ve bu iki çarpanı gecikmeye karşı ayırır.

```js
// gecikme.mjs — yasam-dongusu.mjs'in yazdigi bulgulari okur; gecikme ile yeniden is baginti
import { readFileSync } from "node:fs";

const BULGU = JSON.parse(readFileSync("bulgu.json", "utf8"));
const KOVA = [[0, 0], [1, 5], [6, 12], [13, 24], [25, 99]];

console.log(`dort modelde toplam ${BULGU.length} kusur bulgusu; kova = geri bildirim gecikmesi (tur)\n`);
console.log(`${"gecikme".padStart(9)}${"bulgu".padStart(7)}${"ort. yeniden is (birim)".padStart(25)}` +
  `${"ort. yeniden adim".padStart(19)}${"ort. ustune kurulan kalem".padStart(27)}`);
for (const [a, b] of KOVA) {
  const g = BULGU.filter((x) => x.gecikmeTur >= a && x.gecikmeTur <= b);
  if (!g.length) continue;
  const o = (f) => (g.reduce((s, x) => s + f(x), 0) / g.length).toFixed(1);
  console.log(`${(a === b ? `${a}` : `${a}-${b}`).padStart(9)}${String(g.length).padStart(7)}` +
    `${o((x) => x.bedel).padStart(25)}${o((x) => x.bulus - x.dogum + 1).padStart(19)}` +
    `${o((x) => x.ustune).padStart(27)}`);
}

// SM6: yeniden isin bedeli iki carpandan gelir; yeniden yapilan adim sayisi ve ayni varsayimin
// ustune kurulmus kalem sayisi. Ikisi de gecikmeyle birlikte buyur.
const ADI = (i) => ["cozumleme", "tasarim", "gerceklestirme", "sinama", "isletim"][i];
const kume = (g, f) => [...new Set(g.map(f))].join(" ve ");
const pahali = [...BULGU].sort((a, b) => b.bedel - a.bedel).slice(0, 5);
console.log(`\nen pahali bes bulgu: tur ${kume(pahali, (x) => x.tur)}, ` +
  `dogum ${kume(pahali, (x) => ADI(x.dogum))}, bulus ${kume(pahali, (x) => ADI(x.bulus))}, ` +
  `ort. ${(pahali.reduce((a, x) => a + x.bedel, 0) / 5).toFixed(1)} birim yeniden is`);
```

```
dort modelde toplam 39 kusur bulgusu; kova = geri bildirim gecikmesi (tur)

  gecikme  bulgu  ort. yeniden is (birim)  ort. yeniden adim  ort. ustune kurulan kalem
        0      3                      4.0                1.0                        7.0
      1-5     11                      8.7                2.9                       10.4
     6-12      6                     10.5                3.5                       13.5
    13-24     13                     10.8                3.4                       15.0
    25-99      6                     16.5                5.0                       18.0

en pahali bes bulgu: tur gec kisit, dogum cozumleme, bulus isletim, ort. 16.8 birim yeniden is
```

Kovalar tek yönde ilerler: gecikme sıfırken yeniden iş 4 birim, yirmi beş turun üstünde 16,5
birimdir. Aradaki fark iki çarpandan gelir. Yeniden yapılan adım 1,0'dan 5,0'a çıkar, çünkü geç
bulunan kusur daha çok adımı geçersiz kılar; aynı varsayımın üstüne kurulmuş kalem 7,0'dan 18,0'a
çıkar, çünkü bu arada kusurun etrafında iş birikmiştir. En pahalı beş bulgunun beşi de aynı
türdendir — çözümlemede doğup işletimde bulunan geç öğrenilen kısıt.

Temel iş dört modelde de 270 birimdir; farkı sabit yük ile yeniden iş yaratır. Bir modelin "daha
iyi" olduğunu söyleyen tek bir sayı yoktur: geç öğrenilen kısıt ağır basıyorsa küçük parti, eksik
bilgi ağır basıyorsa erken doğrulama, sabit yayım maliyeti yüksekse büyük parti kazanır.

#### Özet

- Aynı 18 iş kalemi dört yaşam döngüsünde koşturuldu; 270 birimlik temel iş sabit tutuldu, farkı
  yalnız partileme kuralı ile sabit yük yarattı.
- Şelale en kısa akışı verir (43 tur) ama 243 tur bekleme biriktirir, gecikmeyi 20,1 tura çıkarır
  ve her kusurda 18 kalemin tamamı yanlış varsayımın üstündedir.
- V modeli eksik bilgi gecikmesini 13,3 turdan 0'a indirir; karşılığında toplam iş gücü 381'den
  440 birime çıkar ve diğer iki kusur türünde gecikme artar.
- Spiral gecikmeyi 8,5 tura indirir ama aynı kısıtın iki kalemini aynı döngüye koyup partiler arası
  öğrenmeyi kaçırır; artımlı beklemeyi 18 tura, yeniden işi 90 birime indirir ve bir kusuru hiç
  doğurmaz, bedeli 48 turluk en uzun akıştır.
- Havuzlanmış 39 bulguda gecikme 25 turun üstüne çıktığında yeniden iş 4 birimden 16,5 birime
  yükselir; yeniden yapılan adım 1,0'dan 5,0'a, üstüne kurulmuş kalem 7,0'dan 18,0'a çıkar.

#### Sonraki Adım

Bu dersin en güçlü tek değişkeni parti büyüklüğüydü: on sekiz kalemlik tek parti ile üç kalemlik
altı parti arasındaki fark beklemeyi on üç kat, geri bildirim gecikmesini dört kat değiştirdi.
Fakat parti büyüklüğü burada elle seçildi — altı artımın neden altı olduğu hiçbir yerde ölçülmedi.
Sonraki ders yinelemeli teslimatın çerçevelerini ortak yapısıyla ele alır ve asıl değişkeni tarar:
yineleme uzunluğu bir haftadan dört haftaya çıkarıldığında akış süresi, yeniden iş ve **törene
giden süre** nasıl değişir. Kısa yineleme gecikmeyi düşürür, ama her yinelemenin planlama ve gözden
geçirme yükü sabittir ve yinelemeye sığmayan kalem yarım kalıp sonrakine devrolur. İki maliyet
ters yönde büyüdüğü için taramadan tek bir en iyi uzunluk çıkmaz.

### Çevik Çerçeveler

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/cevik-cerceveler

Yinelemeli teslimat çerçevelerinin ortak yapısı ve yineleme uzunluğunun taranması: bir haftadan altı haftaya kadar her uzunlukta akış süresi, geri bildirim gecikmesi, yeniden iş, törene giden süre ve yarım kalan iş kalemi sayılır.

Önceki ders parti büyüklüğünün ne kadar güçlü bir değişken olduğunu gösterdi: on sekiz kalemlik tek
parti ile üç kalemlik altı parti arasında bekleme on üç kat, geri bildirim gecikmesi dört kat
değişti. Ama o partiler elle seçilmişti. Yinelemeli teslimat çerçeveleri tam olarak bu seçimi
kurumsallaştırır — parti büyüklüğünü sabit bir **süreye** bağlarlar ve o süreyi bir ritim hâline
getirirler.

Bu ders çerçeveleri **ortak yapısıyla** ele alır, çünkü ölçülebilir olan yapıdır: bir **biriktirme
listesi**, sabit uzunlukta bir **yineleme**, yinelemenin başında bir planlama ve sonunda bir
**gözden geçirme töreni** ve işi yapan ile kabul edeni ayıran bir **rol ayrımı**. Bu dört öge
seçildiğinde geri kalan sayılar kendiliğinden çıkar. Through-line **bölgesel kütüphane ağıdır** ve
kurgudur; bu derste ağın ödünç, ücretlendirme, üyelik ve şube servislerine gelen değişiklik
istekleri tek bir biriktirme listesinde toplanır.

#### Ortak İskelet

Aşağıdaki blok bir **modeldir**, ölçüm değil. Bir çerçevenin adını değil, iskeletini koşturur.

**SM7 — otuz iş kalemi bir üreteçle türetilir, üreteç kendi yazılır ve tohum görünürdür.** Aynı
kalem kümesi bütün yineleme uzunluklarında kullanılır; uzunluklar arası fark yalnız ritimden gelir.
Her kalemin bir boyutu (2–8 adam-gün), bir geliş günü ve aynı veriye dokunduğu önceki kalemler
vardır.

**SM8 — ekip dört kişidir, günde 4 adam-gün iş çıkarır.** Yineleme başına tören maliyeti
`4 + L` adam-gündür: sabit bir planlama ve değerlendirme yükü artı yineleme uzunluğuyla büyüyen bir
gözden geçirme payı. Bu, kısa yinelemenin bedelini taşıyan tek sayıdır.

**SM9 — kabul yalnızca gözden geçirme töreninde verilir.** Rol ayrımının ölçülebilir sonucu budur:
işi yapan ile kabul eden farklı kişilerdir ve kabul eden yalnız törende masadadır. Bir kalem
yinelemenin ilk günü bittiğinde bile kabulünü yinelemenin son günü alır.

**SM10 — kusur o kabul anında görünür.** Yeniden işin boyutu kalemin üçte biri artı, kusurlu kalem
bittikten sonra aynı yinelemede tamamlanmış ve ona dokunan her kalem için 1 adam-gündür. Uzun
yinelemede kusurlu kalemden sonra daha çok kalem tamamlandığı için bu ek büyür.

**SM11 — yinelemeye sığmayan kalem yarım kalır** ve sonraki yinelemede 1 adam-günlük bir geçiş
maliyeti öder. Kısa yinelemenin ikinci bedeli budur.

```js
// cevik.mjs — yinelemeli teslimatin ortak iskeleti (model); tek uzunlukta ayrintili kosum
import { writeFileSync } from "node:fs";

const KISI = 4;        // ekip; gunde KISI adam-gun is cikar
const GECIS = 1;       // yarim kalan kalemin sonraki yinelemede odedigi geri donus maliyeti
const toren = (L) => 4 + L;                 // planlama + gozden gecirme + degerlendirme (adam-gun)

// SM7: uretec kendi yazilir, tohum gorunur; kalem kumesi butun yineleme uzunluklarinda aynidir.
let tohum = 20250401;
const rast = () => (tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648;
const KALEM = [...Array(30)].map((_, no) => ({
  no, boyut: 2 + Math.floor(rast() * 7), gelis: Math.floor(rast() * 40),
  kusur: rast() < 0.35, bagli: [],
}));
for (const k of KALEM)                      // ayni veriye dokunan onceki kalemler
  for (const o of KALEM) if (o.no < k.no && rast() < 0.18) k.bagli.push(o.no);

function kostur(L) {
  const gun = 5 * L, net = KISI * gun - toren(L);
  const havuz = KALEM.map((k) => ({ ...k, kalan: k.boyut, tamam: -1, baslandi: false, yeniden: false }));
  const kayit = [], gecikmeler = [];
  let n = 0, yarim = 0, gecis = 0, torenToplam = 0, yeniden = 0;

  while (havuz.some((k) => k.tamam < 0)) {
    const bas = n * gun, bit = bas + gun - 1;          // gozden gecirme toreni son gunde
    torenToplam += toren(L);
    let kap = net, harcanan = 0;
    const aday = havuz.filter((k) => k.tamam < 0 && k.gelis <= bas)
      .sort((a, b) => (b.baslandi - a.baslandi) || (a.gelis - b.gelis) || (a.no - b.no));
    const biten = [];
    let calisilan = 0, buYarim = 0;
    for (const k of aday) {                              // planlamada kapasite kadari cekilir
      const ek = k.baslandi ? GECIS : 0;
      if (kap <= ek) break;
      if (ek) { kap -= ek; harcanan += ek; gecis += ek; }
      k.baslandi = true; calisilan += 1;
      const al = Math.min(kap, k.kalan);
      k.kalan -= al; kap -= al; harcanan += al;
      if (k.kalan === 0) { k.tamam = bas + Math.min(gun - 1, Math.floor(harcanan / KISI)); biten.push(k); }
      else { yarim += 1; buYarim += 1; }
    }
    // SM10: kabul yalnizca gozden gecirme toreninde verilir; kusur o gun gorunur.
    let bulunan = 0;
    for (const k of biten) {
      if (!k.kusur || k.yeniden) continue;
      const dokunan = biten.filter((x) => x.bagli.includes(k.no) && x.tamam >= k.tamam).length;
      const boy = Math.ceil(k.boyut / 3) + dokunan;
      havuz.push({ no: 100 + k.no, boyut: boy, kalan: boy, gelis: bit + 1, tamam: -1,
                   baslandi: false, kusur: false, yeniden: true, bagli: [] });
      yeniden += boy; bulunan += 1;
      gecikmeler.push(bit - k.tamam);
    }
    kayit.push({ n: n + 1, bas, bit, cekilen: calisilan, biten: biten.length,
                 yarim: buYarim, bekleyen: aday.length - calisilan, bulunan });
    n += 1;
  }
  const asil = havuz.filter((k) => !k.yeniden);
  const ort = (a) => a.reduce((x, y) => x + y, 0) / a.length;
  const temel = KALEM.reduce((a, k) => a + k.boyut, 0);
  return { L, yineleme: n, gun: Math.max(...havuz.map((k) => k.tamam)) + 1,
    akis: ort(asil.map((k) => k.tamam - k.gelis + 1)), gecikme: ort(gecikmeler),
    kusurlu: gecikmeler.length, yeniden, yarim, gecis, toren: torenToplam,
    temel, toplam: temel + yeniden + gecis + torenToplam, kayit };
}

const TARAMA = [1, 2, 3, 4, 6].map(kostur);
writeFileSync("tarama.json", JSON.stringify(TARAMA.map(({ kayit, ...r }) => r)));

console.log(`is kalemi: ${KALEM.length}, temel is: ${KALEM.reduce((a, k) => a + k.boyut, 0)} adam-gun, ` +
  `kusurlu kalem: ${KALEM.filter((k) => k.kusur).length}, ` +
  `bagimlilik bagi: ${KALEM.reduce((a, k) => a + k.bagli.length, 0)} (tohum ${20250401})`);

const iki = TARAMA[1];
console.log(`\niki haftalik yineleme, ayrintili kosum (toren ${toren(2)} adam-gun, ` +
  `net kapasite ${KISI * 10 - toren(2)} adam-gun):`);
console.log(`${"yineleme".padStart(9)}${"is gunu".padStart(9)}${"cekilen".padStart(9)}` +
  `${"biten".padStart(7)}${"yarim kalan".padStart(13)}${"listede kalan".padStart(15)}` +
  `${"bulunan kusur".padStart(15)}`);
for (const r of iki.kayit)
  console.log(`${String(r.n).padStart(9)}${`${r.bas}-${r.bit}`.padStart(9)}` +
    `${String(r.cekilen).padStart(9)}${String(r.biten).padStart(7)}` +
    `${String(r.yarim).padStart(13)}${String(r.bekleyen).padStart(15)}` +
    `${String(r.bulunan).padStart(15)}`);
console.log(`toplam ${iki.gun} is gunu, ${iki.yineleme} yineleme; ` +
  `${iki.kusurlu} kusur ortalama ${iki.gecikme.toFixed(1)} is gunu gecikmeyle bulundu`);
```

```
is kalemi: 30, temel is: 152 adam-gun, kusurlu kalem: 8, bagimlilik bagi: 75 (tohum 20250401)

iki haftalik yineleme, ayrintili kosum (toren 6 adam-gun, net kapasite 34 adam-gun):
 yineleme  is gunu  cekilen  biten  yarim kalan  listede kalan  bulunan kusur
        1      0-9        1      1            0              0              0
        2    10-19        8      8            0              5              1
        3    20-29        8      7            1              3              2
        4    30-39        7      6            1              3              1
        5    40-49        8      8            0              4              2
        6    50-59        6      6            0              0              2
        7    60-69        2      2            0              0              0
toplam 62 is gunu, 7 yineleme; 8 kusur ortalama 5.5 is gunu gecikmeyle bulundu
```

İki haftalık ritimde ilk yineleme neredeyse boştur: sıfırıncı gün biriktirme listesinde yalnız
bir kalem vardır, sonradan gelenler bir sonraki planlamayı bekler. Üçüncü yinelemeden itibaren
listede kalan üç ile dört arasında bir kuyruk oluşur; üçüncü ve dördüncü yinelemede birer kalem
yarım kalır, beşinciden sonra kuyruk erir. Sekiz kusurun tamamı gözden geçirme törenlerinde
bulunur ve ortalama 5,5 iş günü bekledikten sonra görünür.

#### Yineleme Uzunluğunun Taranması

Ritim tek başına bir değer değil, bir ayardır. Aşağıdaki blok aynı otuz kalemi bir, iki, üç, dört ve
altı haftalık yinelemelerde koşturur.

**SM12 — iki maliyet ters yönde büyür.** Kısa yineleme gecikmeyi ve yarım kalan kalemin süresini
düşürür ama tören payını yükseltir; uzun yineleme tören payını düşürür ama kalemi hem başlamak için
hem kabul için bekletir.

```js
// tarama.mjs — cevik.mjs'in yazdigi tarama sonucunu okur; yineleme uzunlugu taranir
import { readFileSync } from "node:fs";

const T = JSON.parse(readFileSync("tarama.json", "utf8"));
const tablo = (baslik, satir, ust) => {
  const yaz = (h) => console.log(h.map((c, i) => String(c).padStart(baslik[i][1])).join(""));
  console.log(); console.log(ust); yaz(baslik.map((b) => b[0])); satir.forEach(yaz);
};

tablo([["uzunluk", 8], ["yineleme", 10], ["is gunu", 9], ["ort. akis suresi", 18],
       ["ort. gecikme", 14], ["yeniden is", 12], ["yarim kalan", 13]],
  T.map((r) => [`${r.L} hafta`, r.yineleme, r.gun, r.akis.toFixed(1), r.gecikme.toFixed(1),
                r.yeniden, r.yarim]),
  "yineleme uzunlugu taramasi (akis suresi ve gecikme is gunu):");

tablo([["uzunluk", 8], ["temel is", 10], ["toren", 8], ["gecis", 7], ["yeniden is", 12],
       ["toplam", 9], ["toren payi", 12]],
  T.map((r) => [`${r.L} hafta`, r.temel, r.toren, r.gecis, r.yeniden, r.toplam,
                `%${((100 * r.toren) / r.toplam).toFixed(1)}`]),
  "is gucunun dagilimi (adam-gun):");

// SM12: iki maliyet ters yonde buyur; uzunlugu bir kademe artirmanin net bedeli asagida.
const im = (x, d = 0) => (x > 0 ? "+" : "") + x.toFixed(d);
console.log(`\nbir kademe uzatmanin bedeli:`);
for (let i = 1; i < T.length; i++) {
  const a = T[i - 1], b = T[i];
  console.log(`  ${a.L} -> ${b.L} hafta: toren ${im(b.toren - a.toren)}, ` +
    `gecis ${im(b.gecis - a.gecis)}, yeniden is ${im(b.yeniden - a.yeniden)}, ` +
    `net ${im(b.toplam - a.toplam)} adam-gun; akis suresi ${im(b.akis - a.akis, 1)}, ` +
    `gecikme ${im(b.gecikme - a.gecikme, 1)} is gunu`);
}
const enAz = T.reduce((a, b) => (b.toplam < a.toplam ? b : a));
const enHizli = T.reduce((a, b) => (b.akis < a.akis ? b : a));
console.log(`\nen az is gucu ${enAz.L} haftada (${enAz.toplam} adam-gun), ` +
  `en kisa akis suresi ${enHizli.L} haftada (${enHizli.akis.toFixed(1)} is gunu)`);
```

```
yineleme uzunlugu taramasi (akis suresi ve gecikme is gunu):
 uzunluk  yineleme  is gunu  ort. akis suresi  ort. gecikme  yeniden is  yarim kalan
 1 hafta        13       63              12.5           2.3          19            8
 2 hafta         7       62              13.8           5.5          21            2
 3 hafta         5       63              17.6           4.9          20            1
 4 hafta         5       81              21.6          10.6          22            1
 6 hafta         4       93              31.2          17.0          23            0

is gucunun dagilimi (adam-gun):
 uzunluk  temel is   toren  gecis  yeniden is   toplam  toren payi
 1 hafta       152      65      8          19      244       %26.6
 2 hafta       152      42      2          21      217       %19.4
 3 hafta       152      35      1          20      208       %16.8
 4 hafta       152      40      1          22      215       %18.6
 6 hafta       152      40      0          23      215       %18.6

bir kademe uzatmanin bedeli:
  1 -> 2 hafta: toren -23, gecis -6, yeniden is +2, net -27 adam-gun; akis suresi +1.3, gecikme +3.3 is gunu
  2 -> 3 hafta: toren -7, gecis -1, yeniden is -1, net -9 adam-gun; akis suresi +3.8, gecikme -0.6 is gunu
  3 -> 4 hafta: toren +5, gecis 0, yeniden is +2, net +7 adam-gun; akis suresi +4.0, gecikme +5.8 is gunu
  4 -> 6 hafta: toren 0, gecis -1, yeniden is +1, net 0 adam-gun; akis suresi +9.6, gecikme +6.4 is gunu

en az is gucu 3 haftada (208 adam-gun), en kisa akis suresi 1 haftada (12.5 is gunu)
```

#### İki Ölçü Farklı Uzunluğu Gösterir

Tarama tek bir kazanan üretmez, iki ayrı kazanan üretir. **Akış süresi bir haftada en kısadır**
(12,5 iş günü) ve uzunluk arttıkça tek yönde bozulur: altı haftada 31,2 iş gününe, iki buçuk katına
çıkar. Geri bildirim gecikmesi de aynı yöndedir — 2,3 iş gününden 17,0 iş gününe, yedi katına.
Sebebi ikilidir: kalem hem başlamak için bir sonraki planlamayı, hem kabul için yinelemenin sonunu
bekler ve iki bekleme de yineleme uzunluğuyla doğru orantılıdır.

**Toplam iş gücü ise üç haftada en azdır** (208 adam-gün). Bir haftalık ritim 244 adam-gün harcar
ve bunun 65'i törendir — toplamın **%26,6'sı**. Aynı ritim sekiz kez yarım kalan kalem üretir ve 8
adam-gün geçiş maliyeti öder; altı haftalık ritimde hiç yarım kalan yoktur. Bir haftadan iki haftaya
çıkmak 23 adam-gün tören ve 6 adam-gün geçiş tasarrufu sağlar, karşılığında akış süresine yalnız
1,3 iş günü ekler — bu kademe ucuzdur. Üç haftadan dört haftaya çıkmak ise 7 adam-gün **ekler** ve
akış süresine 4,0 iş günü bindirir; bu kademede kazanılacak bir şey kalmamıştır.

Yeniden iş sayısı beklenenden az hareket eder: 19'dan 23 adam-güne, yalnızca beşte bir oranında.
Kusurlu kalemin ardından tamamlanan bağlı kalem sayısı uzun yinelemede artar, ama otuz kalemlik bir
kümede bu ek küçük kalır. **Uzun yinelemenin asıl bedeli yeniden işin hacmi değil, gecikmenin
kendisidir**; iki hafta ile üç hafta arasında yeniden işin bir birim azalması da bu gürültünün
içindedir ve bir eğilim olarak okunmamalıdır.

İş günü sütunu ayrı bir uyarı taşır: bir haftalık ritim 63 iş gününde, iki haftalık ritim 62 iş
gününde biter. Kısa yineleme akış süresini kısaltır ama işin tamamını daha erken bitirmez, çünkü
kaybettiği kapasiteyi törene verir.

#### Özet

- Yinelemeli çerçeveler ortak dört ögeye indirgendi — biriktirme listesi, sabit uzunlukta yineleme,
  planlama ve gözden geçirme töreni, kabul yetkisini ayıran rol ayrımı — ve bu iskelet koşturuldu.
- Aynı 30 kalem beş uzunlukta koşturuldu; akış süresi bir haftada 12,5, altı haftada 31,2 iş günü,
  geri bildirim gecikmesi 2,3'ten 17,0 iş gününe çıktı.
- Toplam iş gücü üç haftada en azdır (208 adam-gün); bir haftalık ritim 244 adam-gün harcar ve
  bunun %26,6'sı törendir, ayrıca 8 kalemi yarım bırakıp 8 adam-gün geçiş maliyeti öder.
- İki ölçü iki farklı uzunluğu gösterdiği için taramadan tek bir en iyi çıkmaz: akış süresi bir
  haftayı, toplam iş gücü üç haftayı işaret eder.
- Yeniden iş 19'dan 23 adam-güne çıkarak en az hareket eden sütundur; uzun yinelemenin bedeli
  yeniden işin hacminden çok gecikmenin kendisidir.

#### Sonraki Adım

Bu dersin bütün ölçümleri sabit bir ritim varsayımına dayandı: iş kalemi ancak bir sonraki
planlamada başlar, ancak yinelemenin sonunda kabul edilir. Ritim kaldırıldığında elde kalan tek
denetim aracı **aynı anda kaç kalemin açık olduğudur**. Sonraki ders bu sınırı tarar: iş sınırı
birden yukarı çıktıkça çevrim süresi ve akış süresinin ne kadarının bekleme olduğu nasıl değişiyor,
iş çıkarma hangi sınırdan sonra artmayı bırakıyor ve sınır fazla düşük tutulduğunda ne kayboluyor.
Aynı koşumda akış ölçütleri tanımlanır — teslim süresi, çevrim süresi ve iş çıkarma — ve her birinin
hangi kararı verdirdiği ayrı ayrı yazılır.

### Akış Tabanlı Yönetim

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/akis-tabanli-yonetim

İş sınırlamanın ve akış ölçütlerinin ölçülmesi: teslim süresi, çevrim süresi ve iş çıkarma aynı koşumda tanımlanır, iş sınırı birden on altıya taranır, sınırın altında boş geçen kapasite ile üstünde geçişe giden iş gücü sayılır.

Önceki dersin bütün ölçümleri bir ritim varsayımına dayanıyordu: iş kalemi ancak bir sonraki
planlamada başlar, ancak yinelemenin sonunda kabul edilir. Ritim kaldırıldığında ortada bir parti
kalmaz ve iş kalemi hazır olduğu anda çekilir. Geriye tek bir denetim aracı kalır — **aynı anda kaç
kalemin açık olduğu**. Bu ders o sayıyı bir uçtan diğerine tarar.

Taramanın anlamlı olması için önce üç ölçütün ayrılması gerekir. **Teslim süresi** kalemin istendiği
günden işletime geçtiği güne kadarki toplam süredir. **Çevrim süresi** kalemin çalışmaya alındığı
günden bittiği güne kadarki süredir; teslim süresinin, kuyrukta beklenen kısmı çıkarılmış hâli.
**İş çıkarma** birim zamanda biten kalem sayısıdır. Üçü aynı koşumdan çıkar ve üçü farklı bir karara
işaret eder. İş sınırı bir geri basınç aracıdır; kuyruk mekaniği ile geri basınç bu müfredatta
başka yerde ölçüldüğü için burada sayılan şey kuyruğun kendisi değil, sınırın insan akışındaki
etkisidir. Through-line **bölgesel kütüphane ağıdır** ve kurgudur.

#### Üç Ölçüt Tek Koşumda

Aşağıdaki blok bir **modeldir**, ölçüm değil.

**SM13 — altmış iş kalemi bir üreteçle türetilir, üreteç kendi yazılır ve tohum görünürdür.** Her
kalemin bir boyutu (2–8 adam-gün) ve bir geliş günü vardır; aynı küme bütün sınır değerlerinde
kullanılır.

**SM14 — bir kaleme günde en çok 1 adam-gün verilebilir**, çünkü kalem üzerinde tek kişi çalışır.
Bu, sınırın altında ne kaybedildiğini belirleyen kuraldır: dört kişilik ekip iki kalem açıkken
günde en çok 2 adam-gün harcayabilir, kalan iki kişi boş kalır.

**SM15 — açık kalem sayısı kişi sayısını aştığında gün bir bölümünü geçişe verir.** Kişi başına
düşen her fazladan açık kalem, günlük kapasitenin %15'ini götürür. Sınırın üstünde ne kaybedildiğini
belirleyen kural budur.

**SM16 — iş sınırı `S` açık kalem sayısını sınırlar.** Sınır doluyken gelen kalem kuyrukta bekler ve
bu bekleme teslim süresine girer, çevrim süresine girmez.

**SM17 — kalemler geliş sırasına göre çekilir ve çalışmaya alınan kalem yarıda bırakılmaz.**
Öncelik sırası değişseydi teslim süresinin dağılımı değişirdi; sabit tutulması, taramada değişen tek
şeyin sınırın kendisi olmasını sağlar.

```js
// akis.mjs — is sinirlamali cekme sistemi (model); akis olcutleri tek sinirda tanimlanir
import { writeFileSync } from "node:fs";

const KISI = 4;        // ekip
const CEZA = 0.15;     // kisi basina her fazladan acik kalemin gunluk kaybi

// SM13: uretec kendi yazilir, tohum gorunur; ayni kalem kumesi butun sinirlarda kullanilir.
let tohum = 20250715;
const rast = () => (tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648;
let t = 0;
const KALEM = [...Array(60)].map((_, no) => {
  t += rast() < 0.35 ? 0 : 1;                    // gelisler yaklasik gunde 1,5 kalem
  return { no, boyut: 2 + Math.floor(rast() * 7), gelis: t };
});

function kostur(S) {
  const kuyruk = KALEM.map((k) => ({ ...k, kalan: k.boyut, bas: -1, bit: -1 }));
  const acik = [];
  let gun = 0, bosKapasite = 0, gecisKaybi = 0;
  while (kuyruk.some((k) => k.bit < 0)) {
    gun += 1;
    for (const k of kuyruk)                      // is sinirinin bosu kadar kalem cekilir
      if (acik.length < S && k.bas < 0 && k.gelis <= gun) { k.bas = gun; acik.push(k); }
    const n = acik.length;
    if (n === 0) { bosKapasite += KISI; continue; }
    // SM15: kisi basina birden cok acik kalem varsa gunun bir bolumu gecise gider
    const etkin = KISI * (1 - CEZA * Math.max(0, n / KISI - 1));
    gecisKaybi += KISI - etkin;
    const pay = Math.min(1, etkin / n);          // SM14: bir kaleme gunde en cok 1 adam-gun
    bosKapasite += Math.max(0, etkin - pay * n);
    for (const k of [...acik]) {
      k.kalan -= pay;
      if (k.kalan <= 1e-9) { k.bit = gun; acik.splice(acik.indexOf(k), 1); }
    }
  }
  const olcum = kuyruk.map((k) => ({
    no: k.no, boyut: k.boyut, teslim: k.bit - k.gelis + 1, cevrim: k.bit - k.bas + 1,
    bekleme: k.bit - k.bas + 1 - k.boyut, kuyrukta: k.bas - k.gelis,
  }));
  const ort = (f) => olcum.reduce((a, x) => a + f(x), 0) / olcum.length;
  return { S, gun, olcum,
    teslim: ort((x) => x.teslim), cevrim: ort((x) => x.cevrim), kuyrukta: ort((x) => x.kuyrukta),
    beklemePayi: ort((x) => x.bekleme) / ort((x) => x.cevrim),
    cikarma: KALEM.length / gun, bosKapasite: +bosKapasite.toFixed(1), gecisKaybi: +gecisKaybi.toFixed(1) };
}

const TARAMA = [1, 2, 3, 4, 5, 6, 8, 10, 12, 16].map(kostur);
writeFileSync("tarama.json", JSON.stringify(TARAMA.map(({ olcum, ...r }) => r)));

const bes = TARAMA[4];
console.log(`is kalemi: ${KALEM.length}, temel is: ${KALEM.reduce((a, k) => a + k.boyut, 0)} adam-gun, ` +
  `son gelis ${KALEM[KALEM.length - 1].gelis}. gun, ekip ${KISI} kisi (tohum ${20250715})`);
console.log(`\nis siniri ${bes.S}: uc olcut ilk sekiz kalemde (gun):`);
console.log(`${"kalem".padStart(6)}${"boyut".padStart(7)}${"kuyrukta".padStart(10)}` +
  `${"cevrim suresi".padStart(15)}${"bunun beklemesi".padStart(17)}${"teslim suresi".padStart(15)}`);
for (const x of bes.olcum.slice(0, 8))
  console.log(`${String(x.no).padStart(6)}${String(x.boyut).padStart(7)}${String(x.kuyrukta).padStart(10)}` +
    `${String(x.cevrim).padStart(15)}${String(x.bekleme).padStart(17)}${String(x.teslim).padStart(15)}`);
console.log(`\nteslim suresi = kuyrukta bekleme + cevrim suresi; cevrim suresi = calisma + bekleme`);
console.log(`ortalama: teslim ${bes.teslim.toFixed(1)}, cevrim ${bes.cevrim.toFixed(1)}, ` +
  `kuyrukta ${bes.kuyrukta.toFixed(1)} gun; bekleme payi %${(100 * bes.beklemePayi).toFixed(1)}; ` +
  `is cikarma ${bes.cikarma.toFixed(2)} kalem/gun`);
```

```
is kalemi: 60, temel is: 285 adam-gun, son gelis 40. gun, ekip 4 kisi (tohum 20250715)

is siniri 5: uc olcut ilk sekiz kalemde (gun):
 kalem  boyut  kuyrukta  cevrim suresi  bunun beklemesi  teslim suresi
     0      7         1              9                2             10
     1      7         0              9                2              9
     2      7         0              9                2              9
     3      5         0              7                2              7
     4      2         0              3                1              3
     5      2         2              3                1              5
     6      2         4              3                1              7
     7      3         3              4                1              7

teslim suresi = kuyrukta bekleme + cevrim suresi; cevrim suresi = calisma + bekleme
ortalama: teslim 21.9, cevrim 6.6, kuyrukta 15.3 gun; bekleme payi %27.8; is cikarma 0.74 kalem/gun
```

Altıncı kalem ölçütlerin neden ayrıldığını tek satırda gösterir: iki adam-günlük bir iş, çalışmaya
alındıktan sonra üç günde biter, ama istendiği günden itibaren yedi gün sürer. Çevrim süresi
kalemin üçte birlik bir bekleme taşıdığını söyler; teslim süresi ise sürenin **dörtte üçünün** iş
başlamadan önce geçtiğini söyler. Bu iki ölçüt aynı koşumda birbirinin dört katı olabilir.

#### İş Sınırının Taranması

**SM18 — üç ölçüt üç ayrı kararı verdirir** ve taramanın amacı hangisinin hangi sınırı işaret
ettiğini görmektir. Aşağıdaki blok sınırı birden on altıya kadar tarar.

```js
// sinir.mjs — akis.mjs'in yazdigi tarama sonucunu okur; is siniri bastan sona taranir
import { readFileSync } from "node:fs";

const T = JSON.parse(readFileSync("tarama.json", "utf8"));
const TEMEL = 285;
const tablo = (baslik, satir, ust) => {
  const yaz = (h) => console.log(h.map((c, i) => String(c).padStart(baslik[i][1])).join(""));
  if (ust) { console.log(); console.log(ust); }
  yaz(baslik.map((b) => b[0])); satir.forEach(yaz);
};

tablo([["is siniri", 10], ["toplam gun", 12], ["teslim suresi", 15], ["cevrim suresi", 15],
       ["kuyrukta", 10], ["bekleme payi", 14], ["is cikarma", 12]],
  T.map((r) => [r.S, r.gun, r.teslim.toFixed(1), r.cevrim.toFixed(1), r.kuyrukta.toFixed(1),
                `%${(100 * r.beklemePayi).toFixed(1)}`, r.cikarma.toFixed(2)]));

tablo([["is siniri", 10], ["toplam kapasite", 17], ["temel is", 10], ["bos gecen", 11],
       ["gecise giden", 14], ["bos oran", 10]],
  T.map((r) => [r.S, 4 * r.gun, TEMEL, r.bosKapasite.toFixed(1), r.gecisKaybi.toFixed(1),
                `%${((100 * r.bosKapasite) / (4 * r.gun)).toFixed(1)}`]),
  "kapasitenin nereye gittigi (adam-gun):");

// SM18: uc olcut uc ayri karari verdirir; her biri baska bir siniri en iyi gosterir.
const enAz = (f) => T.reduce((a, b) => (f(b) < f(a) ? b : a));
const tepe = enAz((r) => -r.cikarma), son = T[T.length - 1];
console.log(`\nen kisa cevrim suresi sinir ${enAz((r) => r.cevrim).S}, ` +
  `en kisa teslim suresi sinir ${enAz((r) => r.teslim).S}, ` +
  `en yuksek is cikarma sinir ${tepe.S} (${tepe.cikarma.toFixed(2)} kalem/gun)`);
console.log(`is cikarma sinir ${tepe.S}'te tepe yapar, sonra duser: ` +
  `sinir ${son.S}'da ${son.cikarma.toFixed(2)} kalem/gun ve ${son.gecisKaybi.toFixed(1)} adam-gun gecise gider`);
console.log(`sinirin altinda kaybedilen: sinir 1'de kapasitenin ` +
  `%${((100 * T[0].bosKapasite) / (4 * T[0].gun)).toFixed(1)}'i, ` +
  `sinir ${tepe.S}'te %${((100 * tepe.bosKapasite) / (4 * tepe.gun)).toFixed(1)}'i bos gecer`);
```

```
 is siniri  toplam gun  teslim suresi  cevrim suresi  kuyrukta  bekleme payi  is cikarma
         1         285          118.5            4.8     113.8          %0.0        0.21
         2         143           51.0            4.8      46.3          %0.0        0.42
         3          98           28.4            4.8      23.7          %0.0        0.61
         4          72           17.3            4.8      12.5          %0.0        0.83
         5          81           21.9            6.6      15.3         %27.8        0.74
         6          83           23.8            8.1      15.7         %41.2        0.72
         8          89           27.6           11.3      16.3         %57.9        0.67
        10          94           31.4           14.6      16.8         %67.5        0.64
        12         102           36.7           18.9      17.9         %74.8        0.59
        16         123           51.0           29.9      21.1         %84.1        0.49

kapasitenin nereye gittigi (adam-gun):
 is siniri  toplam kapasite  temel is  bos gecen  gecise giden  bos oran
         1             1140       285      855.0           0.0     %75.0
         2              572       285      287.0           0.0     %50.2
         3              392       285      107.0           0.0     %27.3
         4              288       285        3.0           0.0      %1.0
         5              324       285        5.0          11.4      %1.5
         6              332       285        4.0          23.6      %1.2
         8              356       285        7.0          49.2      %2.0
        10              376       285        4.0          75.7      %1.1
        12              408       285        4.0         109.1      %1.0
        16              492       285        5.0         195.9      %1.0

en kisa cevrim suresi sinir 1, en kisa teslim suresi sinir 4, en yuksek is cikarma sinir 4 (0.83 kalem/gun)
is cikarma sinir 4'te tepe yapar, sonra duser: sinir 16'da 0.49 kalem/gun ve 195.9 adam-gun gecise gider
sinirin altinda kaybedilen: sinir 1'de kapasitenin %75.0'i, sinir 4'te %1.0'i bos gecer
```

#### Hangi Ölçüt Hangi Kararı Verdirir

Tablonun en öğretici satırı birincisidir. **İş sınırı bir olduğunda çevrim süresi 4,8 günle en
kısadır ve bekleme payı tam olarak sıfırdır** — açılan tek kalem hiç beklemeden, kesintisiz
çalışılır. Aynı satırda teslim süresi 118,5 gündür ve kapasitenin **%75'i boş geçer**. Çevrim
süresine bakarak yönetilen bir akış, mümkün olan en kötü sistemi kusursuz gösterir.

Sınır dörde çıktığında dört kişi dört kaleme dağılır, boş kapasite %75'ten **%1'e** iner, iş çıkarma
0,21'den 0,83 kalem/güne çıkar ve teslim süresi 118,5 günden 17,3 güne düşer. Bu noktaya kadar
çevrim süresi hiç bozulmamıştır (4,8 gün), çünkü her kaleme hâlâ tam bir kişi düşmektedir.

Sınır beşten sonra ikinci mekanizma devreye girer. Kişi başına birden çok kalem düştüğü anda çevrim
süresi 4,8'den 6,6 güne çıkar ve **bekleme payı sıfırdan %27,8'e fırlar**. On altıda çevrim süresi
29,9 gün, bekleme payı %84,1'dir: bir kalemin ömrünün altıda beşi, üstünde çalışılmadan geçer. İş
çıkarma dörtte tepe yapar ve on altıda 0,49'a düşer; 195,9 adam-gün geçişe gider. **Sınırı
yükseltmek daha çok kalemi aynı anda açar, ama hiçbirini daha erken bitirmez.**

Üç ölçüt üç ayrı karara bakar. Çevrim süresi işin kendi içindeki akışı ölçer ve sürecin neresinde
bekleme biriktiğini gösterir; tek başına okunduğunda kuyruktaki her şeyi gizler. Teslim süresi
talep verilen sözün ölçüsüdür ve kapasite kararını verdirir. İş çıkarma yeni iş kabul edilip
edilemeyeceğini söyler ve doyduğu nokta sınırın üst ucunu belirler. Bu koşumda üçü sırasıyla bir,
dört ve dört sınırını işaret eder; yalnız biri okunursa üçünden ikisi görülmez.

#### Özet

- Teslim süresi, çevrim süresi ve iş çıkarma aynı koşumda tanımlandı; teslim süresi kuyrukta
  bekleme ile çevrim süresinin toplamı, çevrim süresi ise çalışma ile bekleme toplamıdır.
- Sınır 1'de çevrim süresi en kısadır (4,8 gün) ve bekleme payı sıfırdır, ama teslim süresi 118,5
  gündür ve kapasitenin %75'i boş geçer — çevrim süresi tek başına yanıltır.
- Sınır 4'te boş kapasite %1'e iner, iş çıkarma 0,83 kalem/günle tepe yapar ve teslim süresi 17,3
  güne düşer; bu noktaya kadar çevrim süresi hiç bozulmaz.
- Sınır 4'ün üstünde bekleme payı sıfırdan %84,1'e çıkar, çevrim süresi 29,9 güne uzar, iş çıkarma
  0,49'a düşer ve 195,9 adam-gün geçişe gider.
- Üç ölçüt bu koşumda sırasıyla 1, 4 ve 4 sınırını işaret eder; üçü birlikte okunmadan sınır
  seçilemez.

#### Sonraki Adım

Bu dersin bütün ölçümleri tek bir ekip üzerinde yapıldı: dört kişi, tek bir biriktirme listesi ve
tek bir iş sınırı. Bu varsayım kaldırıldığında yeni bir maliyet kalemi doğar. Bir iş kalemi birden
çok ekibin dokunduğu bir değişiklik gerektirdiğinde, ekipler arasında bir **eşgüdüm turu** geçmesi
gerekir ve bu tur ne çalışmadır ne de kuyrukta beklemedir. Sonraki ders çok ekipli eşgüdümün
bedelini sayar: ekip sayısı arttıkça bağımlı iş kalemi başına kaç eşgüdüm turu düşüyor, ortak
planlama turu kaça mal oluyor, eşgüdüm katmanının kendi gecikmesi ne kadar ve bu bedel ekip sayısına
göre doğrusal mı yoksa karesel mi büyüyor. Aynı koşumda ikinci bir soru sorulur — hangi bağımlılık
türü kaldırıldığında kaç tur kazanılıyor.

### Ölçekli Çerçeveler

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/olcekli-cerceveler

Çok ekipli eşgüdümün bedelinin sayılması: aynı yirmi dört kişi ve yirmi dört modül bir ile on iki ekip arasında bölünür, bağımlı iş kalemi başına eşgüdüm turu, ortak kanal sayısı, eşgüdüm katmanının gecikmesi ve ortak planlama turunun maliyeti ölçülür.

Önceki dersin bütün ölçümleri tek ekip üzerinde yapıldı: bir biriktirme listesi, bir iş sınırı, dört
kişi. Bu varsayım kaldırıldığında yeni bir maliyet kalemi doğar. Bir iş kalemi birden çok ekibin
sahip olduğu modüllere dokunduğunda, ekipler arasında bir **eşgüdüm turu** geçmesi gerekir; bu tur
ne çalışmadır ne de kuyrukta beklemedir, akış süresine eklenir ama hiçbir kaleme yaklaştırmaz.

Ölçekli çerçeveler bu turu düzene sokma girişimidir: bir **eşgüdüm katmanı**, düzenli bir **ortak
planlama turu** ve ekipler arası bağımlılıkları önceden görünür kılan bir liste. Bu ders çerçeveleri
adlarıyla değil bu üç ögeyle ele alır ve tek bir soruyu ölçer — ekip sayısı arttıkça eşgüdüm bedeli
ne kadar büyür. Through-line **bölgesel kütüphane ağıdır** ve kurgudur; ağın yirmi dört modülü ve
yirmi dört kişilik geliştirme kadrosu sabit tutulur, değişen yalnız ekip sınırlarıdır.

#### Aynı İşin Farklı Bölünmeleri

Aşağıdaki blok bir **modeldir**, ölçüm değil.

**SM19 — yirmi dört modül ve yirmi dört kişi sabittir; `E` ekip yalnızca sınırları değiştirir.**
Modüller bitişik bloklara bölünür ve her ekipte `24 / E` kişi bulunur. Karşılaştırmanın anlamlı
olması için kadro büyümez: ölçülen şey işgücü değil, sınırın kendisidir.

**SM20 — kırk iş kalemi bir üreteçle türetilir, üreteç kendi yazılır ve tohum görünürdür.** Her
kalem bir ile dört modüle dokunur; ilkinden sonraki her dokunuş bir **bağımlılık türü** taşır —
ortak veri, ortak uç, ortak altyapı ya da sıralı teslim.

**SM21 — bir kalem `t` ekibe yayılıyorsa `t - 1` eşgüdüm turu gerekir** ve her tur iki ekibe 2
adam-güne mal olur. Ayrıca kalemin dokunduğu her ekip çifti arasında sürekli bir kanal açılır.

**SM22 — eşgüdüm katmanı bir dönemde en çok altı tur işler**; sırasını bekleyen kalem gecikir. İşin
kendisi eşgüdümden bağımsız olarak sekiz dönem sürer, eşgüdüm birikirse dönem sayısı uzar.

**SM23 — ortak planlama turunda her ekip sunar ve herkes dinler.** Maliyeti dönem sayısı, kişi
sayısı ve ekip sayısının çarpımıyla büyür.

**SM24 — ekip içi eşgüdüm kişi çiftine göre büyür**: `E` ekipli bir düzende toplam iç çift sayısı
`E · s(s-1)/2`, burada `s = 24 / E`. Bu, ekip sayısı arttıkça **azalan** tek kalemdir.

```js
// olcek.mjs — ayni is yukunun farkli ekip sayilarina bolunmesi (model)
import { writeFileSync } from "node:fs";

const MODUL = 24, INSAN = 24;      // modul ve kisi sayisi sabit; degisen yalnizca ekip sinirlari
const TUR_BEDEL = 2;               // bir esgudum turunun iki ekibe maliyeti (adam-gun)
const IC_BEDEL = 0.2;              // ekip ici kisi cifti basina donem maliyeti (adam-gun)
const PLAN_BEDEL = 0.1;            // ortak planlama turunda kisi ve ekip basina (adam-gun)
const TEMEL_DONEM = 8;             // isin kendisi, esgudumden bagimsiz, bu kadar donem surer
const DONEM_TUR = 6;               // esgudum katmaninin bir donemde isleyebildigi tur sayisi

// SM20: uretec kendi yazilir, tohum gorunur; ayni kalem kumesi butun ekip sayilarinda kullanilir.
let tohum = 20251103;
const rast = () => (tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648;
const TIP = ["ortak veri", "ortak uc", "ortak altyapi", "sirali teslim"];
const KALEM = [...Array(40)].map((no) => {
  const kac = 1 + Math.floor(rast() * 4);
  const modul = [], tip = [];
  while (modul.length < kac) {
    const m = Math.floor(rast() * MODUL);
    if (!modul.includes(m)) { modul.push(m); if (modul.length > 1) tip.push(TIP[Math.floor(rast() * 4)]); }
  }
  return { no, modul, tip };
});

// SM19: E ekip, modulleri bitisik bloklara boler; her ekipte INSAN / E kisi bulunur.
const ekipOf = (E) => (m) => Math.min(E - 1, Math.floor((m * E) / MODUL));

function kostur(E, atla = null) {
  const ekip = ekipOf(E);
  let tur = 0, bagimli = 0, yayilan = 0;
  const cift = new Set();
  const dizi = [];                                   // esgudum katmanina giren turlar, kalem sirali
  for (const k of KALEM) {
    const goz = k.modul.filter((_, i) => i === 0 || k.tip[i - 1] !== atla);   // atlanan tip dusurulur
    const t = [...new Set(goz.map(ekip))];
    if (t.length <= 1) continue;
    bagimli += 1; yayilan += t.length; tur += t.length - 1;
    for (let i = 0; i < t.length; i++)
      for (let j = i + 1; j < t.length; j++) cift.add(`${Math.min(t[i], t[j])}-${Math.max(t[i], t[j])}`);
    dizi.push({ no: k.no, tur: t.length - 1 });
  }
  // SM22: esgudum katmani donem basina DONEM_TUR tur isler; sirasini bekleyen kalem gecikir.
  let biriken = 0, gecikmeToplam = 0;
  for (const d of dizi) { biriken += d.tur; gecikmeToplam += Math.ceil(biriken / DONEM_TUR); }
  const donem = Math.max(TEMEL_DONEM, Math.ceil(tur / DONEM_TUR));
  const kisi = INSAN / E;
  return { E, kisi, bagimli, tur, cift: cift.size, donem,
    gecikme: dizi.length ? gecikmeToplam / dizi.length : 0,
    yayilma: bagimli ? yayilan / bagimli : 1,
    disBedel: tur * TUR_BEDEL,
    planBedel: +(donem * INSAN * E * PLAN_BEDEL).toFixed(1),   // her ekip sunar, herkes dinler
    icBedel: +(E * ((kisi * (kisi - 1)) / 2) * IC_BEDEL * donem).toFixed(1) };
}

const EKIP = [1, 2, 3, 4, 6, 8, 12];
const TARAMA = EKIP.map((E) => {
  const r = kostur(E);
  return { ...r, toplam: +(r.disBedel + r.planBedel + r.icBedel).toFixed(1) };
});
writeFileSync("olcek.json", JSON.stringify({ TARAMA, TIP,
  atlamali: TIP.map((t) => ({ tip: t, satir: EKIP.map((E) => kostur(E, t).tur) })) }));

console.log(`modul: ${MODUL}, kisi: ${INSAN}, is kalemi: ${KALEM.length}, ` +
  `bagimlilik bagi: ${KALEM.reduce((a, k) => a + k.tip.length, 0)} (tohum ${20251103})`);
console.log(`tip dagilimi: ${TIP.map((t) =>
  `${t} ${KALEM.reduce((a, k) => a + k.tip.filter((x) => x === t).length, 0)}`).join(", ")}`);

const dort = TARAMA[3];
console.log(`\ndort ekip, ayrintili: ekip basina ${dort.kisi} kisi, ${MODUL / 4} modul`);
console.log(`  ${dort.bagimli}/${KALEM.length} kalem birden cok ekibe yayiliyor, ` +
  `yayilan kalem ortalama ${dort.yayilma.toFixed(2)} ekip`);
console.log(`  esgudum turu ${dort.tur}, ortak kanal gereken ekip cifti ${dort.cift}/${(4 * 3) / 2}, ` +
  `${dort.donem} donem`);
console.log(`  bedel: dis esgudum ${dort.disBedel}, ortak planlama ${dort.planBedel}, ` +
  `ekip ici ${dort.icBedel} adam-gun`);
```

```
modul: 24, kisi: 24, is kalemi: 40, bagimlilik bagi: 69 (tohum 20251103)
tip dagilimi: ortak veri 18, ortak uc 13, ortak altyapi 21, sirali teslim 17

dort ekip, ayrintili: ekip basina 6 kisi, 6 modul
  31/40 kalem birden cok ekibe yayiliyor, yayilan kalem ortalama 2.61 ekip
  esgudum turu 50, ortak kanal gereken ekip cifti 6/6, 9 donem
  bedel: dis esgudum 100, ortak planlama 86.4, ekip ici 108 adam-gun
```

Dört ekipli düzende kırk kalemin **otuz biri** birden çok ekibe yayılır ve yayılan kalem ortalama
2,61 ekibe dokunur. Altı olası ekip çiftinin **altısı da** en az bir kalem yüzünden birbirine bağlı
hâle gelir: dört ekibin hiçbiri diğerinden yalıtılmış değildir.

#### Ekip Sayısının Taranması

```js
// esgudum.mjs — olcek.mjs'in yazdigi tarama sonucunu okur; ekip sayisi bastan sona taranir
import { readFileSync } from "node:fs";

const { TARAMA, TIP, atlamali } = JSON.parse(readFileSync("olcek.json", "utf8"));
const tablo = (baslik, satir, ust) => {
  const yaz = (h) => console.log(h.map((c, i) => String(c).padStart(baslik[i][1])).join(""));
  if (ust) { console.log(); console.log(ust); }
  yaz(baslik.map((b) => b[0])); satir.forEach(yaz);
};

tablo([["ekip", 6], ["ekipte kisi", 13], ["bagimli kalem", 15], ["yayilma", 9], ["esgudum turu", 14],
       ["ekip cifti", 12], ["kalem basina gecikme", 22]],
  TARAMA.map((r) => [r.E, r.kisi, `${r.bagimli}/40`, r.yayilma.toFixed(2), r.tur, r.cift,
                     r.gecikme.toFixed(1)]));

// SM24: buyume duzeni iki oranla okunur; hangisi sabit kaliyorsa buyume o duzendedir.
tablo([["ekip", 6], ["esgudum turu", 14], ["tur / ekip", 12], ["ekip cifti", 12],
       ["cift / (E(E-1)/2)", 19]],
  TARAMA.filter((r) => r.E > 1).map((r) => [r.E, r.tur, (r.tur / r.E).toFixed(1), r.cift,
    (r.cift / ((r.E * (r.E - 1)) / 2)).toFixed(2)]),
  "buyume duzeni:");

tablo([["ekip", 6], ["donem", 8], ["dis esgudum", 13], ["ortak planlama", 16], ["ekip ici", 10],
       ["toplam", 9]],
  TARAMA.map((r) => [r.E, r.donem, r.disBedel, r.planBedel, r.icBedel, r.toplam]),
  "esgudum bedeli (adam-gun):");

const enAz = TARAMA.reduce((a, b) => (b.toplam < a.toplam ? b : a));
console.log(`\nen az esgudum bedeli ${enAz.E} ekipte (${enAz.toplam} adam-gun); ` +
  `tek ekipte ${TARAMA[0].toplam}, on iki ekipte ${TARAMA[TARAMA.length - 1].toplam} adam-gun`);

tablo([["bagimlilik turu", 17], ...TARAMA.map((r) => [`${r.E} ekip`, 9])],
  atlamali.map((a) => [a.tip, ...a.satir.map((t, i) => t - TARAMA[i].tur)]),
  "bir bagimlilik turu kaldirilirsa esgudum turundaki degisim:");
const dort = atlamali.map((a) => ({ tip: a.tip, kazanc: TARAMA[3].tur - a.satir[3] }))
  .sort((a, b) => b.kazanc - a.kazanc);
console.log(`\ndort ekipte en cok tur kazandiran: ${dort.map((d) => `${d.tip} (${d.kazanc})`).join(", ")}`);
```

```
  ekip  ekipte kisi  bagimli kalem  yayilma  esgudum turu  ekip cifti  kalem basina gecikme
     1           24           0/40     1.00             0           0                   0.0
     2           12          27/40     2.00            27           1                   2.8
     3            8          30/40     2.37            41           3                   3.8
     4            6          31/40     2.61            50           6                   4.6
     6            4          32/40     2.69            54          15                   4.8
     8            3          33/40     2.76            58          27                   5.2
    12            2          34/40     2.94            66          55                   5.9

buyume duzeni:
  ekip  esgudum turu  tur / ekip  ekip cifti  cift / (E(E-1)/2)
     2            27        13.5           1               1.00
     3            41        13.7           3               1.00
     4            50        12.5           6               1.00
     6            54         9.0          15               1.00
     8            58         7.3          27               0.96
    12            66         5.5          55               0.83

esgudum bedeli (adam-gun):
  ekip   donem  dis esgudum  ortak planlama  ekip ici   toplam
     1       8            0            19.2     441.6    460.8
     2       8           54            38.4     211.2    303.6
     3       8           82            57.6     134.4      274
     4       9          100            86.4       108    294.4
     6       9          108           129.6      64.8    302.4
     8      10          116             192        48      356
    12      11          132           316.8      26.4    475.2

en az esgudum bedeli 3 ekipte (274 adam-gun); tek ekipte 460.8, on iki ekipte 475.2 adam-gun

bir bagimlilik turu kaldirilirsa esgudum turundaki degisim:
  bagimlilik turu   1 ekip   2 ekip   3 ekip   4 ekip   6 ekip   8 ekip  12 ekip
       ortak veri        0       -6      -10      -12      -15      -14      -18
         ortak uc        0       -4       -5       -8       -8      -11      -13
    ortak altyapi        0       -4       -9      -11      -11      -17      -18
    sirali teslim        0       -7      -11      -14      -15      -14      -17

dort ekipte en cok tur kazandiran: sirali teslim (14), ortak veri (12), ortak altyapi (11), ortak uc (8)
```

#### Doğrusal Değil, İki Ayrı Düzen

Sorunun cevabı tek bir büyüme düzeni değil, iki ayrı düzendir ve ikisi ters yönde okunur.

**Eşgüdüm turu doğrusalın altında kalır.** Tur sayısı 27'den 66'ya çıkarken ekip sayısı altı katına
çıkar; `tur / ekip` oranı 13,5'ten 5,5'e **düşer**. Sebebi tavandır: bir kalem en çok dört modüle
dokunduğu için en çok dört ekibe yayılabilir ve turu üçü geçemez. Ekip sayısı arttıkça yeni bağımlı
kalem bulunmaz, var olanlar biraz daha yayılır — yayılma 2,00'den 2,94'e çıkar ve orada durur.

**Ortak kanal sayısı ise tam olarak karesel büyür.** `cift / (E(E-1)/2)` oranı iki, üç, dört ve altı
ekipte tam 1,00'dir: **olası her ekip çifti** en az bir kalem yüzünden birbirine bağlanır. Doyma
ancak sekiz ve on iki ekipte başlar (0,96 ve 0,83) ve orada bile çift sayısı 27 ile 55'tir. Eşgüdüm
turunun sayısı ölçülüdür, ama o turların dağıldığı **kanal sayısı** ölçülü değildir.

Bedel tablosu bu iki düzenin toplamını gösterir. Tek ekipte dış eşgüdüm sıfırdır ama yirmi dört
kişinin iç eşgüdümü 441,6 adam-gün tutar. On iki ekipte iç eşgüdüm 26,4 adam-güne iner ama ortak
planlama turu 316,8 adam-güne çıkar — her ekip sunduğu ve herkes dinlediği için bu kalem doğrudan
ekip sayısıyla büyür. Toplam **üç ekipte en azdır (274 adam-gün)** ve iki uçta neredeyse eşittir:
460,8 ile 475,2. Aynı iş, aynı yirmi dört kişi, iki farklı yoldan iki kat pahalıya mal olur.

Eşgüdüm katmanının kendi gecikmesi ayrı bir sütundur: bağımlı kalem başına 2,8 dönemden 5,9 döneme
çıkar. Bu süre boyunca kalem üzerinde kimse çalışmaz.

#### Hangi Bağımlılığı Kaldırmak Ne Kazandırır

Son tablo turların nereden geldiğini ayırır. Dört ekipli düzende **sıralı teslim** bağımlılığını
kaldırmak elli turdan on dördünü siler, **ortak veri** on ikisini, **ortak altyapı** on birini,
**ortak uç** sekizini. Sıra ekip sayısıyla değişir: on iki ekipte ortak veri ile ortak altyapı öne
geçer (on sekizer tur), sıralı teslim on yedide kalır.

Okunacak şey sıralama değil, ölçüdür. Dört ekipte tek bir bağımlılık türünü ortadan kaldırmak
turların **%16 ile %28 arasında** bir bölümünü siler; dördünü birden kaldırmak gerekmez, ama hiçbiri
tek başına sorunu çözmez de. Ekip sınırını değiştirmeden yapılabilecek en ucuz iyileştirme, en çok
tur üreten bağımlılık türünü mimariden kaldırmaktır.

#### Özet

- Aynı 24 modül ve 24 kişi bir ile on iki ekibe bölündü; kadro sabit tutulduğu için ölçülen tek şey
  sınırın kendisidir.
- Eşgüdüm turu doğrusalın altında büyür (27'den 66'ya, `tur / ekip` 13,5'ten 5,5'e düşer), çünkü bir
  kalem en çok dört modüle dokunur ve yayılması 2,94'te durur.
- Ortak kanal sayısı karesel büyür: iki ile altı ekip arasında olası her ekip çifti bağlanır
  (`cift / (E(E-1)/2)` tam 1,00), on ikide çift sayısı 55'tir.
- Toplam eşgüdüm bedeli üç ekipte en azdır (274 adam-gün) ve iki uçta neredeyse eşittir — tek ekipte
  441,6 adam-gün iç eşgüdüm, on iki ekipte 316,8 adam-gün ortak planlama.
- Dört ekipte tek bir bağımlılık türünü kaldırmak elli turun 8 ile 14'ünü siler; sıralı teslim en
  çok, ortak uç en az kazandırır, sıra ekip sayısıyla değişir.

#### Sonraki Adım

Bu dersin bütün sayıları bir kabulün üstünde duruyor: kusur bulunduğunda geri dönülür. Kaç turun
geri dönüldüğü sayıldı, ama **kusurun ne zaman bulunduğu** hep aynı yerde varsayıldı — işin sonunda.
Sonraki ders bu varsayımı kaldırır ve konuyu kapatır: kusurun doğduğu adım ile bulunduğu adım
arasındaki mesafe, yani **hata bulma gecikmesi**, doğrudan ölçülür. Tümleştirme sıklığı günde bir
kezden haftada bir keze taranır, eşli çalışma oranı sıfırdan bire taranır ve her ayarda bu gecikme
kaç adım ile kaç saattir, yeniden iş ne kadar değişir, toplam iş gücü ne olur sayılır. Eşli
çalışmanın iki kişilik maliyeti hesaba katılır — bir işin iki kişiyle yapılması, bulunan hatayı
ucuzlatsa bile, iş gücünü iki katına çıkarır.

### Mühendislik Pratikleri

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/muhendislik-pratikleri

Hata bulma gecikmesinin ölçülmesi: kusurun doğduğu adım ile bulunduğu adım arası kaç adım ve kaç saat, tümleştirme sıklığı iki saatten kırk saate ve eşli çalışma oranı sıfırdan bire tarandığında bu gecikme, yeniden iş ve eşli çalışmanın iki kişilik maliyeti dahil toplam iş gücü nasıl değişir.

Önceki dört ders bir sayıyı hep varsayım olarak aldı: kusur bulunduğunda geri dönülür. Kaç kalemin
geri döndüğü ve kaça mal olduğu sayıldı, ama **kusurun ne zaman bulunduğu** her seferinde sürecin
biçiminden okundu. Bu ders konuyu kapatırken o sayıyı doğrudan ölçer: **hata bulma gecikmesi**,
yani kusurun doğduğu adım ile bulunduğu adım arasındaki mesafe.

Mesafe iki ayrı birimde ölçülür ve ikisi aynı şeyi söylemez. **Adım** cinsinden gecikme kusurun kaç
aşama sonra göründüğünü, **saat** cinsinden gecikme o aşamaların ne kadar sürdüğünü verir. İki
pratik bu iki birime ayrı ayrı dokunur: tümleştirme sıklığı saati kısaltır, eşli çalışma adımı.
Teslimat hattının mekaniği bu müfredatta başka yerde koşturulduğu için burada hat bir periyottan
ibarettir. Through-line **bölgesel kütüphane ağıdır** ve kurgudur.

#### Kusur Nerede Bulunuyor

Aşağıdaki blok bir **modeldir**, ölçüm değil.

**SM25 — kırk sekiz iş kalemi bir üreteçle türetilir, üreteç kendi yazılır ve tohum görünürdür.**
Her kalemin bir boyutu (3–12 saat) ve dokunduğu bir modül vardır; aynı küme bütün ayarlarda
kullanılır. Sekiz geliştirici çalışır.

**SM26 — kusurun en erken görülebileceği adım bir sınıf olarak girdidir.** Yol beş adımdır: yazım,
yerel, tümleşim, sürüm, işletim. **Yazım** sınıfı kusur, ikinci bir çift göz varsa yazılırken
görünür; yoksa tümleşime kadar gizli kalır. **Tümleşim** sınıfı ancak başkalarının işiyle
birleşince, **sürüm** sınıfı sürüm sınamasında, **işletim** sınıfı yalnız işletimde görünür. Sürüm
sınaması kırk saatte bir, işletim penceresi seksen saatte bir açılır.

**SM27 — eşli çalışılan kalemde yazım sınıfı kusur yerinde düzeltilir** ve ayrı bir iş kalemi
olmaz. Bu, eşli çalışmanın modeldeki tek kazancıdır.

**SM28 — her tümleştirme olayı sabit 0,5 saat tutar**, üstüne aynı partide tümleşen her kalem çifti
için 0,06 saat çakışma bedeli eklenir. Seyrek tümleştirmenin bedeli buradan gelir: parti büyüdükçe
çift sayısı karesel artar.

Yeniden iş, kalemin üçte biri artı kusurun doğuşu ile bulunuşu arasında **aynı modülde** tamamlanmış
her kalem için bir saattir.

```js
// pratik.mjs — hata bulma gecikmesi (model); tumlestirme sikligi ve esli calisma orani taranir
import { writeFileSync } from "node:fs";

const KISI = 8;            // gelistirici sayisi
const SURUM = 40;          // surum sinamasi bu saatte bir kosar
const ISLETIM = 80;        // isletim penceresi
const SABIT = 0.5;         // her tumlestirme olayinin sabit maliyeti (saat)
const CAKISMA = 0.06;      // ayni partide tumlesen her kalem cifti icin cakisma maliyeti (saat)
const ADIM = ["yazim", "yerel", "tumlesim", "surum", "isletim"];

// SM25: uretec kendi yazilir, tohum gorunur; ayni kalem kumesi butun ayarlarda kullanilir.
let tohum = 20260127;
const rast = () => (tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648;
const MODUL = ["odunc", "ucret", "uyelik", "katalog", "sube", "kimlik"];
const KALEM = [...Array(48)].map((no) => {
  const boyut = 3 + Math.floor(rast() * 10);              // 3-12 saat
  const m = MODUL[Math.floor(rast() * MODUL.length)];
  const r = rast();
  // SM26: kusurun en erken gorulebilecegi adim sinifi girdidir
  const sinif = r < 0.55 ? null : r < 0.76 ? "yazim" : r < 0.90 ? "tumlesim" : r < 0.96 ? "surum" : "isletim";
  return { no, boyut, modul: m, sinif };
});

const sonraki = (t, p) => Math.ceil((t + 1e-9) / p) * p;   // bir sonraki periyodik olay

function kostur(T, oran) {
  const bos = Array(KISI).fill(0);
  const kalem = KALEM.map((k, i) => ({ ...k, esli: i % 4 < Math.round(oran * 4) }));
  let isGucu = 0;
  for (const k of kalem) {
    const kac = k.esli ? 2 : 1;
    const sec = bos.map((t, i) => [t, i]).sort((a, b) => a[0] - b[0]).slice(0, kac);
    const bas = Math.max(...sec.map(([t]) => t));
    for (const [, i] of sec) bos[i] = bas + k.boyut;
    k.bit = bas + k.boyut;
    isGucu += k.boyut * kac;
  }
  // SM27: esli calisilan kalemde yazim sinifi kusur ayni anda gorulur; digerleri periyodu bekler
  const bulgu = [];
  for (const k of kalem) {
    if (!k.sinif) continue;
    const [adim, an] =
      k.sinif === "yazim" && k.esli ? [0, k.bit]
      : k.sinif === "surum" ? [3, sonraki(k.bit, SURUM)]
      : k.sinif === "isletim" ? [4, sonraki(k.bit, ISLETIM)]
      : [2, sonraki(k.bit, T)];
    const ustune = kalem.filter((x) => x.modul === k.modul && x.bit > k.bit && x.bit <= an).length;
    // yazarken yakalanan kusur yerinde duzeltilir, ayri bir is kalemi olmaz
    bulgu.push({ no: k.no, sinif: k.sinif, adim, gecikmeSaat: an - k.bit,
                 yeniden: adim === 0 ? 0 : Math.ceil(k.boyut / 3) + ustune });
  }
  const yeniden = bulgu.reduce((a, b) => a + b.yeniden, 0);
  // SM28: her tumlestirme olayi sabit bir bedel, ustune partideki kalem cifti kadar cakisma odetir
  const son = Math.max(...kalem.map((k) => k.bit));
  let olay = 0, cakisma = 0;
  for (let t = T; t <= sonraki(son, T); t += T) {
    const parti = kalem.filter((k) => k.bit > t - T && k.bit <= t).length;
    if (parti === 0) continue;
    olay += 1; cakisma += (CAKISMA * parti * (parti - 1)) / 2;
  }
  const tumlesimBedeli = +(olay * SABIT + cakisma).toFixed(1);
  const ort = (f) => bulgu.reduce((a, b) => a + f(b), 0) / bulgu.length;
  return { T, oran, sure: son, bulgular: bulgu, bulgu: bulgu.length, olay, cakisma: +cakisma.toFixed(1),
    gecikmeAdim: ort((b) => b.adim), gecikmeSaat: ort((b) => b.gecikmeSaat),
    esliBulunan: bulgu.filter((b) => b.adim === 0).length,
    yeniden, tumlesimBedeli, isGucu,
    toplam: +(isGucu + yeniden + tumlesimBedeli).toFixed(1) };
}

const cikar = ({ bulgular, ...r }) => r;
const SIKLIK = [2, 4, 8, 16, 40].map((T) => kostur(T, 0));
const ORAN = [0, 0.25, 0.5, 0.75, 1].map((o) => kostur(4, o));
writeFileSync("pratik.json", JSON.stringify({ SIKLIK: SIKLIK.map(cikar), ORAN: ORAN.map(cikar) }));

console.log(`is kalemi: ${KALEM.length}, temel is: ${KALEM.reduce((a, k) => a + k.boyut, 0)} saat, ` +
  `gelistirici: ${KISI} (tohum ${20260127})`);
console.log(`kusur sinifi: ${["yazim", "tumlesim", "surum", "isletim"]
  .map((s) => `${s} ${KALEM.filter((k) => k.sinif === s).length}`).join(", ")}; ` +
  `kusursuz ${KALEM.filter((k) => !k.sinif).length}`);
console.log(`adimlar: ${ADIM.map((a, i) => `${i} ${a}`).join(", ")}`);

const temel = SIKLIK[1];
console.log(`\ntumlestirme 4 saatte bir, esli calisma yok: kusur nerede bulunuyor`);
console.log(`${"kusur sinifi".padEnd(14)}${"adet".padStart(6)}${"bulundugu adim".padStart(16)}` +
  `${"gecikme (adim)".padStart(16)}${"gecikme (saat)".padStart(16)}${"yeniden is".padStart(12)}`);
for (const s of ["yazim", "tumlesim", "surum", "isletim"]) {
  const g = temel.bulgular.filter((b) => b.sinif === s);
  const o = (f) => (g.reduce((a, b) => a + f(b), 0) / g.length).toFixed(1);
  console.log(`${s.padEnd(14)}${String(g.length).padStart(6)}${ADIM[g[0].adim].padStart(16)}` +
    `${o((b) => b.adim).padStart(16)}${o((b) => b.gecikmeSaat).padStart(16)}` +
    `${String(g.reduce((a, b) => a + b.yeniden, 0)).padStart(12)}`);
}
```

```
is kalemi: 48, temel is: 354 saat, gelistirici: 8 (tohum 20260127)
kusur sinifi: yazim 14, tumlesim 5, surum 2, isletim 2; kusursuz 25
adimlar: 0 yazim, 1 yerel, 2 tumlesim, 3 surum, 4 isletim

tumlestirme 4 saatte bir, esli calisma yok: kusur nerede bulunuyor
kusur sinifi    adet  bulundugu adim  gecikme (adim)  gecikme (saat)  yeniden is
yazim             14        tumlesim             2.0             2.1          45
tumlesim           5        tumlesim             2.0             3.4          16
surum              2           surum             3.0            20.5          15
isletim            2         isletim             4.0            56.5          13
```

Tablo hata bulma gecikmesinin neden iki birimde ölçülmesi gerektiğini gösterir. Yazım sınıfı on
dört kusur, eşli çalışma olmadığında **iki adım** sonra ve ortalama 2,1 saat sonra bulunur; bunlar
yerinde düzeltilebilecekken tümleşimi beklerler. Karşı uçta yalnız iki işletim kusuru vardır ama
gecikmeleri 56,5 saattir ve on üç saatlik yeniden iş üretirler — kusur başına 6,5 saat, yazım
sınıfının iki katı. Az sayıda ama geç bulunan kusur, çok sayıda ve erken bulunan kusurdan pahalıdır.

#### İki Ayarın Taranması

```js
// gecikme-taramasi.mjs — pratik.mjs'in yazdigi sonuclari okur; iki ayar ayri ayri taranir
import { readFileSync } from "node:fs";

const { SIKLIK, ORAN } = JSON.parse(readFileSync("pratik.json", "utf8"));
const SABIT = 0.5;
const tablo = (baslik, satir, ust) => {
  const yaz = (h) => console.log(h.map((c, i) => String(c).padStart(baslik[i][1])).join(""));
  if (ust) { console.log(); console.log(ust); }
  yaz(baslik.map((b) => b[0])); satir.forEach(yaz);
};

tablo([["tumlestirme", 13], ["olay", 6], ["gecikme (adim)", 16], ["gecikme (saat)", 16],
       ["yeniden is", 12], ["tumlesim bedeli", 17], ["toplam", 9]],
  SIKLIK.map((r) => [`${r.T} saat`, r.olay, r.gecikmeAdim.toFixed(2), r.gecikmeSaat.toFixed(1),
                     r.yeniden, r.tumlesimBedeli, r.toplam]),
  "tumlestirme sikligi (esli calisma yok):");

// SM29: siklastirmanin tek bedeli olay basina sabit maliyettir; basa bas noktasi asagida.
const a = SIKLIK[0], b = SIKLIK[1];
const basaBas = (b.yeniden + b.cakisma - a.yeniden - a.cakisma) / (a.olay - b.olay);
console.log(`\niki saatlik ritim ${a.olay} olay, dort saatlik ${b.olay} olay uretir; ` +
  `olay basina sabit maliyet ${SABIT} saatken iki saatlik ritim ${(b.toplam - a.toplam).toFixed(1)} saat one gecer.`);
console.log(`bu ustunluk olay basina sabit maliyet ${basaBas.toFixed(2)} saati asinca kaybolur.`);

tablo([["esli oran", 11], ["sure (saat)", 13], ["yazarken bulunan", 18], ["gecikme (adim)", 16],
       ["gecikme (saat)", 16], ["yeniden is", 12], ["is gucu", 9], ["toplam", 9]],
  ORAN.map((r) => [`%${(100 * r.oran).toFixed(0)}`, r.sure, `${r.esliBulunan}/${r.bulgu}`,
                   r.gecikmeAdim.toFixed(2), r.gecikmeSaat.toFixed(1), r.yeniden, r.isGucu, r.toplam]),
  "esli calisma orani (tumlestirme 4 saatte bir):");

// SM30: esli calismanin iki kisilik maliyeti kazanci asiyorsa, hangi carpanda basa bas gelir
const y = ORAN[0], z = ORAN[ORAN.length - 1];
const carpan = (z.isGucu - y.isGucu) / (y.yeniden - z.yeniden);
console.log(`\nesli calisma %100'de gecikmeyi ${y.gecikmeSaat.toFixed(1)} saatten ` +
  `${z.gecikmeSaat.toFixed(1)} saate, yeniden isi ${y.yeniden} saatten ${z.yeniden} saate indirir; ` +
  `karsiliginda is gucu ${y.isGucu} saatten ${z.isGucu} saate cikar ve is ${z.sure - y.sure} saat uzar.`);
console.log(`kusur basina yeniden is ${(y.yeniden / y.bulgu).toFixed(1)} saattir; ` +
  `esli calismanin karsiligini vermesi icin bu sayinin ${carpan.toFixed(1)} katina cikmasi gerekir.`);
```

```
tumlestirme sikligi (esli calisma yok):
  tumlestirme  olay  gecikme (adim)  gecikme (saat)  yeniden is  tumlesim bedeli   toplam
       2 saat    21            2.26             8.0          82             13.3    449.3
       4 saat    13            2.26             8.7          89             12.3    455.3
       8 saat     7            2.26            10.0          94             13.6    461.6
      16 saat     4            2.26            13.4         103             22.9    479.9
      40 saat     2            2.26            21.4         132             53.6    539.6

iki saatlik ritim 21 olay, dort saatlik 13 olay uretir; olay basina sabit maliyet 0.5 saatken iki saatlik ritim 6.0 saat one gecer.
bu ustunluk olay basina sabit maliyet 1.25 saati asinca kaybolur.

esli calisma orani (tumlestirme 4 saatte bir):
  esli oran  sure (saat)  yazarken bulunan  gecikme (adim)  gecikme (saat)  yeniden is  is gucu   toplam
         %0           50              0/23            2.26             8.7          89      354    455.3
        %25           62              4/23            1.91             7.8          69      443    523.8
        %50           73              7/23            1.65             6.3          59      530    601.9
        %75           85              9/23            1.48             5.3          50      615    677.5
       %100           90             14/23            1.04             4.7          35      708    755.8

esli calisma %100'de gecikmeyi 8.7 saatten 4.7 saate, yeniden isi 89 saatten 35 saate indirir; karsiliginda is gucu 354 saatten 708 saate cikar ve is 40 saat uzar.
kusur basina yeniden is 3.9 saattir; esli calismanin karsiligini vermesi icin bu sayinin 6.6 katina cikmasi gerekir.
```

#### İki Pratik, İki Ayrı Bileşen

İlk tablonun en dikkat çekici sütunu değişmeyendir. Tümleştirme iki saatten kırk saate seyrekleşse
de **adım cinsinden gecikme 2,26'da sabit kalır**: kusur yine aynı adımda bulunur, yalnız o adıma
varmak uzar. Saat cinsinden gecikme 8,0'dan 21,4'e, yeniden iş 82'den 132 saate çıkar. Kırk saatlik
ritimde tümleşim bedeli de 13,3'ten 53,6 saate fırlar, çünkü tek partide tümleşen kalem sayısı
arttıkça çakışma çifti karesel büyür. **Tümleştirmeyi sıklaştırmak bu modelde hiçbir yerde
kaybettirmez**; iki saatlik ritim dört saatliğe göre 6,0 saat öndedir ve bu üstünlük ancak olay
başına sabit maliyet 1,25 saati aşarsa kaybolur. Ölçülmesi gereken sayı budur: bir tümleştirme
olayı ne kadar sürüyor.

İkinci tablo tam tersini yapar. Eşli çalışma **adım cinsinden gecikmeye** dokunur — 2,26'dan 1,04'e
iner, çünkü on dört yazım kusurunun on dördü sıfırıncı adımda yakalanır ve hiç yeniden iş üretmez.
Yeniden iş 89 saatten 35 saate düşer. Bedeli ise başka hiçbir ayarda görülmeyen büyüklüktedir: iş
gücü 354 saatten **708 saate** çıkar, çünkü aynı işi iki kişi yapar ve iş kırk saat uzar, çünkü
sekiz kişi yarısı kadar kalemi aynı anda yürütür.

Aritmetik açıktır. 354 saatlik ek iş gücü 54 saatlik yeniden iş tasarrufu satın alır. Eşli
çalışmanın bu modelde karşılığını vermesi için kusur başına yeniden işin 3,9 saatten **6,6 katına**
çıkması gerekir. Bu çarpan hayalî değildir: işletim sınıfı kusurlar zaten kusur başına 6,5 saatte
seyreder ve bir kusurun işletime kaçması hâlinde yeniden iş bu modeldekinin çok üstüne çıkar. Yani
eşli çalışma, kusurun ucuz olduğu yerde pahalı bir alışkanlık, kusurun pahalı olduğu yerde ucuz bir
sigortadır — ve hangisinin geçerli olduğu ölçülebilir bir sorudur.

#### Özet

- Hata bulma gecikmesi iki birimde ölçüldü: adım cinsinden gecikme kusurun kaç aşama sonra
  göründüğünü, saat cinsinden gecikme o aşamaların ne kadar sürdüğünü verir.
- Dört saatlik tümleştirmede 14 yazım kusuru 2 adım ve 2,1 saat sonra bulunur; 2 işletim kusuru 4
  adım ve 56,5 saat sonra bulunur ve kusur başına 6,5 saatle en pahalı yeniden işi üretir.
- Tümleştirme sıklığı adım sayısını hiç değiştirmez (2,26'da sabit), saati değiştirir: 2 saatten 40
  saate çıkınca gecikme 8,0'dan 21,4 saate, yeniden iş 82'den 132 saate, tümleşim bedeli 13,3'ten
  53,6 saate çıkar.
- Sıklaştırmanın tek bedeli olay başına sabit maliyettir; 2 saatlik ritmin üstünlüğü ancak bu
  maliyet 1,25 saati aşarsa kaybolur.
- Eşli çalışma adım cinsinden gecikmeyi 2,26'dan 1,04'e, yeniden işi 89'dan 35 saate indirir, ama iş
  gücünü 354'ten 708 saate çıkarır ve işi 40 saat uzatır; başa baş için kusur başına yeniden işin
  6,6 katına çıkması gerekir.

#### Sonraki Adım

Beş ders sürecin biçimini seçti, akışı sınırladı, eşgüdüm bedelini saydı ve hata bulma gecikmesini
kısalttı. Hepsinin ortak bir kör noktası var. Bütün bu ölçümler işin **kimden kime geçtiğini** veri
olarak aldı: yaşam döngüsü modelinde adım sınırı, yinelemede biriktirme listesinin sahibi, akış
modelinde iş sınırının kapsadığı ekip, ölçekli düzende modüllerin hangi ekibe düştüğü. Her seferinde
o sınır girdiydi ve hiç sorgulanmadı. Oysa o sınır bir yerden geliyor: ekipler bir biçimde bölünmüş,
modüller bir biçimde paylaştırılmış ve iş kaleminin geçtiği her sınır aslında bir **ekip sınırıdır**.
Sonraki konu bu soruyu sorar — ekiplerin nasıl bölündüğü mimariyi ne kadar belirliyor ve iletişim
yapısı ile modül yapısı örtüşmediğinde bu beş derste sayılan bekleme, yeniden iş ve eşgüdüm turu ne
kadar büyüyor.

## Ekip ve Teslimat

Ekip sınırının mimari sınırla ilişkisi: iletişim yapısının modül yapısına yansıması, akış odaklı ekip düzenlerinin el değiştirme ve bekleme cinsinden karşılaştırılması, belirsizlik altında tahminin hata payı, kapsam değişikliğinin akışta yarattığı yeniden iş ve geliştirme ile işletim arasındaki sorumluluk sözleşmesinin devredilen ve devredilemeyen kalemleri.

### Conway Yasası

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/conway-yasasi

İletişim yapısının modül yapısına yansımasının ölçülmesi: aynı modül grafiğine iki ayrı ekip bölünmesinin bindirilmesi, modül başına ekip ve ekip sınırını geçen bağ sayımı, bu bağların iletişim mesafesine göre dağılımı, iletişim yolu olmayan ekipler arasında duran bağların bulunması ve aynı iş kalemi kümesinin iki bölünmedeki el değiştirme, bekleme ve yeniden iş sayıları.

Önceki konu sürecin biçimini seçti, akışı sınırladı ve hata bulma gecikmesini kısalttı. Bütün o
ölçümlerin ortak bir sessiz girdisi vardı: işin **kimden kime geçtiği** veri olarak alındı; o
sınırın nereden geldiği hiç sorulmadı. Bu ders o soruyu sorar.

**Conway yasası**, bir sistemi üreten kuruluşun iletişim yapısı ile ürettiği sistemin yapısı
arasında bir benzerlik olduğunu söyleyen terimdir. Terim tek başına ölçü vermez; ölçü iki
grafik yan yana konarak kurulur — **modül grafiği** (hangi modül hangi modüle bağımlıdır) ve
**iletişim grafiği** (hangi ekibin hangi ekiple düzenli bir kanalı vardır).

Aynı türden bir ithal grafiği daha önce başka amaçlarla okundu: katman kuralı denetlendi, sınır
ihlali sayıldı. **Buradaki sayım o değildir.** Grafiğe bindirilen şey kural değil **ekip
sınırıdır**. Through-line **bölgesel kütüphane ağıdır** ve kurgudur.

#### İki Grafik, Tek Kod Tabanı

**ET1 — kod tabanı on yedi modülden ve kırk üç bağımlılık bağından oluşur.** Gerekçe: örtüşme ancak
bağ sayısının ekip sayısından çok büyük olduğu bir grafikte anlam taşır.

**ET2 — bileşen odaklı bölünmede beş ekip vardır, her ekip bir teknik bileşenin sahibidir ve dört
düzenli kanal bulunur.** **ET3 — akış odaklı bölünmede altı ekip vardır, her ekip bir hizmet
akışının sahibidir ve dokuz kanal bulunur.** Gerekçe: iki bölünme aynı on yedi modülü paylaştırır,
yani **modül grafiği iki koşumda da bit bit aynıdır**; değişen tek şey sınırın yeridir.

**ET4 — iş yükü on iki kalemdir; her kalem modülleri işin izlediği sırayla listeler ve ilk modül
isteğin düştüğü yerdir.** **ET5 — bir modülün "değiştiren ekipleri" sahibi ile o modüle dokunan
kalemleri başlatan ekiplerin birleşimidir.** Gerekçe: kurumda kod herkese açıktır; kalemi başlatan
ekip gerektiğinde başka ekibin modülünde değişiklik yazar ve sahibinden gözden geçirme ister.

Aşağıdaki blok bir **modeldir**; gerçek bir kod tabanından okunmuş değildir.

```js
// kur.mjs — modul grafigi ile iletisim grafigi yan yana konur, ortusme olculur (model)
import { writeFileSync } from "node:fs";

// ET1 — 17 modul; "a: b c" satiri a modulunun b ve c modullerini ithal ettigini soyler
const ITHAL = {
  subeUcu: "oduncAkisi ucretAkisi rezervasyonAkisi ortakBicim",
  personelUcu: "uyelikAkisi oduncAkisi ucretAkisi ortakBicim",
  ceptenErisim: "oduncAkisi rezervasyonAkisi katalogKoprusu ortakBicim",
  oduncAkisi: "oduncKurali katalogKurali depoErisimi bildirimKuyrugu ortakBicim",
  ucretAkisi: "ucretKurali depoErisimi bildirimKuyrugu ortakBicim",
  uyelikAkisi: "uyelikKurali kimlikKoprusu depoErisimi ortakBicim",
  rezervasyonAkisi: "oduncKurali katalogKoprusu depoErisimi bildirimKuyrugu ortakBicim",
  oduncKurali: "ortakBicim", ucretKurali: "oduncKurali ortakBicim",
  katalogKurali: "ortakBicim", uyelikKurali: "ortakBicim",
  depoErisimi: "olayGunlugu ortakBicim", katalogKoprusu: "katalogKurali ortakBicim",
  kimlikKoprusu: "ortakBicim", bildirimKuyrugu: "olayGunlugu ortakBicim",
  olayGunlugu: "ortakBicim", ortakBicim: "",
};
const M = Object.keys(ITHAL);
const KENAR = Object.entries(ITHAL)
  .flatMap(([a, s]) => (s ? s.split(" ").map((b) => [a, b]) : []));

// ET2 — bilesen odakli bolunme: bes ekip, her ekip bir teknik bilesenin sahibi
const A = { ad: "A (bilesen odakli)", bolunme: {
  arayuz: "subeUcu personelUcu ceptenErisim",
  akis: "oduncAkisi ucretAkisi uyelikAkisi rezervasyonAkisi",
  kural: "oduncKurali ucretKurali katalogKurali uyelikKurali",
  altyapi: "depoErisimi katalogKoprusu kimlikKoprusu bildirimKuyrugu olayGunlugu",
  ortak: "ortakBicim" },
  kanal: "arayuz-akis akis-kural akis-altyapi kural-altyapi" };

// ET3 — akis odakli bolunme: alti ekip, her ekip bir hizmet akisinin sahibi
const B = { ad: "B (akis odakli)", bolunme: {
  deneyim: "subeUcu personelUcu ceptenErisim",
  odunc: "oduncAkisi oduncKurali rezervasyonAkisi depoErisimi",
  ucret: "ucretAkisi ucretKurali",
  uyelik: "uyelikAkisi uyelikKurali kimlikKoprusu",
  katalog: "katalogKurali katalogKoprusu",
  platform: "ortakBicim olayGunlugu bildirimKuyrugu" },
  kanal: "deneyim-odunc deneyim-ucret deneyim-uyelik odunc-ucret odunc-katalog " +
    "odunc-platform ucret-platform uyelik-platform katalog-platform" };

// ET4 — on iki is kalemi; moduller isin izledigi sirayla, ilki istegin dustugu yerdir
const KALEM = [
  ["gecikme ucreti orani", "ucretAkisi ucretKurali subeUcu ortakBicim"],
  ["rezervasyon iptali", "ceptenErisim rezervasyonAkisi oduncKurali bildirimKuyrugu"],
  ["uyelik hatirlatmasi", "uyelikAkisi uyelikKurali bildirimKuyrugu personelUcu"],
  ["katalog kaydinda alan", "katalogKoprusu katalogKurali ortakBicim ceptenErisim"],
  ["odunc suresi uzatma", "oduncAkisi oduncKurali subeUcu"],
  ["kimlikte ikinci adim", "kimlikKoprusu uyelikAkisi personelUcu ortakBicim"],
  ["ucret iadesi kaydi", "ucretAkisi depoErisimi olayGunlugu"],
  ["sube gecikme raporu", "personelUcu depoErisimi oduncAkisi"],
  ["bildirim metni bicimi", "bildirimKuyrugu ortakBicim"],
  ["rezervasyon sirasi", "ceptenErisim rezervasyonAkisi subeUcu"],
  ["odunc kurali istisnasi", "oduncKurali ucretKurali oduncAkisi ucretAkisi"],
  ["olay gunlugune alan", "olayGunlugu ortakBicim depoErisimi"],
];

function kur({ ad, bolunme, kanal }) {
  const sahip = {}, E = Object.keys(bolunme), kom = Object.fromEntries(E.map((e) => [e, []]));
  for (const [e, ms] of Object.entries(bolunme)) for (const m of ms.split(" ")) sahip[m] = e;
  for (const k of kanal.split(" ")) {
    const [x, y] = k.split("-");
    kom[x].push(y); kom[y].push(x);
  }
  const d = {};                                  // iletisim grafiginde en kisa yol; yol yoksa -1
  for (const s of E) {
    d[s] = Object.fromEntries(E.map((e) => [e, -1]));
    d[s][s] = 0;
    for (let q = [s]; q.length; ) {
      const u = q.shift();
      for (const v of kom[u]) if (d[s][v] < 0) { d[s][v] = d[s][u] + 1; q.push(v); }
    }
  }
  // ET5 — kod herkese acik: kalemi baslatan ekip gerektiginde baska ekibin modulunu degistirir
  const deg = Object.fromEntries(M.map((m) => [m, new Set([sahip[m]])]));
  for (const [, ms] of KALEM) for (const m of ms.split(" ")) deg[m].add(sahip[ms.split(" ")[0]]);
  return { ad, bolunme, sahip, d, deg: Object.fromEntries(M.map((m) => [m, [...deg[m]]])) };
}

const S = [kur(A), kur(B)];
writeFileSync("ag.json", JSON.stringify({ M, KENAR, KALEM, S }));

const olc = (s) => {
  const dis = KENAR.filter(([a, b]) => s.sahip[a] !== s.sahip[b]);
  const uzak = (f) => dis.filter(([a, b]) => f(s.d[s.sahip[a]][s.sahip[b]])).length;
  const ek = (n) => M.filter((m) => s.deg[m].length >= n).length;
  return {
    "ekip sinirini gecen modul bagi": `${dis.length}/${KENAR.length}`,
    "  iletisim mesafesi 1 olan ekipler arasi": uzak((u) => u === 1),
    "  iletisim mesafesi 2 olan ekipler arasi": uzak((u) => u === 2),
    "  ILETISIM YOLU OLMAYAN ekipler arasi": uzak((u) => u < 0),
    "birden cok ekibin degistirdigi modul": ek(2),
    "  uc ve daha cok ekibin degistirdigi modul": ek(3),
    "modul basina ekip ortalamasi":
      (M.reduce((t, m) => t + s.deg[m].length, 0) / M.length).toFixed(2),
  };
};

const O = S.map(olc);
console.log(`${M.length} modul, ${KENAR.length} bag, ${KALEM.length} is kalemi\n`);
console.log(`${"olcu".padEnd(42)}${S.map((s) => s.ad.padStart(20)).join("")}`);
for (const k of Object.keys(O[0]))
  console.log(`${k.padEnd(42)}${O.map((o) => String(o[k]).padStart(20)).join("")}`);
for (const s of S) {
  const c = {};
  for (const [a, b] of KENAR)
    if (s.d[s.sahip[a]][s.sahip[b]] < 0) {
      const k = `${s.sahip[a]}->${s.sahip[b]}`;
      c[k] = (c[k] ?? 0) + 1;
    }
  console.log(`\n${s.ad} — uc ve daha cok ekibin degistirdigi: ` +
    M.filter((m) => s.deg[m].length >= 3).map((m) => `${m}(${s.deg[m].length})`).join(", "));
  console.log(`  iletisim yolu olmayan ekipler arasinda duran bag: ` +
    (Object.keys(c).length ? Object.entries(c).map(([k, n]) => `${k} ${n}`).join(", ") : "yok"));
}
```

```
17 modul, 43 bag, 12 is kalemi

olcu                                        A (bilesen odakli)     B (akis odakli)
ekip sinirini gecen modul bagi                           40/43               32/43
  iletisim mesafesi 1 olan ekipler arasi                    23                  27
  iletisim mesafesi 2 olan ekipler arasi                     1                   5
  ILETISIM YOLU OLMAYAN ekipler arasi                       16                   0
birden cok ekibin degistirdigi modul                        15                  12
  uc ve daha cok ekibin degistirdigi modul                   6                   4
modul basina ekip ortalamasi                              2.24                2.06

A (bilesen odakli) — uc ve daha cok ekibin degistirdigi: personelUcu(3), oduncAkisi(3), oduncKurali(3), depoErisimi(3), bildirimKuyrugu(3), ortakBicim(3)
  iletisim yolu olmayan ekipler arasinda duran bag: arayuz->ortak 3, akis->ortak 4, kural->ortak 4, altyapi->ortak 5

B (akis odakli) — uc ve daha cok ekibin degistirdigi: subeUcu(3), depoErisimi(4), bildirimKuyrugu(3), ortakBicim(4)
  iletisim yolu olmayan ekipler arasinda duran bag: yok
```

#### Örtüşme Nerede Bozulur

Tablonun en keskin satırı ortadadır. Bileşen odaklı bölünmede **on altı modül bağı, iletişim
grafiğinde birbirine hiç bağlı olmayan iki ekip arasında durur** — kırk üç bağın üçte birinden
fazlası; akış odaklı bölünmede sayı sıfırdır.

Son çıktı satırları bu on altı bağın nereden geldiğini adlandırır: hepsi `ortak` ekibi ile diğer
dört ekip arasındadır. `ortak` tek modülün — `ortakBicim` — sahibidir ve hiçbir iletişim kanalı
yoktur; istekler ona yazılı bir sıradan ulaşır. Modül grafiğinde ise `ortakBicim` on altı modül
tarafından ithal edilir. **Kod tabanının en çok bağımlı olunan modülü, kimsenin konuşmadığı ekibin
elindedir.** İki grafik örtüşmediğinde modül grafiği kazanır: bağımlılık kodda durmaya devam eder ve
eksik kanal kendini o bağdan geçen her kalemin beklemesiyle gösterir.

Akış odaklı bölünme bu sayıyı sıfıra indirir ama başkasını büyütür. Bölünme A'da hiçbir modül üç
ekibi aşmaz; B'de `depoErisimi` ve `ortakBicim` dört ekip tarafından değiştirilir, çünkü akış odaklı
ekipler kalemlerini uçtan uca bitirmek için ortak modüllere doğrudan girer. **B'nin ortalaması daha
iyidir (2.06 karşı 2.24) ama en kötü modülü daha kötüdür.**

#### Aynı İşin İki Bölünmedeki Akışı

Bedeli görmek için aynı on iki kalem iki bölünmede koşturulur.

**ET6 — bir kalem dokunduğu her modül için bir tur çalışır; iki ekip arasındaki her geçiş, iletişim
mesafesi 1 ise 1, mesafe 2 ise 3, mesafe 3 ise 5, yol yoksa 8 tur bekler.** Gerekçe: doğrudan kanalı
olan iki ekip aynı turda konuşur; aracıya düşen her adım bir kuyruk daha bekletir.

**ET7 — üç yeniden iş nedeni sayılır: mesafesi 1'den büyük bir geçiş varsa `kisit` (geç öğrenilen
kısıt), kalem üç ve daha çok ekibin değiştirdiği bir modüle dokunuyorsa `sinir` (yanlış sınır),
kalem dört ve daha çok ekibe dağılıyorsa `bilgi` (eksik bilgi); her yeniden iş 2 tur çalışma ekler
ve en uzun beklemeyi bir kez daha ödetir.** Gerekçe: üç neden üç ayrı yapısal kusuru işaret eder —
kanal yokluğu, sahiplik belirsizliği, kapsamın yayılması.

```js
// akis.mjs — ayni on iki is kalemi iki bolunmede kosturulur: el degistirme, bekleme, yeniden is
import { readFileSync } from "node:fs";
const { KALEM, S } = JSON.parse(readFileSync("ag.json", "utf8"));

const BEKLE = [0, 1, 3, 5], YOK = 8;       // ET6: iletisim mesafesine gore bekleme turu
const kosum = (s) => KALEM.map(([ad, dizi]) => {
  const ms = dizi.split(" ");
  const sira = [...new Set(ms.map((m) => s.sahip[m]))];   // ekipler, isin izledigi sirayla
  let bek = 0, enUzun = 0, kopuk = 0;
  for (let j = 1; j < sira.length; j++) {
    const u = s.d[sira[j - 1]][sira[j]], b = u < 0 ? YOK : BEKLE[u];
    bek += b; enUzun = Math.max(enUzun, b);
    if (u < 0 || u >= 2) kopuk += 1;
  }
  const neden = [];                                                 // ET7: uc yeniden is nedeni
  if (kopuk) neden.push("kisit");                                   // gec ogrenilen kisit
  if (ms.some((m) => s.deg[m].length >= 3)) neden.push("sinir");    // yanlis sinir
  if (sira.length >= 4) neden.push("bilgi");                        // eksik bilgi
  const cal = ms.length + neden.length * 2;        // her yeniden is 2 tur calisma ekler
  const bekT = bek + neden.length * enUzun;        // ve en uzun beklemeyi bir kez daha odetir
  return { ad, ekip: sira.length, eld: sira.length - 1, cal, bek: bekT, akis: cal + bekT, neden };
});

const R = S.map((s) => ({ ad: s.ad, k: kosum(s) }));
const BAS = ["ekip", "eld", "bek", "akis"];
const hucre = (r) => [r.ekip, r.eld, r.bek, r.akis].map((x) => String(x).padStart(6)).join("") +
  `  ${(r.neden.join("+") || "-").padEnd(17)}`;
console.log(`${"is kalemi".padEnd(24)}${R.map((r) => r.ad.padEnd(43)).join("")}`.trimEnd());
console.log(`${"".padEnd(24)}${R.map(() =>
  BAS.map((h) => h.padStart(6)).join("") + `  ${"neden".padEnd(17)}`).join("")}`.trimEnd());
for (let i = 0; i < KALEM.length; i++)
  console.log(`${R[0].k[i].ad.padEnd(24)}${R.map((r) => hucre(r.k[i])).join("")}`.trimEnd());

const ozet = (r) => {
  const T = (f) => r.k.reduce((t, x) => t + f(x), 0);
  const n = (c) => r.k.filter((x) => x.neden.includes(c)).length;
  return {
    "el degistirme": T((x) => x.eld), "bekleme turu": T((x) => x.bek),
    "akis suresi (tur)": T((x) => x.akis),
    "akis suresinin bekleme payi": `%${(100 * T((x) => x.bek) / T((x) => x.akis)).toFixed(1)}`,
    "yeniden is (kalem / toplam)":
      `${r.k.filter((x) => x.neden.length).length} / ${T((x) => x.neden.length)}`,
    "  neden: gec ogrenilen kisit": n("kisit"),
    "  neden: yanlis sinir": n("sinir"), "  neden: eksik bilgi": n("bilgi"),
  };
};

const Z = R.map(ozet);
console.log(`\n${"toplam".padEnd(40)}${R.map((r) => r.ad.padStart(20)).join("")}`);
for (const k of Object.keys(Z[0]))
  console.log(`${k.padEnd(40)}${Z.map((z) => String(z[k]).padStart(20)).join("")}`);
```

```
is kalemi               A (bilesen odakli)                         B (akis odakli)
                          ekip   eld   bek  akis  neden              ekip   eld   bek  akis  neden
gecikme ucreti orani         4     3    36    46  kisit+sinir+bilgi     3     2    10    18  kisit+sinir
rezervasyon iptali           4     3     5    13  sinir+bilgi           3     2     3     9  sinir
uyelik hatirlatmasi          4     3    14    24  kisit+sinir+bilgi     3     2    10    18  kisit+sinir
katalog kaydinda alan        4     3    41    51  kisit+sinir+bilgi     3     2    10    18  kisit+sinir
odunc suresi uzatma          3     2    10    17  kisit+sinir           2     1     2     7  sinir
kimlikte ikinci adim         4     3    34    44  kisit+sinir+bilgi     3     2    10    18  kisit+sinir
ucret iadesi kaydi           2     1     2     7  sinir                 3     2     3     8  sinir
sube gecikme raporu          3     2    10    17  kisit+sinir           2     1     2     7  sinir
bildirim metni bicimi        2     1    24    30  kisit+sinir           1     0     0     4  sinir
rezervasyon sirasi           2     1     1     4  -                     2     1     2     7  sinir
odunc kurali istisnasi       2     1     2     8  sinir                 2     1     1     5  -
olay gunlugune alan          2     1    24    31  kisit+sinir           2     1     2     7  sinir

toplam                                    A (bilesen odakli)     B (akis odakli)
el degistirme                                             24                  17
bekleme turu                                             203                  55
akis suresi (tur)                                        292                 126
akis suresinin bekleme payi                            %69.5               %43.7
yeniden is (kalem / toplam)                          11 / 24             11 / 15
  neden: gec ogrenilen kisit                               8                   4
  neden: yanlis sinir                                     11                  11
  neden: eksik bilgi                                       5                   0
```

#### Bölünme Değiştiğinde Ne Değişmedi

Toplam tabloda üç sayı belirgin biçimde düşer ve bir sayı hiç kıpırdamaz.

Düşenler: el değiştirme 24'ten 17'ye, bekleme 203 turdan 55 tura, akış süresi 292'den 126'ya iner;
bekleme payı %69.5'ten %43.7'ye düşer. Önemli olan orantısızlıktır: **el değiştirme yalnız %29
azalırken bekleme %73 azalır.** Bedelin çoğu el değiştirmenin sayısında değil, el değiştirilen
ekibin uzaklığındadır. Bölünme A'da "bildirim metni biçimi" yalnız iki ekibe dokunur ve tek el
değiştirme içerir, ama o el değiştirme `ortak` ekibine yapıldığı için kalem otuz tura ulaşır —
dört ekibe dağılan "rezervasyon iptali" kaleminin iki katından fazla.

Kıpırdamayan sayı `sinir` nedenidir: iki bölünmede de on bir kalem bu nedenle yeniden işe girer.
A'da altı modül üç ekip tarafından değiştirilir; B'de bu sayı dörde iner ama iki modül dört ekibe
çıkar ve o ikisi (`depoErisimi`, `ortakBicim`) kalemlerin çoğunda görünür. **Ekip
sınırını taşımak paylaşılan modülü ortadan kaldırmaz; yalnız kimin beklediğini değiştirir.** Buna
karşılık `bilgi` nedeni 5'ten 0'a iner ve `kisit` 8'den 4'e düşer ama sıfırlanmaz; kalan dördü
`platform` ile `deneyim` arasındaki iki adımlık mesafeden gelir.

İki gözlem birlikte dersin sonucudur. İletişim yapısını değiştirmek modül grafiğine hiç dokunmadan
akış süresini iki kattan fazla kısaltabilir; ama ortak bağımlılığı yalnız iletişim yapısıyla çözmek
mümkün değildir. **Örtüşmeyi kurmanın iki yönü vardır ve bir bölünme kararı yalnız birini
kullanır.**

#### Özet

- Aynı 17 modüllü ve 43 bağlı grafiğe iki bölünme bindirildi: bileşen odaklı 5 ekip (4 kanal) ve
  akış odaklı 6 ekip (9 kanal); modül grafiği iki koşumda da değişmedi.
- Bileşen odaklı bölünmede 40/43 bağ ekip sınırını geçer ve bunların **16'sı iletişim grafiğinde
  hiç yolu olmayan ekipler arasında** durur; akış odaklıda sınırı geçen bağ 32'ye iner ve yolu
  olmayan ekip çifti kalmaz.
- On altı kopuk bağın hepsi tek modülün etrafındadır: 16 modülün ithal ettiği `ortakBicim`, hiçbir
  kanalı olmayan tek modüllük bir ekibin elindedir.
- Aynı 12 iş kalemi iki bölünmede koşturulduğunda el değiştirme 24'ten 17'ye, bekleme 203 turdan
  55 tura, akış süresi 292'den 126'ya iner; bekleme payı %69.5'ten %43.7'ye düşer.
- Bekleme %73, el değiştirme yalnız %29 azalır: bedel el değiştirmenin sayısında değil, karşı
  ekibin iletişim grafiğindeki uzaklığındadır.
- `sinir` yeniden iş nedeni iki bölünmede de 11 kalemde görülür; akış odaklı bölünme en çok
  paylaşılan modülü 3 ekipten 4 ekibe çıkarır. Paylaşılan modüldeki çekişme ekip sınırı taşınarak
  yok edilemez.

#### Sonraki Adım

Bu dersin ikinci bölünmesi "akış odaklı" adıyla anıldı ama yalnız tek bir özelliğiyle kullanıldı:
her ekip bir hizmet akışının sahibidir. Sayılar bu özelliğin akış süresini iki kattan fazla
kısalttığını gösterdi — ve bir şeyi hiç ölçmedi: **o ekiplerin ne kadar yük taşıdığını**. Sonraki
ders bu yükü sayar: aynı iş kalemi kümesi üç ayrı ekip düzeninde koşturulur ve el değiştirme,
bekleme, yeniden iş sayılarının yanına ekip başına **bilişsel yük** eklenir — sahip olunan modül ve
bağımlı olunan dış arayüz sayısı. Akış odaklı düzenin kazandığı yer bu dersin tablosunda görüldü;
kaybettiği yer orada görülecek.

### Ekip Topolojileri

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/ekip-topolojileri

Akış odaklı ekip düzenlerinin ölçülmesi: aynı modül grafiği ve aynı iş kalemi kümesi bileşen odaklı, akış odaklı ve karma üç ekip düzeninde koşturulur; el değiştirme, bekleme ve yeniden iş sayılarının yanına ekip başına bilişsel yük, dış talep, yinelenen uzmanlık ve ortak bileşenin darboğaza dönüşmesi eklenir.

Önceki ders iki ekip bölünmesini aynı modül grafiği üzerinde karşılaştırdı ve akış odaklı bölünmenin
akış süresini iki kattan fazla kısalttığını saydı. O tabloda bir sütun yoktu: **ekiplerin taşıdığı
yük**. Akış odaklı bir ekip kalemini uçtan uca bitirebilmek için sahip olduğu modüllerin yanında
bağımlı olduğu dış arayüzleri de bilmek zorundadır.

**Bilişsel yük**, bir ekibin işini yapabilmek için aynı anda zihninde tutmak zorunda olduğu şeyin
büyüklüğüdür; burada iki sayıyla kurulur: ekibin **sahip olduğu modül** sayısı ve modüllerinin
**dışarıdan ithal ettiği modül** sayısı. Aynı on iki iş kalemi üç düzende koşturulur — bileşen
odaklı, akış odaklı ve karma. Through-line **bölgesel kütüphane ağıdır** ve kurgudur.

#### Üçüncü Düzen ve Yük Ölçüsü

**ET8 — önceki dersin on yedi modüllü grafiği, iki bölünmesi ve on iki iş kalemi değişmeden
kullanılır.** Gerekçe: üç düzen ancak aynı grafik ve aynı iş yükü üzerinde karşılaştırılabilir.

**ET9 — karma düzende yedi ekip vardır: üç akış ekibi, bir arayüz, bir kural, bir köprü ve bir
platform ekibi; on iki kanal bulunur.** Gerekçe: karma düzen alan bilgisini akışa, teknik bilgiyi
ortak ekibe verme girişimidir; ekip sayısı arttığı için kanal sayısı da artar.

**ET10 — bir ekibin bilişsel yükü, sahip olduğu modül sayısı ile modüllerinin dışarıdan ithal ettiği
ayrık modül sayısının toplamıdır.** **ET11 — bir ekibin dış talebi, başka bir ekibin başlattığı ve
o ekibin modüllerine dokunan kalem sayısıdır.** Gerekçe: yük ekibin *bildiği* şeyi, dış talep ise
ekibe *başkasından gelen* işi ölçer; bir ekipte biri düşükken diğeri yüksek olabilir.

```js
// duzen.mjs — ayni modul grafigi ve ayni is kalemleri uc ekip duzeninde kosturulur (model)
import { writeFileSync } from "node:fs";

// ET8 — onceki dersin 17 modullu grafigi ve 12 is kalemi degismeden kullanilir
const ITHAL = {
  subeUcu: "oduncAkisi ucretAkisi rezervasyonAkisi ortakBicim",
  personelUcu: "uyelikAkisi oduncAkisi ucretAkisi ortakBicim",
  ceptenErisim: "oduncAkisi rezervasyonAkisi katalogKoprusu ortakBicim",
  oduncAkisi: "oduncKurali katalogKurali depoErisimi bildirimKuyrugu ortakBicim",
  ucretAkisi: "ucretKurali depoErisimi bildirimKuyrugu ortakBicim",
  uyelikAkisi: "uyelikKurali kimlikKoprusu depoErisimi ortakBicim",
  rezervasyonAkisi: "oduncKurali katalogKoprusu depoErisimi bildirimKuyrugu ortakBicim",
  oduncKurali: "ortakBicim", ucretKurali: "oduncKurali ortakBicim",
  katalogKurali: "ortakBicim", uyelikKurali: "ortakBicim",
  depoErisimi: "olayGunlugu ortakBicim", katalogKoprusu: "katalogKurali ortakBicim",
  kimlikKoprusu: "ortakBicim", bildirimKuyrugu: "olayGunlugu ortakBicim",
  olayGunlugu: "ortakBicim", ortakBicim: "",
};
const M = Object.keys(ITHAL);
const KENAR = Object.entries(ITHAL)
  .flatMap(([a, s]) => (s ? s.split(" ").map((b) => [a, b]) : []));
const KALEM = [
  ["gecikme ucreti orani", "ucretAkisi ucretKurali subeUcu ortakBicim"],
  ["rezervasyon iptali", "ceptenErisim rezervasyonAkisi oduncKurali bildirimKuyrugu"],
  ["uyelik hatirlatmasi", "uyelikAkisi uyelikKurali bildirimKuyrugu personelUcu"],
  ["katalog kaydinda alan", "katalogKoprusu katalogKurali ortakBicim ceptenErisim"],
  ["odunc suresi uzatma", "oduncAkisi oduncKurali subeUcu"],
  ["kimlikte ikinci adim", "kimlikKoprusu uyelikAkisi personelUcu ortakBicim"],
  ["ucret iadesi kaydi", "ucretAkisi depoErisimi olayGunlugu"],
  ["sube gecikme raporu", "personelUcu depoErisimi oduncAkisi"],
  ["bildirim metni bicimi", "bildirimKuyrugu ortakBicim"],
  ["rezervasyon sirasi", "ceptenErisim rezervasyonAkisi subeUcu"],
  ["odunc kurali istisnasi", "oduncKurali ucretKurali oduncAkisi ucretAkisi"],
  ["olay gunlugune alan", "olayGunlugu ortakBicim depoErisimi"],
];

const DUZEN = [
  { ad: "bilesen odakli", bolunme: {                        // ET8: onceki dersin bolunme A'si
    arayuz: "subeUcu personelUcu ceptenErisim",
    akis: "oduncAkisi ucretAkisi uyelikAkisi rezervasyonAkisi",
    kural: "oduncKurali ucretKurali katalogKurali uyelikKurali",
    altyapi: "depoErisimi katalogKoprusu kimlikKoprusu bildirimKuyrugu olayGunlugu",
    ortak: "ortakBicim" },
    kanal: "arayuz-akis akis-kural akis-altyapi kural-altyapi" },
  { ad: "akis odakli", bolunme: {                           // ET8: onceki dersin bolunme B'si
    deneyim: "subeUcu personelUcu ceptenErisim",
    odunc: "oduncAkisi oduncKurali rezervasyonAkisi depoErisimi",
    ucret: "ucretAkisi ucretKurali",
    uyelik: "uyelikAkisi uyelikKurali kimlikKoprusu",
    katalog: "katalogKurali katalogKoprusu",
    platform: "ortakBicim olayGunlugu bildirimKuyrugu" },
    kanal: "deneyim-odunc deneyim-ucret deneyim-uyelik odunc-ucret odunc-katalog " +
      "odunc-platform ucret-platform uyelik-platform katalog-platform" },
  { ad: "karma", bolunme: {                                 // ET9: akis ekipleri + ortak bilesen
    deneyim: "subeUcu personelUcu ceptenErisim",
    odunc: "oduncAkisi rezervasyonAkisi",
    ucret: "ucretAkisi", uyelik: "uyelikAkisi",
    kural: "oduncKurali ucretKurali katalogKurali uyelikKurali",
    kopru: "depoErisimi katalogKoprusu kimlikKoprusu",
    platform: "ortakBicim olayGunlugu bildirimKuyrugu" },
    kanal: "deneyim-odunc deneyim-ucret deneyim-uyelik odunc-kural ucret-kural uyelik-kural " +
      "odunc-kopru uyelik-kopru kural-kopru kural-platform kopru-platform deneyim-platform" },
];

function kur({ ad, bolunme, kanal }) {
  const sahip = {}, E = Object.keys(bolunme), kom = Object.fromEntries(E.map((e) => [e, []]));
  for (const [e, ms] of Object.entries(bolunme)) for (const m of ms.split(" ")) sahip[m] = e;
  for (const k of kanal.split(" ")) {
    const [x, y] = k.split("-");
    kom[x].push(y); kom[y].push(x);
  }
  const d = {};
  for (const s of E) {
    d[s] = Object.fromEntries(E.map((e) => [e, -1]));
    d[s][s] = 0;
    for (let q = [s]; q.length; ) {
      const u = q.shift();
      for (const v of kom[u]) if (d[s][v] < 0) { d[s][v] = d[s][u] + 1; q.push(v); }
    }
  }
  const deg = Object.fromEntries(M.map((m) => [m, new Set([sahip[m]])]));
  for (const [, ms] of KALEM) for (const m of ms.split(" ")) deg[m].add(sahip[ms.split(" ")[0]]);
  // ET10 — bilissel yuk: sahip olunan modul + disaridan ithal edilen modul (dis arayuz)
  const yuk = Object.fromEntries(E.map((e) => [e, { sahip: bolunme[e].split(" ").length,
    disArayuz: new Set(), disEkip: new Set(), disTalep: 0 }]));
  for (const [a, b] of KENAR) if (sahip[a] !== sahip[b]) {
    yuk[sahip[a]].disArayuz.add(b);
    yuk[sahip[a]].disEkip.add(sahip[b]);
  }
  // ET11 — dis talep: baska ekibin baslattigi ve bu ekibin modulune dokunan kalem
  for (const [, ms] of KALEM) {
    const dizi = ms.split(" "), bas = sahip[dizi[0]];
    for (const e of new Set(dizi.map((m) => sahip[m]))) if (e !== bas) yuk[e].disTalep += 1;
  }
  return { ad, kanalSayisi: kanal.split(" ").length, bolunme, sahip, d, deg, yuk, E };
}

const D = DUZEN.map(kur);
writeFileSync("duzen.json", JSON.stringify({ M, KENAR, KALEM, D: D.map((x) =>
  ({ ...x, deg: Object.fromEntries(M.map((m) => [m, [...x.deg[m]]])) })) }));

const orta = (v) => `${v[0]} / ${v[(v.length - 1) >> 1]} / ${v[v.length - 1]}`;
console.log(`${"duzen".padEnd(16)}${"ekip".padStart(6)}${"kanal".padStart(7)}` +
  `${"sahip olunan modul".padStart(22)}${"bilissel yuk".padStart(22)}`);
console.log(`${"".padEnd(29)}${"en az/ortanca/en cok".padStart(22)}${"en az/ortanca/en cok".padStart(22)}`);
for (const x of D) {
  const mod = x.E.map((e) => x.yuk[e].sahip).sort((a, b) => a - b);
  const yk = x.E.map((e) => x.yuk[e].sahip + x.yuk[e].disArayuz.size).sort((a, b) => a - b);
  console.log(`${x.ad.padEnd(16)}${String(x.E.length).padStart(6)}` +
    `${String(x.kanalSayisi).padStart(7)}${orta(mod).padStart(22)}${orta(yk).padStart(22)}`);
}

for (const x of D) {
  console.log(`\n${x.ad} — ekip basina bilissel yuk`);
  console.log(`${"ekip".padEnd(12)}${"sahip".padStart(7)}${"dis arayuz".padStart(12)}` +
    `${"dis ekip".padStart(10)}${"yuk".padStart(6)}${"dis talep".padStart(11)}`);
  for (const e of x.E)
    console.log(`${e.padEnd(12)}${String(x.yuk[e].sahip).padStart(7)}` +
      `${String(x.yuk[e].disArayuz.size).padStart(12)}${String(x.yuk[e].disEkip.size).padStart(10)}` +
      `${String(x.yuk[e].sahip + x.yuk[e].disArayuz.size).padStart(6)}` +
      `${String(x.yuk[e].disTalep).padStart(11)}`);
}
```

```
duzen             ekip  kanal    sahip olunan modul          bilissel yuk
                               en az/ortanca/en cok  en az/ortanca/en cok
bilesen odakli       5      4             1 / 4 / 5            1 / 7 / 13
akis odakli          6      9             2 / 3 / 4             3 / 5 / 9
karma                7     12             1 / 3 / 4             3 / 5 / 9

bilesen odakli — ekip basina bilissel yuk
ekip          sahip  dis arayuz  dis ekip   yuk  dis talep
arayuz            3           6         3     9          5
akis              4           9         3    13          5
kural             4           1         1     5          5
altyapi           5           2         2     7          4
ortak             1           0         0     1          5

akis odakli — ekip basina bilissel yuk
ekip          sahip  dis arayuz  dis ekip   yuk  dis talep
deneyim           3           6         5     9          5
odunc             4           5         2     9          5
ucret             2           4         2     6          1
uyelik            3           2         2     5          0
katalog           2           1         1     3          0
platform          3           0         0     3          6

karma — ekip basina bilissel yuk
ekip          sahip  dis arayuz  dis ekip   yuk  dis talep
deneyim           3           6         5     9          5
odunc             2           6         3     8          4
ucret             1           4         3     5          1
uyelik            1           4         3     5          1
kural             4           1         1     5          5
kopru             3           3         2     6          3
platform          3           0         0     3          6
```

#### Yükün Dağılımı

İlk tablo bileşen odaklı düzenin sorununu ortaya koyar: yük en az 1, en çok 13'tür. `akis` ekibi
dört modüle sahiptir ama dokuz dış arayüze bağımlıdır; `ortak` ekibi tek modüle sahiptir ve hiçbir
dış arayüze bağımlı değildir. **Aynı kuruluşta bir ekip on üç şeyi, başka bir ekip bir şeyi bilmek
zorundadır.** Akış odaklı ve karma düzenlerde aralık 3–9'a iner.

Dengelenmenin nasıl olduğu ikinci tabloda görünür. `akis` ekibinin dokuz dış arayüzü üç ekibe
bölünür: `odunc` beş, `ucret` dört, `uyelik` iki dış arayüze bağımlıdır. Yük yok olmadı, **bölündü**
— ve bölünme işe yarar, çünkü her akış ekibi kendi alanının kuralını da sahiplenir: `odunc` ekibi
`oduncKurali` modülünü içeride tutar ve o modül artık dış arayüz sayılmaz.

Dış talep sütunu ters yönde okunur. Akış odaklı düzende `platform` ekibinin bilişsel yükü üçtür —
en düşük değerlerden biri — ama **dış talebi altıdır**. Yükü en hafif olan ekip, işin en çok geçtiği
ekiptir.

#### Akış Sayıları ve Yinelenen Uzmanlık

İkinci koşum üç düzeni akış cinsinden karşılaştırır ve iki yeni sayı ekler.

**ET12 — bir modülün yinelenen uzmanlığı, o modülü sahibi olmadığı halde ithal eden ekip
sayısıdır.** Gerekçe: bir modülü ithal eden her ekip onun arayüzünü öğrenmek zorundadır; aynı bilgi
kaç ekipte tekrarlanıyorsa uzmanlık o kadar yinelenmiştir.

**ET13 — darboğaz, en çok dış talep alan ekiptir; o ekibin modüllerine dokunan yeniden iş kalemleri
ayrıca sayılır.** Gerekçe: bedelin nerede toplandığı ancak bu iki sayı birlikte okunarak görülür.

```js
// akis2.mjs — uc duzende akis sayilari ve yinelenen uzmanlik
import { readFileSync } from "node:fs";
const { M, KENAR, KALEM, D } = JSON.parse(readFileSync("duzen.json", "utf8"));

const BEKLE = [0, 1, 3, 5], YOK = 8;      // ET6'nin bekleme cetveli degismeden kullanilir
const kosum = (x) => KALEM.map(([ad, dizi]) => {
  const ms = dizi.split(" "), sira = [...new Set(ms.map((m) => x.sahip[m]))];
  let bek = 0, enUzun = 0, kopuk = 0;
  for (let j = 1; j < sira.length; j++) {
    const u = x.d[sira[j - 1]][sira[j]], b = u < 0 ? YOK : BEKLE[u];
    bek += b; enUzun = Math.max(enUzun, b);
    if (u < 0 || u >= 2) kopuk += 1;
  }
  const neden = [];
  if (kopuk) neden.push("kisit");
  if (ms.some((m) => x.deg[m].length >= 3)) neden.push("sinir");
  if (sira.length >= 4) neden.push("bilgi");
  const cal = ms.length + neden.length * 2, bekT = bek + neden.length * enUzun;
  return { ad, ekip: sira.length, eld: sira.length - 1, cal, bek: bekT, akis: cal + bekT, neden };
});

const R = D.map((x) => ({ ad: x.ad, k: kosum(x) }));
const T = (r, f) => r.k.reduce((t, y) => t + f(y), 0);
const n = (r, c) => r.k.filter((y) => y.neden.includes(c)).length;
console.log(`${"duzen".padEnd(16)}${"el deg.".padStart(9)}${"bekleme".padStart(9)}` +
  `${"akis".padStart(7)}${"bekleme payi".padStart(14)}${"yen. is".padStart(9)}` +
  `${"kisit".padStart(7)}${"sinir".padStart(7)}${"bilgi".padStart(7)}${"tek ekip".padStart(10)}`);
for (const r of R)
  console.log(`${r.ad.padEnd(16)}${String(T(r, (y) => y.eld)).padStart(9)}` +
    `${String(T(r, (y) => y.bek)).padStart(9)}${String(T(r, (y) => y.akis)).padStart(7)}` +
    `${`%${(100 * T(r, (y) => y.bek) / T(r, (y) => y.akis)).toFixed(1)}`.padStart(14)}` +
    `${String(T(r, (y) => y.neden.length)).padStart(9)}${String(n(r, "kisit")).padStart(7)}` +
    `${String(n(r, "sinir")).padStart(7)}${String(n(r, "bilgi")).padStart(7)}` +
    `${String(r.k.filter((y) => y.ekip === 1).length).padStart(10)}`);

// ET12 — yinelenen uzmanlik: bir modulu sahibi olmadigi halde ithal eden ekip sayisi
const bagimli = (x, m) => new Set(KENAR.filter(([a, b]) => b === m && x.sahip[a] !== x.sahip[m])
  .map(([a]) => x.sahip[a])).size;
const ilgi = M.filter((m) => D.some((x) => bagimli(x, m) >= 2));
console.log(`\n${"modul".padEnd(18)}${D.map((x) => x.ad.padStart(16)).join("")}   sahibi (uc duzende)`);
for (const m of ilgi)
  console.log(`${m.padEnd(18)}${D.map((x) => String(bagimli(x, m)).padStart(16)).join("")}` +
    `   ${D.map((x) => x.sahip[m]).join(" / ")}`);
console.log(`${"TOPLAM ekip-modul".padEnd(18)}` +
  `${D.map((x) => String(M.reduce((t, m) => t + bagimli(x, m), 0)).padStart(16)).join("")}`);

// ET13 — darbogaz: en cok dis talep alan ekip ve o ekibin modullerine dokunan yeniden is
console.log(`\n${"duzen".padEnd(16)}${"en cok dis talep alan ekip".padStart(28)}` +
  `${"dis talep".padStart(11)}${"sahip".padStart(7)}${"o ekibin moduluyle gelen yen. is".padStart(34)}`);
D.forEach((x, i) => {
  const e = x.E.reduce((a, b) => (x.yuk[a].disTalep >= x.yuk[b].disTalep ? a : b));
  const ykl = R[i].k.filter((y, j) => y.neden.length &&
    KALEM[j][1].split(" ").some((m) => x.sahip[m] === e)).length;
  console.log(`${x.ad.padEnd(16)}${e.padStart(28)}${String(x.yuk[e].disTalep).padStart(11)}` +
    `${String(x.yuk[e].sahip).padStart(7)}${String(ykl).padStart(34)}`);
});
```

```
duzen             el deg.  bekleme   akis  bekleme payi  yen. is  kisit  sinir  bilgi  tek ekip
bilesen odakli         24      203    292         %69.5       24      8     11      5         0
akis odakli            17       55    126         %43.7       15      4     11      0         1
karma                  25       78    163         %47.9       22      5     12      5         1

modul               bilesen odakli     akis odakli           karma   sahibi (uc duzende)
katalogKurali                    2               1               2   kural / katalog / kural
depoErisimi                      1               2               3   altyapi / odunc / kopru
katalogKoprusu                   2               2               2   altyapi / katalog / kopru
bildirimKuyrugu                  1               2               2   altyapi / platform / platform
ortakBicim                       4               5               6   ortak / platform / platform
TOPLAM ekip-modul               18              18              24

duzen             en cok dis talep alan ekip  dis talep  sahip  o ekibin moduluyle gelen yen. is
bilesen odakli                        arayuz          5      3                                 7
akis odakli                         platform          6      3                                 8
karma                               platform          6      3                                 8
```

#### Akış Odaklı Düzenin Kaybettiği Yer

Akış sayılarında akış odaklı düzen üç düzenin de önündedir: en az el değiştirme (17), en az bekleme
(55 tur), en kısa akış (126 tur), en az yeniden iş (15). Karma düzen beklenenin tersini yapar —
**yirmi beş el değiştirmeyle üç düzenin en yükseğidir**, bileşen odaklının yirmi dördünü de aşar.
Nedeni yapısaldır: karma düzen akışı böldüğü gibi kuralı, köprüyü ve platformu da ayrı ekiplere
verir, yani bir kalem hem akış sınırını hem katman sınırını geçer. `sinir` nedeninde de en
yüksektir (12).

Akış odaklı düzenin kaybettiği yer ikinci tablodadır. **Toplam ekip-modül bağımlılık çifti bileşen
odaklı düzende 18, akış odaklı düzende de 18'dir** — akış odaklı düzen yinelenen uzmanlığı hiç
azaltmaz. Tek tek satırlarda ise dağılım kayar: `depoErisimi` bir ekip yerine iki, `bildirimKuyrugu`
bir yerine iki, `ortakBicim` dört yerine beş ekip tarafından dışarıdan ithal edilir. Ortak biçim
modülünü bilmek zorunda olan ekip sayısı artmıştır, çünkü her akış ekibi kendi kalemini uçtan uca
bitirirken o modülün arayüzüne çarpar. Karma düzende toplam 24'e çıkar ve `ortakBicim` altı ekibe
ulaşır: düzen ne kadar bölünürse yinelenen uzmanlık o kadar artar.

Üçüncü tablo ortak bileşenin ne olduğunu adlandırır. Akış odaklı ve karma düzenlerde darboğaz
`platform` ekibidir: üç modüle sahiptir, altı dış talep alır ve **yeniden işe giren kalemlerin
sekizi onun bir modülüne dokunur**. Ortak bileşen sahipsiz değildir — sahibi vardır, ama kendi
akışına ait bir kalem üretmez, yalnız başkasının kalemini bekletir. Bileşen odaklı düzende aynı
rolü `arayuz` ekibi oynar (beş dış talep, yedi yeniden iş kalemi), fakat orada darboğazın yükü de
yüksektir (9); akış odaklı düzende üçtür. **Düzen değiştikçe darboğazın yeri değişir, varlığı
değişmez.**

Akış odaklı düzen akış sayılarını ve yük dengesini birlikte iyileştirir; bunu yinelenen uzmanlığı
azaltmadan, hatta ortak modüllerde artırarak yapar. Karma düzen yükü aynı ölçüde dengeler ama el
değiştirmeyi ve yinelenen uzmanlığı en kötü noktaya çıkarır.

#### Özet

- Aynı grafik ve aynı 12 kalem üç düzende koşturuldu: bileşen odaklı (5 ekip, 4 kanal), akış odaklı
  (6 ekip, 9 kanal) ve karma (7 ekip, 12 kanal).
- Bileşen odaklı düzende bilişsel yük 1 ile 13 arasında dağılır; `akis` ekibi 4 modüle sahipken
  9 dış arayüze bağımlıdır. Akış odaklı ve karma düzenlerde aralık 3–9'a iner.
- Akış sayılarında akış odaklı düzen önde: el değiştirme 17, bekleme 55 tur, akış 126 tur, yeniden
  iş 15. Karma düzen 25 el değiştirmeyle üç düzenin en yükseğidir, bileşen odaklının 24'ünü de aşar.
- Yinelenen uzmanlıkta akış odaklı düzenin kazancı yoktur: toplam ekip-modül bağımlılık çifti
  bileşen odaklıda da akış odaklıda da 18, karma düzende 24'tür.
- `ortakBicim` modülünü dışarıdan ithal eden ekip sayısı üç düzende sırasıyla 4, 5 ve 6'dır; düzen
  bölündükçe ortak biçimi bilmek zorunda olan ekip sayısı artar.
- Akış odaklı ve karma düzende darboğaz `platform` ekibidir: bilişsel yükü 3, dış talebi 6 ve
  yeniden işe giren kalemlerin 8'i onun modüllerine dokunur. Darboğazın yeri değişir, varlığı
  değişmez.

#### Sonraki Adım

Bu iki derste ekip sınırının nereden geçtiği ölçüldü ve bir çeyreklik iş yükü üç düzende
koşturuldu. Her koşumda iş kaleminin dokunduğu modüller **baştan biliniyordu**. Gerçekte bu bilgi
kalem başlarken yoktur: bir kalemin ne kadar süreceği ancak tahmin edilir ve tahmin ilerledikçe
daralır. Sonraki ders tahmini ölçer — bir tahmin kümesi gerçekleşen sürelerle karşılaştırılır, hata
payı ve belirsizliğin aşama aşama daralması sayılır, tek kalem tahmini ile toplam tahmininin neden
farklı davrandığı gösterilir.

### Tahmin ve Planlama

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/tahmin-ve-planlama

Belirsizlik altında iş kalemi süresinin tahmini: üç aşamada üretilen tahminlerin gerçekleşen akış süresiyle karşılaştırılması, hata payı ile yanlılığın ayrılması, belirsizlik konisinin aşama aşama daralması, tahmine göre kurulan planın kaç kalemde tuttuğu ve tek kalem tahmini ile toplam tahmini arasındaki farkın hataların birbirini götürüp götürmemesiyle açıklanması.

Önceki iki derste her iş kaleminin dokunduğu modüller baştan biliniyordu. El değiştirme, bekleme ve
yeniden iş bu bilgiden hesaplandı. Gerçekte bir kalem başlarken bu bilgi yoktur: kalemin ne kadar
süreceği **tahmin edilir** ve tahmin iş ilerledikçe değişir.

Mimari kararların etkisi daha önce tahmin edilmişti; burada tahmin edilen şey **iş kaleminin
süresidir** ve ölçüsü turdur. Ders bir tahmin kümesini gerçekleşen sürelerle
karşılaştırır ve dört sayı üretir: hata payı, hatanın yönü, **belirsizlik konisinin** aşama aşama
daralması ve tahmine göre kurulan planın kaç kalemde tuttuğu. Sonra tek kalem tahmini ile toplam
tahmininin neden farklı davrandığı sayılır. Through-line **bölgesel kütüphane ağıdır** ve kurgudur.

#### Tahmin Edilen ile Gerçekleşen

**ET15 — önceki iki dersin akış odaklı düzeni ve on iki iş kalemi değişmeden kullanılır.** **ET16 —
bir kalemin gerçekleşen süresi, önceki derslerin akış modelinden gelir: çalışma turu artı bekleme
turu artı yeniden işin eklediği turlar.** Gerekçe: tahminin karşılaştırılacağı "gerçek" bir yerden
gelmelidir; burada o yer daha önce koşturulmuş ve sayıları basılmış modeldir, yani gerçekleşen süre
bu ders için bağımsız bir veri değil, aynı modelin çıktısıdır.

**ET17 — sapma bir üreteçten çekilir; üreteç doğrusal eşlemedir ve tohumu `20250401` olarak
görünürdür.** Gerekçe: tahmin hatasının rastgele bir bileşeni vardır ve koşum tekrarlanabilir
olmalıdır.

**ET18 — üç tahmin aşaması vardır. Aşama 1'de yalnız kalemin başlığı bilinir ve dokunulacak modül
sayısı ±%80 sapmayla tahmin edilir. Aşama 2'de kalem incelenmiştir, dokunulan modüller tam bilinir,
sapma ±%30'dur. Aşama 3'te ilk ekip işini bitirmiştir; çalışma turu ve kaç ekibe dağılacağı
bilinir, her el değiştirme için bir tur bekleme eklenir, sapma ±%10'dur.** Gerekçe: aşamalar
belirsizliğin doğal olarak azaldığı üç ana durağı temsil eder; her aşamada tahmincinin **ne
bildiği** ayrıca yazılıdır, çünkü koninin daralması bilginin artmasından gelir.

```js
// tahmin.mjs — uc asamali tahmin, ayni kalemlerin gerceklesen akis suresiyle karsilastirilir (model)
import { writeFileSync } from "node:fs";

// ET15 — onceki iki dersin akis odakli duzeni ve on iki kalemi degismeden kullanilir
const BOLUNME = {
  deneyim: "subeUcu personelUcu ceptenErisim",
  odunc: "oduncAkisi oduncKurali rezervasyonAkisi depoErisimi",
  ucret: "ucretAkisi ucretKurali",
  uyelik: "uyelikAkisi uyelikKurali kimlikKoprusu",
  katalog: "katalogKurali katalogKoprusu",
  platform: "ortakBicim olayGunlugu bildirimKuyrugu",
};
const KANAL = "deneyim-odunc deneyim-ucret deneyim-uyelik odunc-ucret odunc-katalog " +
  "odunc-platform ucret-platform uyelik-platform katalog-platform";
const KALEM = [
  ["gecikme ucreti orani", "ucretAkisi ucretKurali subeUcu ortakBicim"],
  ["rezervasyon iptali", "ceptenErisim rezervasyonAkisi oduncKurali bildirimKuyrugu"],
  ["uyelik hatirlatmasi", "uyelikAkisi uyelikKurali bildirimKuyrugu personelUcu"],
  ["katalog kaydinda alan", "katalogKoprusu katalogKurali ortakBicim ceptenErisim"],
  ["odunc suresi uzatma", "oduncAkisi oduncKurali subeUcu"],
  ["kimlikte ikinci adim", "kimlikKoprusu uyelikAkisi personelUcu ortakBicim"],
  ["ucret iadesi kaydi", "ucretAkisi depoErisimi olayGunlugu"],
  ["sube gecikme raporu", "personelUcu depoErisimi oduncAkisi"],
  ["bildirim metni bicimi", "bildirimKuyrugu ortakBicim"],
  ["rezervasyon sirasi", "ceptenErisim rezervasyonAkisi subeUcu"],
  ["odunc kurali istisnasi", "oduncKurali ucretKurali oduncAkisi ucretAkisi"],
  ["olay gunlugune alan", "olayGunlugu ortakBicim depoErisimi"],
];

const sahip = {}, E = Object.keys(BOLUNME), kom = Object.fromEntries(E.map((e) => [e, []]));
for (const [e, ms] of Object.entries(BOLUNME)) for (const m of ms.split(" ")) sahip[m] = e;
for (const k of KANAL.split(" ")) {
  const [x, y] = k.split("-");
  kom[x].push(y); kom[y].push(x);
}
const d = {};
for (const s of E) {
  d[s] = Object.fromEntries(E.map((e) => [e, -1]));
  d[s][s] = 0;
  for (let q = [s]; q.length; ) {
    const u = q.shift();
    for (const v of kom[u]) if (d[s][v] < 0) { d[s][v] = d[s][u] + 1; q.push(v); }
  }
}
const deg = {};
for (const [, ms] of KALEM) for (const m of ms.split(" "))
  (deg[m] ??= new Set([sahip[m]])).add(sahip[ms.split(" ")[0]]);

// ET16 — gerceklesen sure onceki derslerin akis modelinden gelir: calisma + bekleme + yeniden is
const BEKLE = [0, 1, 3, 5], YOK = 8;
const GERCEK = KALEM.map(([ad, dizi]) => {
  const ms = dizi.split(" "), sira = [...new Set(ms.map((m) => sahip[m]))];
  let bek = 0, enUzun = 0, kopuk = 0;
  for (let j = 1; j < sira.length; j++) {
    const u = d[sira[j - 1]][sira[j]], b = u < 0 ? YOK : BEKLE[u];
    bek += b; enUzun = Math.max(enUzun, b);
    if (u < 0 || u >= 2) kopuk += 1;
  }
  const neden = [];
  if (kopuk) neden.push("kisit");
  if (ms.some((m) => deg[m].size >= 3)) neden.push("sinir");
  if (sira.length >= 4) neden.push("bilgi");
  const cal = ms.length + neden.length * 2, bekT = bek + neden.length * enUzun;
  return { ad, modul: ms.length, ekip: sira.length, calisma: cal, bekleme: bekT,
    yenidenIs: neden.length, gercek: cal + bekT };
});

// ET17 — uretec: dogrusal esleme, tohum gorunur; her asamada bir tur cekilir
const TOHUM = 20250401;
function uretec(t) {
  return () => { t = (t * 1103515245 + 12345) % 2147483648; return t / 2147483648; };
}
const r = uretec(TOHUM);
const sapma = (genislik) => 1 + (r() * 2 - 1) * genislik;

// ET18 — uc tahmin asamasi: istek geldiginde, kalem incelendiginde, ilk ekip isini bitirdiginde
const T = GERCEK.map((g) => {
  const a1 = Math.max(1, Math.round(g.modul * sapma(0.8)));    // yalnizca basligi gorur
  const a2 = Math.round(g.modul * sapma(0.3));                 // dokunulan modulleri bilir
  const a3 = Math.round((g.calisma + (g.ekip - 1)) * sapma(0.1)); // ekip sayisini da bilir
  return { ...g, a1, a2, a3 };
});
writeFileSync("tahmin.json", JSON.stringify(T));

console.log(`${"is kalemi".padEnd(24)}${"modul".padStart(6)}${"ekip".padStart(5)}` +
  `${"asama1".padStart(8)}${"asama2".padStart(8)}${"asama3".padStart(8)}${"gercek".padStart(8)}` +
  `${"  = calisma + bekleme"}`);
for (const t of T)
  console.log(`${t.ad.padEnd(24)}${String(t.modul).padStart(6)}${String(t.ekip).padStart(5)}` +
    `${String(t.a1).padStart(8)}${String(t.a2).padStart(8)}${String(t.a3).padStart(8)}` +
    `${String(t.gercek).padStart(8)}    ${String(t.calisma).padStart(2)} + ${String(t.bekleme).padStart(2)}` +
    `${t.yenidenIs ? `  (${t.yenidenIs} yeniden is)` : ""}`);
console.log(`\ntohum ${TOHUM}; toplam gercek ${T.reduce((s, t) => s + t.gercek, 0)} tur ` +
  `(${T.reduce((s, t) => s + t.calisma, 0)} calisma + ${T.reduce((s, t) => s + t.bekleme, 0)} bekleme)`);
```

```
is kalemi                modul ekip  asama1  asama2  asama3  gercek  = calisma + bekleme
gecikme ucreti orani         4    3       5       4      11      18     8 + 10  (2 yeniden is)
rezervasyon iptali           4    3       1       3       7       9     6 +  3  (1 yeniden is)
uyelik hatirlatmasi          4    3       6       5      10      18     8 + 10  (2 yeniden is)
katalog kaydinda alan        4    3       4       3       9      18     8 + 10  (2 yeniden is)
odunc suresi uzatma          3    2       1       2       6       7     5 +  2  (1 yeniden is)
kimlikte ikinci adim         4    3       3       3      10      18     8 + 10  (2 yeniden is)
ucret iadesi kaydi           3    3       4       4       6       8     5 +  3  (1 yeniden is)
sube gecikme raporu          3    2       4       2       6       7     5 +  2  (1 yeniden is)
bildirim metni bicimi        2    1       3       3       4       4     4 +  0  (1 yeniden is)
rezervasyon sirasi           3    2       5       3       6       7     5 +  2  (1 yeniden is)
odunc kurali istisnasi       4    2       6       5       5       5     4 +  1
olay gunlugune alan          3    2       5       4       6       7     5 +  2  (1 yeniden is)

tohum 20250401; toplam gercek 126 tur (71 calisma + 55 bekleme)
```

#### Hata Payı ve Koninin Daralması

**ET19 — bir kalemde plan "tuttu" sayılır: tahmin gerçeğin %20 bandı içinde kalıyorsa.** **ET20 —
kalemler dokundukları ekip sayısına göre iki kümeye ayrılır: bir–iki ekibe dokunanlar ve üç ve daha
çok ekibe dokunanlar.** Gerekçe: bant olmadan "tuttu" sözcüğü sayıya çevrilemez; ikinci ayrım ise
ekip sınırının tahmin üzerindeki payını yalıtır.

```js
// koni.mjs — hata payi, belirsizlik konisinin daralmasi, tek kalem tahmini ile toplam tahmini
import { readFileSync } from "node:fs";
const T = JSON.parse(readFileSync("tahmin.json", "utf8"));

const AS = ["a1", "a2", "a3"];
const AD = { a1: "asama 1 (istek)", a2: "asama 2 (inceleme)", a3: "asama 3 (ilk ekip bitti)" };
const top = (f) => T.reduce((s, t) => s + f(t), 0);
const yuzde = (x) => `%${(100 * x).toFixed(1)}`;
// ET19 — plan bir kalemde "tuttu" sayilir: tahmin gercegin %20 bandi icinde kaliyorsa
const BANT = 0.2;

console.log(`${"asama".padEnd(26)}${"ort. mutlak hata".padStart(18)}${"ort. yanlilik".padStart(15)}` +
  `${"koni: tahmin/gercek".padStart(21)}${"genislik".padStart(10)}${"plan tuttu".padStart(12)}`);
for (const a of AS) {
  const oran = T.map((t) => t[a] / t.gercek).sort((x, y) => x - y);
  const mape = top((t) => Math.abs(t[a] - t.gercek) / t.gercek) / T.length;
  const yan = top((t) => (t[a] - t.gercek) / t.gercek) / T.length;
  const tut = T.filter((t) => Math.abs(t[a] - t.gercek) / t.gercek <= BANT).length;
  console.log(`${AD[a].padEnd(26)}${yuzde(mape).padStart(18)}${yuzde(yan).padStart(15)}` +
    `${`${oran[0].toFixed(2)} - ${oran[oran.length - 1].toFixed(2)}`.padStart(21)}` +
    `${(oran[oran.length - 1] - oran[0]).toFixed(2).padStart(10)}${`${tut}/${T.length}`.padStart(12)}`);
}

console.log(`\n${"asama".padEnd(26)}${"toplam tahmin".padStart(15)}${"toplam gercek".padStart(15)}` +
  `${"toplamin hatasi".padStart(17)}${"tek kalem ort. hatasi".padStart(23)}`);
for (const a of AS) {
  const tt = top((t) => t[a]), tg = top((t) => t.gercek);
  const mape = top((t) => Math.abs(t[a] - t.gercek) / t.gercek) / T.length;
  console.log(`${AD[a].padEnd(26)}${String(tt).padStart(15)}${String(tg).padStart(15)}` +
    `${yuzde((tt - tg) / tg).padStart(17)}${yuzde(mape).padStart(23)}`);
}

// hatanin nereden geldigi: asama 2 yalnizca calismayi tahmin eder
const a2 = top((t) => t.a2), gercek = top((t) => t.gercek);
console.log(`\nasama 2 toplami ${a2} tur; gercek ${gercek} tur; fark ${gercek - a2} tur`);
console.log(`  farkin bilesenleri: bekleme ${top((t) => t.bekleme)} tur, ` +
  `yeniden isin ekledigi calisma ${top((t) => 2 * t.yenidenIs)} tur, ` +
  `dokunulan modul ${top((t) => t.modul)} tur (asama 2 bunu tahmin eder)`);

// ET20 — kalemler dokunduklari ekip sayisina gore ayrilir
console.log(`\n${"kalem kumesi".padEnd(26)}${"kalem".padStart(7)}${"ort. gercek".padStart(13)}` +
  `${"bekleme payi".padStart(14)}${"asama 2 hatasi".padStart(16)}${"asama 3 hatasi".padStart(16)}`);
for (const [ad, f] of [["1-2 ekibe dokunan", (t) => t.ekip <= 2], ["3+ ekibe dokunan", (t) => t.ekip >= 3]]) {
  const k = T.filter(f), s = (g) => k.reduce((x, t) => x + g(t), 0);
  console.log(`${ad.padEnd(26)}${String(k.length).padStart(7)}` +
    `${(s((t) => t.gercek) / k.length).toFixed(1).padStart(13)}` +
    `${yuzde(s((t) => t.bekleme) / s((t) => t.gercek)).padStart(14)}` +
    `${yuzde(s((t) => Math.abs(t.a2 - t.gercek) / t.gercek) / k.length).padStart(16)}` +
    `${yuzde(s((t) => Math.abs(t.a3 - t.gercek) / t.gercek) / k.length).padStart(16)}`);
}
```

```
asama                       ort. mutlak hata  ort. yanlilik  koni: tahmin/gercek  genislik  plan tuttu
asama 1 (istek)                        %55.8         %-52.5          0.11 - 1.20      1.09        1/12
asama 2 (inceleme)                     %58.4         %-58.4          0.17 - 1.00      0.83        1/12
asama 3 (ilk ekip bitti)               %23.5         %-23.5          0.50 - 1.00      0.50        6/12

asama                       toplam tahmin  toplam gercek  toplamin hatasi  tek kalem ort. hatasi
asama 1 (istek)                        47            126           %-62.7                  %55.8
asama 2 (inceleme)                     41            126           %-67.5                  %58.4
asama 3 (ilk ekip bitti)               86            126           %-31.7                  %23.5

asama 2 toplami 41 tur; gercek 126 tur; fark 85 tur
  farkin bilesenleri: bekleme 55 tur, yeniden isin ekledigi calisma 30 tur, dokunulan modul 41 tur (asama 2 bunu tahmin eder)

kalem kumesi                kalem  ort. gercek  bekleme payi  asama 2 hatasi  asama 3 hatasi
1-2 ekibe dokunan               6          6.2         %24.3           %44.6            %9.5
3+ ekibe dokunan                6         14.8         %51.7           %72.2           %37.5
```

#### Koni Daralırken Hata Neden Durdu

İlk tablonun iki sütunu ters yönlere gider. **Koni gerçekten daralır:** tahmin/gerçek oranının
genişliği 1.09'dan 0.83'e, oradan 0.50'ye iner. Ama ortalama mutlak hata aynı yolu izlemez —
aşama 1'de %55.8, aşama 2'de %58.4'tür. **Belirsizlik azalırken hata azalmadı.**

Nedeni yanlılık sütununda yazılıdır. Üç aşamanın üçünde de yanlılık negatiftir: %-52.5, %-58.4,
%-23.5. Yani tahminler yalnız dağınık değil, **hepsi aynı yöne yanlıştır** — her aşamada süre
olduğundan az tahmin edilir. Aşama 1'den aşama 2'ye geçerken tahmincinin öğrendiği şey dokunulan
modüllerin tam listesidir; bu bilgi sapmayı ±%80'den ±%30'a indirir ama yanlılığa dokunmaz, çünkü
yanlılık modül sayısını yanlış bilmekten gelmiyordu.

Nereden geldiğini ikinci çıktı bloğunun ortasındaki satır adlandırır. Aşama 2'nin toplam tahmini 41
tur, gerçekleşen toplam 126 turdur; aradaki 85 turun 55'i **bekleme**, 30'u **yeniden işin eklediği
çalışmadır**. Aşama 2 dokunulan modül sayısını (41 tur) neredeyse tam bilir — ve tahmin ettiği tek
şey odur. **Tahmin çalışmayı tahmin eder; gerçekleşen süre akış süresidir.** İkisinin arasındaki
fark önceki iki dersin ölçtüğü şeyin ta kendisidir: el değiştirmede beklenen turlar ve
yanlış sınır yüzünden geri dönen kalemler.

Aşama 3 hatayı %23.5'e indirir ve planın tuttuğu kalem sayısını 1'den 6'ya çıkarır. Yaptığı tek şey
bekleme kavramını tahmine sokmaktır — her el değiştirme için bir tur. Bu kaba düzeltme bile hatanın
yarısından fazlasını kapatır; kalan %23.5 ise beklemenin bir turdan uzun olduğu geçişlerden ve
yeniden işten gelir.

#### Tek Kalem Tahmini ile Toplam Tahmini

İkinci tablo yaygın bir beklentiyi sınar: tek tek kalemlerde yapılan hataların toplamda birbirini
götürmesi. Götürmez. Aşama 2'de tek kalem ortalama mutlak hatası %58.4, **toplamın hatası
%-67.5'tir** — toplam, tek kalemden daha kötüdür. Aynı ilişki üç aşamada da sürer.

Hataların birbirini götürmesi ancak hataların **iki yöne** dağıldığı durumda olur. Burada on iki
kalemin hiçbirinde aşama 2 tahmini gerçeği aşmaz; koni sütunundaki en yüksek oran 1.00'dır. Bir yöne
yanlı hatalar toplandığında büyüklükleri de toplanır. **Bir tahmin kümesinin toplamı, ancak
kümedeki hatalar yansızsa tek kalem hatasından daha güvenilirdir**; yanlılık varsa toplam tahmin
tek kalem tahmininden daha az güvenilirdir.

Son tablo yanlılığın nereden geldiğini gösterir. Bir–iki ekibe dokunan altı kalemin ortalama
gerçekleşen süresi 6.2 tur ve bunun %24.3'ü beklemedir; aşama 2 hatası %44.6, aşama 3 hatası
%9.5'tir. Üç ve daha çok ekibe dokunan altı kalemde ise ortalama süre 14.8 tur, bekleme payı %51.7,
aşama 2 hatası %72.2 ve aşama 3 hatası %37.5'tir. **Aynı tahmin yöntemi, ekip sınırını çok geçen
kalemlerde yaklaşık iki kat daha kötü çalışır.** Tahminin kötüleştiği yer, önceki iki dersin akış
süresinin uzadığı yerle aynıdır — modül sınırı ile ekip sınırının örtüşmediği kalemler.

#### Özet

- On iki kalemin gerçekleşen süresi önceki derslerin akış modelinden alındı (toplam 126 tur =
  71 çalışma + 55 bekleme) ve üç aşamada üretilen tahminlerle karşılaştırıldı; üreteç tohumu
  `20250401`.
- Belirsizlik konisi aşama aşama daralır (tahmin/gerçek oranının genişliği 1.09 → 0.83 → 0.50) ama
  ortalama mutlak hata aynı yolu izlemez: %55.8 → %58.4 → %23.5. Aşama 1'den 2'ye geçişte koni
  daraldığı halde hata azalmadı.
- Üç aşamada da yanlılık negatiftir (%-52.5, %-58.4, %-23.5): tahminler dağınık değil, hepsi aynı
  yöne yanlıştır. Aşama 2'nin 41 turluk toplam tahmini ile 126 turluk gerçek arasındaki 85 turun
  55'i bekleme, 30'u yeniden işin eklediği çalışmadır.
- Beklemeyi kaba biçimde (el değiştirme başına bir tur) tahmine sokmak hatayı %23.5'e indirir ve
  %20 bandında tutan kalem sayısını 1/12'den 6/12'ye çıkarır.
- Hatalar birbirini götürmez: aşama 2'de tek kalem ortalama hatası %58.4 iken toplamın hatası
  %-67.5'tir. Tek yöne yanlı hatalar toplandığında büyüklükleri de toplanır.
- Ekip sınırını çok geçen kalemlerde tahmin yaklaşık iki kat kötüleşir: 1–2 ekibe dokunan kalemlerde
  aşama 2 hatası %44.6 ve bekleme payı %24.3 iken, 3+ ekibe dokunanlarda %72.2 ve %51.7'dir.

#### Sonraki Adım

Bu dersin bütün sayıları bir varsayıma dayanıyordu: **iş kalemi kümesi çeyrek boyunca sabittir.**
On iki kalem baştan sayıldı, tahmin edildi, koşturuldu. Gerçekte kalem kümesi durmaz — çeyrek
ortasında yeni bir istek gelir, var olan bir kalemin kapsamı büyür, bir başkası iptal edilir. Bu
durumda tahminin hata payı yalnız yukarıdaki nedenlerle değil, **tahmin edilen işin kendisi
değiştiği için de** büyür. Sonraki ders bu değişimi ele alır: bir kalemin kapsamı büyüdüğünde
akışta ne olur, değişiklik hangi noktadan sonra kabul edilirse yeniden iş kaçınılmaz olur ve
değişimi denetleyen bir düzenin kendisi akışa kaç tur ekler.

### Değişiklik Yönetimi

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/degisiklik-yonetimi

Kapsam değişiminin denetimi: aynı isteğin çözümlemede 0, doğrulamada 8 tur yeniden iş yazması ve kalemi 12 turdan 39 tura taşıması, aynı altı isteği geldiğinde alan biçimin ikisini alıp 8 tur yeniden iş üretmesine karşılık sınırda toplayan biçimin dördünü alıp isteği ortalama 30 tur bekletmesi, denetim kaldırıldığında planın ikinci istekte sekiz kalemin birinde tutması ve ekip sınırının dışına düşen değişikliğin aynı kalemi 23 yerine 28 turda teslim ettirmesi.

Önceki ders iş kaleminin süresini tahmin etti ve tahminin hata payını ölçtü. Ama planı asıl bozan
şey tahminin sapması değildir: tahmin, sabiti bilinen bir işin süresine dair bir sayıdır; planın
altındaki kapsam değişince o sayı yanlış çıkmaz, konusuz kalır.

**Değişiklik denetimi** (change control), kapsam değişikliğinin akışa hangi noktadan ve hangi
bedelle gireceğini belirleyen karar yoludur. Aşağıdaki dört ölçüm onu sayıya çevirir.

#### Değişikliğin Girdiği An

Örnek, kursun kurgu **bölgesel kütüphane ağı** ile onu yazan üç ekiptir; ağ da ekipler de
kurgudur. **ET22:** modül sahipliği üçe bölünür — E1 şube ön yüzü, terminal ve üyelik kapısını;
E2 ödünç ile ücretlendirmeyi; E3 katalog kapısı, raporlama ve bildirimi tutar. **ET23:** iş kalemi
dört aşamadan geçer (çözümleme, geliştirme, gözden geçirme, doğrulama); kalem ikinci bir ekibin
modülüne dokunuyorsa o ekip yarım geliştirme ile gözden geçirmeyi alır. Her ekip aynı anda tek
adım işler, biten adımdan sonra kalem kuyruğun sonuna döner. **ET24:** ilk kapsam sekiz kalem ve
71 tur iştir; plan kalemleri 0., 6. ve 12. turda bırakır, **kapsam kaydı** bu planın teslim
turlarıdır. **ET25:** değişiklik kalemi çözümlemeye döndürür; o ana kadar yapılmış işin tamamı
**yeniden iş**tir, geri dönüşün kendisi bir el değiştirmedir. **ET26:** yineleme on tur, yineleme
başına **değişiklik payı** sekiz turdur; paydan düşen tutar ek iş artı tetiklediği yeniden iştir,
sığmayan istek reddedilir. Akış ile iki denetim biçimi süreç içi bir **modeldir**; ağ ya da saat
yoktur, turlar sayıdır.

```js
// degisiklik/akis.mjs — kurgu kutuphane aginin is kalemi akisi ve degisiklik denetimi
// (model): ne ag ne depo var, kuyruklar veri yapisi, rastgelelik yok.

export const EKIP = { "sube-onyuz": "E1", "sube-terminal": "E1", "uyelik-kapisi": "E1",
  odunc: "E2", ucret: "E2", rapor: "E3", bildirim: "E3", "katalog-kapisi": "E3" };
export const EKIPLER = [...new Set(Object.values(EKIP))];
export const YINELEME = 10, PAY = 8, COZ = 1;

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

// Ilk kapsam: ad, modul, asama turlari, plan girisi.
export const KAPSAM = cizelge(`
  gecikme-ucreti-esigi  ucret           2,4,2,2   0
  sube-rafi-gorunumu    sube-onyuz      2,3,1,2   0
  katalog-alan-esleme   katalog-kapisi  1,3,1,1   0
  odunc-suresi-uzatma   odunc           2,4,2,2   6
  terminal-kart-okuma   sube-terminal   1,3,1,2   6
  aylik-odunc-raporu    rapor,odunc     2,3,2,1   6
  borc-bildirimi        bildirim,ucret  2,4,2,2  12
  uyelik-dogrulama      uyelik-kapisi   2,3,1,2  12`,
([ad, m, i, g]) => ({ ad, modul: m.split(","), is: i.split(",").map(Number), giris: +g }));

// Degisiklik: gelis turu, ad, hedef, modul, ek is.
export const DEGISIKLIK = cizelge(`
   3  ucret-muafiyeti       gecikme-ucreti-esigi  ucret           3
   6  rafta-filtre          sube-rafi-gorunumu    sube-onyuz      2
   9  uzatma-siniri         odunc-suresi-uzatma   odunc           3
  12  raporda-ucret-sutunu  aylik-odunc-raporu    ucret           3
  15  terminalde-uzatma     terminal-kart-okuma   odunc           2
  18  ikinci-alan-eslemesi  katalog-alan-esleme   katalog-kapisi  3`,
([t, ad, h, m, e]) => ({ tur: +t, ad, hedef: h, modul: m.split(","), ek: +e }));

// Sahip ekip cozumler ve gelistirir; ikinci ekip yarim gelistirme ile gozdeni alir.
export function adimlar(modul, is) {
  const e = [...new Set(modul.map((m) => EKIP[m]))], sahip = e[0];
  const a = [{ ad: "cozumleme", ekip: sahip, is: is[0] },
    { ad: "gelistirme", ekip: sahip, is: is[1] }];
  for (const x of e.slice(1)) a.push({ ad: "gelistirme", ekip: x, is: Math.ceil(is[1] / 2) });
  return [...a, { ad: "gozden", ekip: e.at(-1), is: is[2] },
    { ad: "dogrulama", ekip: sahip, is: is[3] }];
}

const kur = (ad, modul, is, giris, kaynak) => ({ ad, modul: [...modul], taban: [...is],
  adim: adimlar(modul, is), i: 0, yapilan: 0, giris, kaynak, bitis: null, bekleme: 0,
  elDegistirme: 0, yenidenIs: 0 });

export const isi = (k) => k.adim.reduce((s, a) => s + a.is, 0);

// "alan" istegi geldigi turda, "toplayan" yineleme sinirinda karara baglar; paya sigmayan red.
export function kos(bicim, degisiklikler, ayar = {}) {
  const pay = ayar.pay ?? PAY;
  const havuz = KAPSAM.map((k) => kur(k.ad, k.modul, k.is, k.giris, "kapsam"));
  const kalem = [], harcanan = {}, kabul = [], red = [], tampon = [];
  const kuyruk = Object.fromEntries(EKIPLER.map((e) => [e, []]));
  const mevcut = Object.fromEntries(EKIPLER.map((e) => [e, null]));
  const koy = (k) => { kalem.push(k); kuyruk[k.adim[0].ekip].push(k); };

  function karar(d, tur, yin) {
    const k = kalem.find((x) => x.ad === d.hedef && x.bitis === null);
    const yerinde = bicim === "alan" && k;              // yerinde alinmiyorsa ayri kalem olur
    // Yerinde alma yapilmis isi yeniden ise cevirir; ayri kalem baglami kurar (COZ).
    const yapilmis = yerinde
      ? k.adim.slice(0, k.i).reduce((s, a) => s + a.is, 0) + k.yapilan : COZ;
    const asama = yerinde ? k.adim[k.i].ad : k ? "sinirda" : "teslim-sonrasi";
    const m = d.ek + yapilmis;                         // paydan dusen tutar
    if ((harcanan[yin] ?? 0) + m > pay) return red.push({ d, asama, m });
    harcanan[yin] = (harcanan[yin] ?? 0) + m;
    if (!yerinde) {
      const y = kur(d.ad, d.modul, [COZ, d.ek, 1, 1], d.tur, "degisiklik");
      y.yenidenIs = COZ; koy(y);
      return kabul.push({ d, kalem: y, asama, m });
    }
    k.yenidenIs += yapilmis; k.elDegistirme += 1;      // geri donus de el degistirmedir
    k.modul = [...new Set([...k.modul, ...d.modul])];
    k.taban[1] += d.ek; k.adim = adimlar(k.modul, k.taban); k.i = 0; k.yapilan = 0;
    for (const e of EKIPLER) {
      if (mevcut[e] === k) mevcut[e] = null;
      kuyruk[e] = kuyruk[e].filter((x) => x !== k);
    }
    kuyruk[k.adim[0].ekip].push(k);
    kabul.push({ d, kalem: k, asama, m });
  }

  for (let tur = 0; tur < 80; tur++) {
    havuz.filter((k) => k.giris === tur).forEach(koy);
    for (const d of degisiklikler.filter((x) => x.tur === tur))
      if (bicim === "alan") karar(d, tur, Math.floor(tur / YINELEME)); else tampon.push(d);
    if (bicim === "toplayan" && tur > 0 && tur % YINELEME === 0)
      for (const d of tampon.splice(0)) karar(d, tur, tur / YINELEME);
    for (const e of EKIPLER) if (!mevcut[e] && kuyruk[e].length) mevcut[e] = kuyruk[e].shift();
    for (const e of EKIPLER) for (const k of kuyruk[e]) k.bekleme++;
    for (const e of EKIPLER) {
      const k = mevcut[e];
      if (!k || ++k.yapilan < k.adim[k.i].is) continue;
      k.yapilan = 0; k.i++; mevcut[e] = null;
      if (k.i >= k.adim.length) k.bitis = tur + 1;
      else { k.elDegistirme++; kuyruk[k.adim[k.i].ekip].push(k); }
    }
  }
  if (kalem.some((k) => k.bitis === null)) throw new Error("kosum 80 turda bitmedi");
  return { kalem, kabul, red, son: Math.max(...kalem.map((k) => k.bitis)) };
}
```

```js
// degisiklik/olc.mjs — giris aninin bedeli, iki denetim bicimi, kapsam kaymasi, ekip siniri.
import { kos, isi, KAPSAM, DEGISIKLIK, PAY, YINELEME } from "./akis.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const top = (r, a) => r.kalem.reduce((s, k) => s + k[a], 0);
const ort = (a) => (a.reduce((s, x) => s + x, 0) / a.length).toFixed(1);
const kapsamda = (r) => r.kalem.filter((k) => k.kaynak === "kapsam");

const T = kos("alan", []), KAYIT = Object.fromEntries(T.kalem.map((k) => [k.ad, k.bitis]));
const TABAN_IS = T.kalem.reduce((s, k) => s + isi(k), 0);
const satir = (r, ad) => {                       // bir kalemin akis olculeri
  const k = r.kalem.find((x) => x.ad === ad);
  return [k.yenidenIs, k.elDegistirme, k.bekleme, k.bitis - k.giris, r.son];
};
console.log(`kayitli plan: ${KAPSAM.length} kalem, ${TABAN_IS} tur is, son teslim ${T.son}. tur, ` +
  `ortalama teslim suresi ${ort(kapsamda(T).map((k) => k.bitis - k.giris))} tur; ` +
  `yineleme ${YINELEME} tur, yineleme payi ${PAY} tur`);

// 1. Ayni degisiklik, farkli giris ani; pay sinirsiz.
const HEDEF = "gecikme-ucreti-esigi";
const G = [-7, -16, 12, 15, 9, 15, 11];
console.log("\n1. ayni degisiklik (ucret-muafiyeti, 3 tur ek is), farkli giris ani");
yaz(G, "gelis", "girdigi asama", "yeniden is", "el degistirme", "bekleme", "teslim suresi",
  "akis sonu");
yaz(G, "yok", "-", ...satir(T, HEDEF));
for (const tur of [0, 8, 14]) {
  const r = kos("alan", [{ tur, ad: "ucret-muafiyeti", hedef: HEDEF, modul: ["ucret"], ek: 3 }],
    { pay: Infinity });
  yaz(G, tur, r.kabul[0].asama, ...satir(r, HEDEF));
}

// 2. Iki denetim bicimi, ayni alti istek, ayni pay.
const R = { alan: kos("alan", DEGISIKLIK), toplayan: kos("toplayan", DEGISIKLIK) };
const sonuc = (r, d) => {                        // istegin bu bicimdeki sonucu
  const a = r.kabul.find((x) => x.d.ad === d.ad), x = r.red.find((y) => y.d.ad === d.ad);
  return a ? `alindi/${a.asama}/${a.m} -> ${a.kalem.bitis}` : `reddedildi/${x.asama}/${x.m}`;
};
const B = [-22, 6, -33, -1];
console.log("\n2. degisiklik denetimi: geldiginde alan bicim ile sinirda toplayan bicim");
yaz(B, "degisiklik", "gelis", "  alan bicim", "  toplayan bicim");
for (const d of DEGISIKLIK)
  yaz(B, d.ad, d.tur, "  " + sonuc(R.alan, d), "  " + sonuc(R.toplayan, d));
const O = [-34, 12, 12];
console.log();
yaz(O, "olcu", "alan", "toplayan");
const ozet = (r) => ({
  "ilk kapsam ort. teslim": ort(kapsamda(r).map((k) => k.bitis - k.giris)),
  "kayitli turunda biten": `${kapsamda(r).filter((k) => k.bitis <= KAYIT[k.ad]).length}/8`,
  "yeniden is": top(r, "yenidenIs"), bekleme: top(r, "bekleme"),
  "el degistirme": top(r, "elDegistirme"),
  "alinan / reddedilen": `${r.kabul.length}/${r.red.length}`,
  "degisikligin ort. teslimi": ort(r.kabul.map((x) => x.kalem.bitis - x.d.tur)),
  "akisin sonu": r.son,
});
const oA = ozet(R.alan), oT = ozet(R.toplayan);
for (const k of Object.keys(oA)) yaz(O, k, oA[k], oT[k]);

// 3. Denetim reddetmezse kayit ne kadar dayaniyor.
const K = [-12, 12, 17, 14, 11];
console.log("\n3. kapsam kaymasi (pay sinirsiz: her istek aliniyor)");
yaz(K, "alinan", "eklenen is", "eklenen/kayitli", "plan tuttu", "akis sonu");
for (const n of [0, 1, 2, 6]) {
  const r = kos("alan", DEGISIKLIK.slice(0, n), { pay: Infinity });
  const kap = kapsamda(r), ek = r.kalem.reduce((s, k) => s + isi(k), 0) - TABAN_IS;
  let tuttu = 0;                                   // plan sirasinda ilk sapmaya kadar
  for (const k of [...kap].sort((a, b) => KAYIT[a.ad] - KAYIT[b.ad])) {
    if (k.bitis > KAYIT[k.ad]) break;
    tuttu++;
  }
  yaz(K, n, ek, `%${((100 * ek) / TABAN_IS).toFixed(1)}`, `${tuttu}/8`, r.son);
}

// 4. Degisiklik ekip sinirinin icine mi disina mi.
const M = [-24, 6, 12, 15, 9, 15, 11];
console.log("\n4. ayni degisiklik (terminal-kart-okuma, 12. tur, 2 tur ek is) nereye dusuyor");
yaz(M, "dusen yer", "adim", "yeniden is", "el degistirme", "bekleme", "teslim suresi", "akis sonu");
const AD = "terminal-kart-okuma";
yaz(M, "degisiklik yok", T.kalem.find((k) => k.ad === AD).adim.length, ...satir(T, AD));
for (const [yer, modul] of [["ekip sinirinin icine", ["sube-terminal"]],
  ["ekip sinirinin disina", ["odunc"]]]) {
  const r = kos("alan", [{ tur: 12, ad: "terminal-degisikligi", hedef: AD, modul, ek: 2 }],
    { pay: Infinity });
  yaz(M, yer, r.kalem.find((k) => k.ad === AD).adim.length, ...satir(r, AD));
}
```

```
kayitli plan: 8 kalem, 71 tur is, son teslim 30. tur, ortalama teslim suresi 12.9 tur; yineleme 10 tur, yineleme payi 8 tur

1. ayni degisiklik (ucret-muafiyeti, 3 tur ek is), farkli giris ani
gelis  girdigi asama     yeniden is  el degistirme  bekleme  teslim suresi  akis sonu
yok    -                          0              3        2             12         30
0      cozumleme                  0              4        8             21         33
8      dogrulama                  8              7       18             39         39
14     teslim-sonrasi             0              3        2             12         34

2. degisiklik denetimi: geldiginde alan bicim ile sinirda toplayan bicim
degisiklik             gelis  alan bicim                       toplayan bicim
ucret-muafiyeti            3  alindi/gelistirme/6 -> 22        alindi/sinirda/4 -> 41
rafta-filtre               6  reddedildi/dogrulama/8           alindi/teslim-sonrasi/3 -> 26
uzatma-siniri              9  reddedildi/cozumleme/3           reddedildi/sinirda/4
raporda-ucret-sutunu      12  alindi/gelistirme/8 -> 36        alindi/sinirda/4 -> 44
terminalde-uzatma         15  reddedildi/dogrulama/7           alindi/teslim-sonrasi/3 -> 45
ikinci-alan-eslemesi      18  reddedildi/teslim-sonrasi/4      reddedildi/teslim-sonrasi/4

olcu                                      alan    toplayan
ilk kapsam ort. teslim                    16.3        16.3
kayitli turunda biten                      4/8         3/8
yeniden is                                   8           4
bekleme                                     44         133
el degistirme                               31          38
alinan / reddedilen                        2/4         4/2
degisikligin ort. teslimi                 21.5        30.0
akisin sonu                                 36          45

3. kapsam kaymasi (pay sinirsiz: her istek aliniyor)
alinan        eklenen is  eklenen/kayitli    plan tuttu  akis sonu
0                      0             %0.0           8/8         30
1                      3             %4.2           2/8         34
2                      5             %7.0           1/8         34
6                     23            %32.4           1/8         44

4. ayni degisiklik (terminal-kart-okuma, 12. tur, 2 tur ek is) nereye dusuyor
dusen yer                 adim  yeniden is  el degistirme  bekleme  teslim suresi  akis sonu
degisiklik yok               4           0              3        4             11         30
ekip sinirinin icine         4           4              6       10             23         30
ekip sinirinin disina        5           4              7       12             28         34
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır. Birinci tablo aynı isteği üç
ayrı anda aynı akışa sokar. Çözümlemedeyken giren istek sıfır yeniden iş yazar; doğrulamadayken
giren aynı istek sekiz tur yeniden iş, dört fazladan el değiştirme ve on altı tur fazladan bekleme
getirir: teslim süresi 12 turdan 39 tura çıkar, üç turluk ek iş yirmi yedi tura mal olur. Erken
giren de bedava değildir — büyüyen kalem sonradan bırakılanların arkasına düştüğü için 21 turda
biter. Kalem teslim edilmişse istek ayrı bir kalem olur: hedef plandaki 12 turda kalır, akışın
sonu 30'dan 34'e gider. **Bedel kalemden çıkar, akışa geçer.**

#### Toplayan Biçim ile Alan Biçim

İkinci ölçüm aynı altı isteği aynı payla iki biçimde koşturur: alan biçim isteği kalemin içine
sokar, toplayan biçim kalemi plana göre bitirip isteği sınırda ayrı kalem olarak alır. Alan biçim
ikisini alır, dördünü reddeder. Paydan düşen tutar yeniden işi de içerdiğinden doğrulamadaki bir
kaleme gelen istek sekiz turluk payın tamamını yer; payı dolduran pahalı istek arkadan gelen ucuzu
da reddettirir: dokuzuncu turdaki üç turluk istek, hedefi çözümlemedeyken sığmaz. Toplayan biçim dördünü alır ve yeniden işi yarıya indirir (8 yerine 4); bedeli
geciktirdiği değerdir — gelişten teslime ortalama 30 tur geçer, alan biçimde 21,5. Aldığı dört
isteğin ikisi sınıra geldiğinde hedef kalem çoktan bitmiştir. İlk kapsamın ortalama teslim süresi
iki biçimde de 16,3 tur çıkar; **ortalama ayrımı gizler**: kayıtlı turunda biten kalem 4/8'e
karşı 3/8'dir, alan biçimde gecikme değişen kalemlerde toplanır, toplayanda tümüne yayılır.

#### Kapsam Kayması ve Kaydın Ömrü

**ET27:** üçüncü ölçümde denetim kaldırılır, her istek alınır. Altı istek 71 turluk işe 23 tur
ekler (yüzde 32,4'lük **kapsam kayması**), ama kayıt bu oranla orantılı bozulmaz. Tek istekte
plan sırasında ilk sapmaya kadar tutan kalem sekizden ikiye, ikinci istekte bire iner ve altıncıya
kadar orada kalır. Eklenen iş büyümeyi sürdürür, kaydın anlatma gücü ikinci değişiklikte dibi
bulur. **Kapsam kaydı o noktadan sonra bir plan değil bir tarihtir**: hangi kalemin ne zaman
biteceğini değil, bir zamanlar ne sanıldığını anlatır.

#### Değişiklik Hangi Sınıra Düşüyor

Dördüncü ölçüm aynı kaleme aynı turda aynı büyüklükte iki istek sokar; tek fark dokundukları
modüldür. Sınırın içinde kalan istek kalemin dört adımını korur; dışarı düşen istek onu iki ekibin
dokunduğu bir kaleme çevirir: adım beşe, el değiştirme altıdan yediye, bekleme 10'dan 12'ye çıkar,
teslim süresi 23 yerine 28 tur olur, akışın sonu 30'dan 34'e gider. Yeniden iş ikisinde de dört
turdur; fark bütünüyle sınırı geçmektendir. **Ekip sınırıyla örtüşmeyen istek pahalıdır** ve farkı
büyüten şey isteğin kendisi değil modül sahipliğinin bölünüşüdür.

#### Özet

- Aynı istek çözümlemede sıfır, doğrulamada sekiz tur yeniden iş yazar; teslim süresi 12 turdan
  39 tura çıkar. Teslim edilmiş kaleme gelen istek ayrı bir kalem olur.
- Aynı altı istek ve aynı payla alan biçim ikisini, toplayan biçim dördünü alır; yeniden iş 8'e
  karşı 4, bekleme 44'e karşı 133, akışın sonu 36'ya karşı 45'tir. Toplayan biçimin bedeli
  geciktirdiği değerdir: gelişten teslime ortalama 30 tur, alan biçimde 21,5; ilk kapsamın
  ortalaması ikisinde de 16,3 tur (kayıtlı turunda biten 4/8'e karşı 3/8).
- Denetim kaldırılınca altı istek kapsamı yüzde 32,4 büyütür ama plan daha erken kopar: birinci
  istekte 8/8'den 2/8'e, ikincide 1/8'e iner.
- Ekip sınırının dışına düşen istek bir adım, bir el değiştirme ve iki tur bekleme ekler; teslim
  süresi 23 yerine 28 turdur.

#### Sonraki Adım

Değişiklik denetlendi, kapsam kaydı tutuldu, bedeli yeniden iş ve bekleme cinsinden sayıldı. Ama
bu ölçümlerin hepsi sayacı kalemin teslim edildiği anda durduruyor. Teslim modelde son adımın
bitmesidir, alandaysa yazılımın asıl ömrünün başlaması: gece çalan bir çağrının kime gittiği ve
devredilemeyen işin neye mal olduğu bu tabloların hiçbirinde yok. Sonraki ders sayacı teslimin
ötesine taşır: geliştiren ile işleten arasındaki sorumluluk hangi kalemlerden oluşuyor ve
devredilemeyen kalem kime kalıyor?

### İşletim Devri

Source: https://academia.sh/tr/kurslar/surec-ve-ekip/isletim-devri

Geliştirme ile işletim arasındaki sorumluluk sözleşmesi: yirmi sekiz sorumluluk kaleminin yirmisinin devredilmesi ve sekizinin bilgi, araç ya da yordam yokluğunda geliştirmede kalması, aynı on dört olayın paylaşımlı nöbette 3,8 tam devirde 5,0 turda kapanması, buna karşılık geliştirme akışından çıkan turun 37'den 54'e ve yeniden işin 9'dan 20 tura çıkması, üç yazılmamış yordam yazıldığında geri dönen olayın 8'den 5'e ve akış sonunun 94'ten 84. tura inmesi.

Önceki ders kapsam değişikliğini denetime bağladı ve bedelini saydı, ama sayacı kalemin teslim
edildiği anda durdurdu. Teslim modelde son adımın bitmesidir; alanda servisin gece de ayakta
durması gereken ilk gündür.

**İşletim devri**, bir servisin işletme sorumluluğunun yazan ekipten işleten ekibe geçmesidir ve
tek parça değildir, kalem kalem devredilir. Bu ders devri bir **sözleşme** olarak modeller: hangi
kalem devredildi, devredilemeyen neden devredilemedi ve faturası nereye çıkıyor.

#### Devir Sözleşmesi Kalem Kalem

Örnek, kursun kurgu **bölgesel kütüphane ağı** ile onu yazan üç ekiptir; ağ da ekipler de
kurgudur. **ET28:** yedi servis üç yazan ekibe, bir de işletim ekibine dağılmıştır; `ortak-kayit`
servisine üç ekip birden dokunur. Her ekibin önünde altı kalem, kalem başına altı tur iş vardır.
**ET29:** gün on turdur; ilk altı turu mesai, son dördü gecedir ve kalem yalnız mesaide ilerler.
**ET30:** sözleşme dört sorumluluk kalemidir — koşum, ilk yanıt, yeniden başlatma, yapılandırma
değişikliği; devredilememenin nedeni **bilgi**, **araç** ya da **yordam** eksikliğidir. **ET31:**
ağır olay gece de karşılanır, hafif olay sabaha kalır. **ET32:** kesilen ekip yanıt süresi artı iki
tur toparlanma boyunca akıştan çıkar, kesinti kalemin ortasına düşerse en çok iki tur yeniden iş
yazılır, gece uyandırılan ekip ertesi sabah iki tur kaybeder. **ET33:** devredilmiş sorumluluğu
işletim ekibi iki turda kapatır; geri dönen olayın çözümü, bağlam ikinci elden kurulduğu için,
yazan ekibe üç tur tutar (paylaşımlı nöbette iki).

Sözleşme ile iki nöbet biçimi süreç içi bir **modeldir**; gerçek bir nöbet çizelgesi ya da olay
kaydı yoktur.

```js
// devir/nobet.mjs — kurgu kutuphane aginin isletim devri ve nobet modeli (model): gercek bir
// nobet cizelgesi ya da olay kaydi yok, turlar veri yapisidir. Rastgelelik yok.

export const GUN = 10, MESAI = 6;          // her gun 10 tur: ilk 6 tur mesai, son 4 tur gece
export const ILK = 1, UYAN = 2, AKTAR = 1, COZ_DEVIR = 2, COZ_YAZAN = 3, COZ_ICERI = 2;
export const TOPARLANMA = 2, UYKU = 2, YENIDEN_TAVAN = 2;
export const KALEM_IS = [6, 6, 6, 6, 6, 6];   // her yazan ekibin onundeki alti kalem
export const EKIPLER = ["E1", "E2", "E3"];

export const gece = (t) => t % GUN >= MESAI;
export const sabah = (t) => (Math.floor(t / GUN) + 1) * GUN;

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

// Devir sozlesmesi: servis, sahip ekip, dokunan ekip sayisi, dort sorumluluk. "+" devredildi;
// digerleri devredilemedi ve nedenini yazar (bilgi, arac, yordam).
export const SOZLESME = cizelge(`
  odunc           E2  1  +  +  +       bilgi
  ucret           E2  1  +  +  +       +
  sube-onyuz      E1  1  +  +  +       +
  uyelik-kapisi   E1  1  +  +  arac    arac
  katalog-kapisi  E3  1  +  +  +       yordam
  bildirim        E3  1  +  +  yordam  yordam
  ortak-kayit     E3  3  +  +  bilgi   bilgi`,
([servis, ekip, dokunan, ...h]) => ({ servis, ekip, dokunan: +dokunan,
  hak: { kosum: h[0], "ilk-yanit": h[1], "yeniden-baslatma": h[2], yapilandirma: h[3] } }));

// Olay: geldigi tur, servis, kapanmasi icin gereken sorumluluk, agirlik.
export const OLAY = cizelge(`
   3  odunc           yapilandirma      agir
   7  ucret           yeniden-baslatma  agir
  12  ortak-kayit     yapilandirma      agir
  16  bildirim        yeniden-baslatma  agir
  18  sube-onyuz      yapilandirma      agir
  23  uyelik-kapisi   yeniden-baslatma  agir
  27  katalog-kapisi  yapilandirma      hafif
  31  odunc           yeniden-baslatma  agir
  36  ortak-kayit     yeniden-baslatma  agir
  39  bildirim        yapilandirma      agir
  44  ucret           yapilandirma      agir
  47  uyelik-kapisi   yapilandirma      hafif
  50  katalog-kapisi  yeniden-baslatma  agir
  52  sube-onyuz      yeniden-baslatma  hafif`,
([tur, servis, cozum, a]) => ({ tur: +tur, servis, cozum, agir: a === "agir" }));

// bicim: "tam" isletim ekibi her olayi karsilar, "paylasimli" yazan ekip nobettedir.
// kapat: bu nedenle devredilememis kalemler kapatilmis sayilir (karsit koseum).
export function kos(bicim, kapat = null) {
  const S = Object.fromEntries(SOZLESME.map((s) => [s.servis, s]));
  const ekip = Object.fromEntries(EKIPLER.map((e) =>
    [e, { mesgul: 0, i: 0, yapilan: 0, cikan: 0, yenidenIs: 0, bitis: null }]));
  const plan = {}, kayit = [];
  const ekle = (e, t, sure) => ((plan[t] ??= []).push([e, sure]));
  const acik = (s, c) => s.hak[c] === "+" || s.hak[c] === kapat;

  const isle = (o, t) => {
    const s = S[o.servis];
    if (bicim === "tam" && acik(s, o.cozum))          // yazili yordamla isletim ekibi kapatir
      return { s, ilk: ILK, kapanis: ILK + COZ_DEVIR, eld: 1, geri: false, uyandi: false,
        kesinti: 0, neden: "-" };
    const geri = bicim === "tam";
    const eld = (geri ? 2 : 1) + (s.dokunan > 1 ? 1 : 0);
    const ak = AKTAR * (eld - 1), coz = geri ? COZ_YAZAN : COZ_ICERI;
    const ilkYanit = geri ? ILK : gece(t) ? (o.agir ? UYAN : sabah(t) - t) : ILK;
    const neden = geri ? s.hak[o.cozum] : "-";
    const ort = { s, ilk: ilkYanit, eld, geri, neden };
    if (!gece(t)) {
      const kesinti = (geri ? 0 : ILK) + ak + coz + TOPARLANMA;
      ekle(s.ekip, t, kesinti);
      return { ...ort, kapanis: ilkYanit + ak + coz, uyandi: false, kesinti };
    }
    if (o.agir) {                                     // gece uyandirma: bedeli ertesi sabah
      ekle(s.ekip, sabah(t), UYKU);
      return { ...ort, kapanis: (geri ? ILK + UYAN : UYAN) + ak + coz, uyandi: true,
        kesinti: UYKU };
    }
    const kesinti = ak + coz + TOPARLANMA;            // hafif gece olayi sabaha kalir
    ekle(s.ekip, sabah(t), kesinti);
    return { ...ort, kapanis: (geri ? sabah(t) - t : ilkYanit) + ak + coz, uyandi: false, kesinti };
  };

  const olaylar = bicim === "yok" ? [] : OLAY;
  for (let t = 0; t < 200; t++) {
    for (const o of olaylar.filter((x) => x.tur === t)) kayit.push({ o, ...isle(o, t) });
    for (const [e, sure] of plan[t] ?? []) {
      const k = ekip[e];
      k.mesgul += sure;
      const d = Math.min(k.yapilan, YENIDEN_TAVAN);   // kesinti kalemin ortasina dusmusse
      k.yapilan -= d; k.yenidenIs += d;
    }
    if (gece(t)) continue;                            // mesai disinda kalem ilerlemez
    for (const e of EKIPLER) {
      const k = ekip[e];
      if (k.bitis !== null) continue;
      if (k.mesgul > 0) { k.mesgul--; k.cikan++; continue; }
      if (++k.yapilan < KALEM_IS[k.i]) continue;
      k.yapilan = 0; k.i++;
      if (k.i >= KALEM_IS.length) k.bitis = t + 1;
    }
  }
  const top = (f) => EKIPLER.reduce((a, e) => a + f(ekip[e]), 0);
  const ort = (f) => (kayit.length ? kayit.reduce((a, x) => a + f(x), 0) / kayit.length : 0);
  return { kayit, ekip,
    ilk: ort((x) => x.ilk).toFixed(1), kapanis: ort((x) => x.kapanis).toFixed(1),
    eld: kayit.reduce((a, x) => a + x.eld, 0), geri: kayit.filter((x) => x.geri).length,
    uyandi: kayit.filter((x) => x.uyandi).length,
    cikan: top((k) => k.cikan), yenidenIs: top((k) => k.yenidenIs),
    son: Math.max(...EKIPLER.map((e) => ekip[e].bitis)) };
}
```

```js
// devir/olc.mjs — devir sozlesmesi, iki devir bicimi, devredilemeyenin bedeli, ekip siniri.
import { kos, SOZLESME, OLAY, gece } from "./nobet.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 ort = (a) => (a.length ? (a.reduce((s, x) => s + x, 0) / a.length).toFixed(1) : "-");
const SORUMLULUK = ["kosum", "ilk-yanit", "yeniden-baslatma", "yapilandirma"];

const kalem = SOZLESME.flatMap((s) => SORUMLULUK.map((c) => s.hak[c]));
const neden = ["bilgi", "arac", "yordam"];
const say = (x) => kalem.filter((k) => k === x).length;
console.log(`sozlesme: ${kalem.length} kalem, devredilen ${say("+")}, devredilemeyen ` +
  `${kalem.length - say("+")} (${neden.map((n) => `${n} ${say(n)}`).join(", ")})`);
const R = { yok: kos("yok"), tam: kos("tam"), paylasimli: kos("paylasimli"),
  yordam: kos("tam", "yordam") };
console.log(`\n${OLAY.length} olay, ${OLAY.filter((o) => gece(o.tur)).length} tanesi mesai disi, ` +
  `${OLAY.filter((o) => o.agir).length} tanesi agir; olaysiz akis ${R.yok.son}. turda biter`);

const O = [-30, 11, 18, 22];
console.log("\n1. ayni olay kumesi iki devir biciminde (ucuncu sutun: karsit kosum)");
yaz(O, "olcu", "tam devir", "paylasimli nobet", "tam devir + 3 yordam");
const OLCU = [["ilk yanit gecikmesi (tur)", "ilk"], ["kapanis gecikmesi (tur)", "kapanis"],
  ["el degistirme", "eld"], ["geri donen olay", "geri"], ["gece uyandirma", "uyandi"],
  ["akistan cikan tur", "cikan"], ["yeniden is (tur)", "yenidenIs"],
  ["gelistirme akisinin sonu", "son"]];
for (const [ad, a] of OLCU) yaz(O, ad, R.tam[a], R.paylasimli[a], R.yordam[a]);

const N = [-10, 7, 15, 15, 17];
console.log("\n2. tam devirde geri donen olayin nedeni");
yaz(N, "neden", "olay", "ort. kapanis", "kesinti turu", "gece uyandirma");
for (const n of neden) {
  const g = R.tam.kayit.filter((x) => x.neden === n);
  yaz(N, n, g.length, ort(g.map((x) => x.kapanis)), g.reduce((s, x) => s + x.kesinti, 0),
    g.filter((x) => x.uyandi).length);
}

const M = [-24, 7, 15, 20];
console.log("\n3. servis ekip siniriyla ortusuyor mu (tam devir)");
yaz(M, "servis", "olay", "ort. kapanis", "olay basina el deg.");
for (const [ad, f] of [["tek ekibin", (x) => x.s.dokunan === 1],
  ["birden cok ekibin", (x) => x.s.dokunan > 1]]) {
  const g = R.tam.kayit.filter(f);
  yaz(M, ad, g.length, ort(g.map((x) => x.kapanis)), ort(g.map((x) => x.eld)));
}
```

```
sozlesme: 28 kalem, devredilen 20, devredilemeyen 8 (bilgi 3, arac 2, yordam 3)

14 olay, 7 tanesi mesai disi, 11 tanesi agir; olaysiz akis 56. turda biter

1. ayni olay kumesi iki devir biciminde (ucuncu sutun: karsit kosum)
olcu                            tam devir  paylasimli nobet  tam devir + 3 yordam
ilk yanit gecikmesi (tur)             1.0               1.6                   1.0
kapanis gecikmesi (tur)               5.0               3.8                   4.1
el degistirme                          24                16                    21
geri donen olay                         8                 0                     5
gece uyandirma                          3                 5                     1
akistan cikan tur                      37                54                    27
yeniden is (tur)                        9                20                    10
gelistirme akisinin sonu               94               105                    84

2. tam devirde geri donen olayin nedeni
neden        olay   ort. kapanis   kesinti turu   gece uyandirma
bilgi           3            6.3             15                1
arac            2            6.0             12                0
yordam          3            7.0             10                2

3. servis ekip siniriyla ortusuyor mu (tam devir)
servis                     olay   ort. kapanis olay basina el deg.
tek ekibin                   12            4.7                 1.5
birden cok ekibin             2            7.0                 3.0
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır. Yirmi sekiz kalemin yirmisi
devredilir ve sözleşme çizelgesi şunu söyler: **koşum ile ilk yanıt yedi servisin yedisinde de
devredilmiştir**, devredilemeyen sekizin tamamı yeniden başlatma ile yapılandırma sütunlarındadır.
Devir, servisi ayakta tutmakta değil, ona dokunmak gerektiğinde durur.

#### Tam Devir ile Paylaşımlı Nöbet

Birinci tablonun ilk iki sütunu aynı on dört olayı iki biçimde karşılar. Tam devirde nöbetçi
işletim ekibidir ve ilk yanıt gecikmesi gece gündüz ayrımı olmadan 1,0 turdur; paylaşımlı nöbette
ilk yanıtı yazan ekip verir ve gecikme 1,6 tura çıkar, çünkü gece gelen hafif olay sabahı bekler.
Kapanışta sıra tersine döner: paylaşımlı nöbet 3,8, tam devir 5,0 turda kapatır. Fark, sekiz olayın
çözülemeyip yazan ekibe geri dönmesidir; her geri dönüş bir el değiştirme ve bağlamın ikinci elden
kurulmasıdır (24'e karşı 16 el değiştirme).

Fatura alt satırlardadır. Olay yokken üç ekip işini 56. turda bitirir; tam devirde akış 94.,
paylaşımlıda 105. tura uzar, akıştan çıkan tur 37'ye karşı 54 ve yeniden iş 9'a karşı 20'dir. Gece
uyandırma da paylaşımlıda yüksektir (5'e karşı 3): tam devirde yalnız devredilemeyen ağır gece
olayı uyandırır. **Paylaşımlı nöbet olayı daha hızlı kapatır ve bunu akıştan öder.**

#### Devredilemeyenin Bedeli

İkinci tablo geri dönen sekiz olayı nedenine göre ayırır. En pahalı neden **yazılmamış
yordam**dır: üç olay, ortalama 7,0 tur kapanış ve üç gece uyandırmanın ikisi. Bilgi eksikliği üç
olayda 6,3 tur ve en yüksek kesinti turunu (15) üretir; araç eksikliği iki olayda 6,0 turdur.

Birinci tablonun üçüncü sütunu yordamın fiyatını verir: üç yordam yazılınca geri dönen olay 8'den
5'e, gece uyandırma 3'ten 1'e, akıştan çıkan tur 37'den 27'ye ve akışın sonu 94'ten 84. tura iner.
**Yazılmamış yordam bir belge eksiği değil, on turluk akış gecikmesi ve iki gece uyandırmadır.**

#### Olay Hangi Ekip Sınırına Düşüyor

Üçüncü tablo olayları servisin ekip sınırıyla örtüşmesine göre ayırır. Tek ekibin servislerinde on
iki olay 4,7 turda ve olay başına 1,5 el değiştirmeyle kapanır; üç ekibin dokunduğu `ortak-kayit`
servisinde iki olay 7,0 turda ve 3,0 el değiştirmeyle. Nedeni sözleşmededir: o servisin
devredilemeyen iki kalemi de `bilgi` nedenlidir, çünkü bilgi tek bir ekipte durmaz. **Ekip
sınırıyla örtüşmeyen servis yalnız yazılırken değil, gece de pahalıdır.**

#### Özet

- Devir sözleşmesi 28 kaleme ayrıldı; 20'si devredildi, 8'i devredilemedi (bilgi 3, araç 2,
  yordam 3) ve devredilemeyenlerin tamamı yeniden başlatma ile yapılandırma sütunundadır.
- Aynı 14 olay tam devirde 5,0, paylaşımlı nöbette 3,8 turda kapanır; ilk yanıt tersinedir (1,0'a
  karşı 1,6) ve el değiştirme 24'e karşı 16'dır.
- Bedel geliştirme akışındadır: olaysız akış 56. turda biterken tam devirde 94., paylaşımlıda
  105. tura uzar; akıştan çıkan tur 37'ye karşı 54 ve yeniden iş 9'a karşı 20'dir.
- Üç yazılmamış yordam yazıldığında geri dönen olay 8'den 5'e, gece uyandırma 3'ten 1'e ve akış
  sonu 94'ten 84. tura iner; üç ekibin dokunduğu servisin olayı 7,0 turda ve 3,0 el değiştirmeyle
  kapanır (tek ekipte 4,7 ve 1,5).

#### Kurs Kapanışı

| Ders | Akış nesnesi | El değiştirme / bekleme / yeniden iş | Mimariyle uyumun bedeli |
|---|---|---|---|
| Yaşam Döngüsü Modelleri | 18 kalem, 4 döngü | 125 → 120 / 243 → 18 tur / 105 → 90 birim | yanlış sınır gecikmesi 14,8 → 7,8 tur |
| Çevik Çerçeveler | 30 kalem, 1–6 hafta | yarım kalan 8 → 0 / akış 12,5 → 31,2 gün / 19 → 23 adam-gün | 75 bağımlılık bağı yeniden işi belirler |
| Akış Tabanlı Yönetim | 60 kalem, sınır 1–16 | teslim 118,5 → 17,3 gün / bekleme payı %0 → %84,1 | sınır ekip değil iş sınırı; 195,9 adam-gün geçiş kaybı |
| Ölçekli Çerçeveler | 40 kalem, 1–12 ekip | eşgüdüm turu 0 → 66 / kalem başına 0 → 5,9 dönem | ortak kanal karesel; en az bedel 3 ekipte |
| Mühendislik Pratikleri | 48 kalem, 2–40 saat | olay 21 → 2 / gecikme 8,0 → 21,4 saat / 82 → 132 saat | yeniden iş aynı modüldeki kalemle büyür |
| Conway Yasası | 12 kalem, iki bölünme | 24 → 17 / 203 → 55 tur / 24 → 15 | sınırı geçen bağ 40/43 → 32/43; yolsuz ekip arası 16 → 0 |
| Ekip Topolojileri | 12 kalem, üç düzen | 24 / 17 / 25 — 203 / 55 / 78 tur — 24 / 15 / 22 | yük 1–13'ten 3–9'a iner, yinelenen uzmanlık 18 / 18 / 24 |
| Tahmin ve Planlama | 12 kalemin süresi | beklemeyi tahmine sokmak hatayı %58,4 → %23,5 yapar | 3+ ekipte bekleme payı %51,7 ve hata %72,2 (1–2 ekipte %24,3 ve %44,6) |
| Değişiklik Yönetimi | 8 kalem, 6 istek | 31 / 38 — 44 / 133 tur — 8 / 4 tur | sınır dışına düşen istek teslimi 23 yerine 28 tur yapar |
| İşletim Devri | 14 olay, 28 kalem | 24 / 16 — kapanış 5,0 / 3,8, akıştan çıkan 37 / 54 — 9 / 20 tur | üç ekibin servisinde el değiştirme 1,5 yerine 3,0 |

**Süreç, Ekip ve Teslimat** kursunun kuralı budur: **süreç ve ekip kararları mimariyi işin
beklediği yerden biçimlendirir.** Hiçbir ders bir süreci kendiliğinden iyi bulmadı; her biri aynı
iş kalemi kümesinde koşturuldu ve kazandığı yerde neyi kaybettiği sayıldı.

**Yazılım Mimarlığı** müfredatı burada biter. Beş kursun beş ölçü ekseni tek cümlede toplanır:
karar bir nesnedir ve izlenebilirliği ölçülür (**Mimarın Rolü**), belge yanıtladığı soruyla ölçülür
(**Mimari Karar ve Dokümantasyon**), kurum ölçeğinde ölçü bağdır (**Kurumsal Bağlam ve
Tümleştirme**), kural makinece denetlenebildiği ölçüde yönetilebilir (**Kalite Nitelikleri ve
Yönetişim**), süreç ve ekip kararları işin beklediği yerden ölçülür (**Süreç, Ekip ve Teslimat**).

