---
title: 'Mimarın Rolü'
source: 'https://academia.sh/tr/kurslar/mimarin-rolu'
language: tr
updated: '2026-08-17T04:42:28+00:00'
license: 'CC BY-SA 4.0'
lessons: 11
outcomes:
    - 'Mimarlık düzeylerini ve her düzeyin karar kapsamını ayırır'
    - 'Mimarın teknik ve teknik olmayan sorumluluklarını tanımlar'
    - 'Basitleştirme ve denge kurma pratiğini uygular'
---

# Mimarın Rolü

Mimarlığın bir kararlar kümesi ve bir rol olarak tanımlanması: değiştirilmesi pahalı kararların ayırt edilmesi, uygulama, çözüm ve kurumsal düzeylerin karar kapsamıyla ayrılması, karar, iletişim ve gözetim sorumlulukları, mimar ile geliştirici ilişkisinde fildişi kule sorunu, kararın ekibe aktarılması ve denge kurma, basitleştirme, geri döndürülebilirlik, paydaş yönetimi, teknoloji değerlendirme ile sürekli öğrenme pratikleri.

## Mimarlık Nedir

Mimarlığın tanımı ve kapsamı: değiştirilmesi pahalı kararların ayırt edilmesi, uygulama, çözüm ve kurumsal düzeylerin karar kapsamıyla ayrılması, karar, iletişim ve gözetim sorumlulukları, koddan kopan kararın fildişi kule sorununa dönüşmesi ve kararın danışmanlık ile koçlukla ekibe aktarılması.

### Yazılım Mimarisi Tanımı

Source: https://academia.sh/tr/kurslar/mimarin-rolu/yazilim-mimarisi-tanimi

Yazılım mimarisinin geri alınması pahalı kararlar kümesi olarak tanımlanması: model bir kod tabanında her kararın geri alınma maliyetinin bağımlı kapanıştan okunması, kararların bu sayıya göre sıralanması, eşiğin kaynağının yazılması ve gövde büyüklüğüne göre sıralamayla karşılaştırılması.

Önkoşul müfredatlar kararların kendisini kurdu. Yazılım Tasarımı müfredatı bağlaşımı, bütünlüğü,
tasarım kalıplarını ve mimari biçemleri tanımladı ve her birini ölçtü; Sistem Tasarımı müfredatı
ölçekleme, dayanıklılık ve veri dağıtımı kararlarını varsayımdan hesaba, hesaptan ölçüme bağladı.
İki müfredat da şu soruya yanıt verdi: bu seçenekler arasındaki fark nedir ve hangi sayıyla
görünür.

Hiçbiri şunu sormadı: bu kararı **kim**, neye göre, hangi alternatifi eleyerek verir ve karar
verildikten sonra ona ne olur. Bu müfredatın konusu kararların kendisi değil, kararın süreci ve
izidir. İlk soru tanımdır: bir kod tabanındaki yüzlerce karardan hangileri "mimari" sayılır. Bu
ders o ayrımı bir sayıya bağlar — kararın **geri alınma maliyeti**ne.

#### Kararın Gövdesi ve Geri Alınması

Bir karar kodda bir yerde durur. "Ödünç süresi kuralı yapılandırmadan okunur" kararının gövdesi
kural modülüdür; "kimlik doğrulama tek modülde toplanır" kararının gövdesi o modüldür. Gövde
küçük olabilir. Kararı geri almanın maliyeti ise gövdeyle değil, gövdeye bağımlı olan her şeyle
ölçülür: kararı bozmak için gövdeyi değiştirmek yetmez, gövdeye doğrudan ya da dolaylı bağımlı
her modüle dokunmak gerekir.

Ölçüm için bir kod tabanı gerekir. Aşağıdaki dosya, bu müfredat boyunca sürecek örneğin
modelidir: **bölgesel bir kütüphane ağının yazılım sistemi**. Ağda birden çok şube, kendi
bütçesi olan bir bilgi işlem birimi, dışarıdan alınmış bir katalog sistemi ve içeride yazılmış
ödünç servisleri vardır. Bu bir modeldir; gerçek bir kurum anlatılmıyor. Modül adları, dosya
sayıları ve ithal kenarları elle seçilmiştir (**MN1**).

```js
// mimari/kod-tabani.mjs — bolgesel kutuphane agi yazilim sisteminin MODEL kod tabani.
// Gercek bir kurum degildir; modul adlari, dosya sayilari ve ithal kenarlari elle secilmistir.
export const DOSYA = {
  yapilandirma: 3, kayit: 4, zaman: 2, "veri-erisim": 9, "olay-yolu": 7,
  "kimlik-dogrulama": 8, yetki: 5, "katalog-baglayici": 11, "katalog-onbellek": 6,
  "odunc-kural": 5, "odunc-cekirdek": 14, ayirtma: 8, "uye-kayit": 9, "uye-ceza": 6,
  "sube-envanter": 10, "sube-esitleme": 12, "bildirim-kuyruk": 6, "bildirim-eposta": 15,
  "rapor-gunluk": 7, "rapor-toplu": 13, "web-ucu": 18, "personel-ucu": 22,
  "kiosk-ucu": 9, "toplu-is": 8,
};

// ITHAL[a] = a modulunun ithal ettigi moduller (a -> b: a, b'ye baglidir)
export const ITHAL = {
  yapilandirma: [], zaman: [], kayit: ["yapilandirma"],
  "veri-erisim": ["yapilandirma", "kayit"],
  "olay-yolu": ["yapilandirma", "kayit"],
  "kimlik-dogrulama": ["veri-erisim", "yapilandirma", "kayit"],
  yetki: ["kimlik-dogrulama"],
  "katalog-baglayici": ["yapilandirma", "kayit"],
  "katalog-onbellek": ["katalog-baglayici", "zaman"],
  "odunc-kural": ["yapilandirma", "zaman"],
  "odunc-cekirdek": ["odunc-kural", "veri-erisim", "olay-yolu", "zaman", "katalog-baglayici"],
  ayirtma: ["odunc-cekirdek", "bildirim-kuyruk", "veri-erisim"],
  "uye-kayit": ["veri-erisim", "kayit"],
  "uye-ceza": ["uye-kayit", "odunc-kural", "zaman", "veri-erisim"],
  "sube-envanter": ["veri-erisim", "olay-yolu"],
  "sube-esitleme": ["sube-envanter", "olay-yolu", "katalog-baglayici", "kayit"],
  "bildirim-kuyruk": ["veri-erisim", "olay-yolu"],
  "bildirim-eposta": ["bildirim-kuyruk", "yapilandirma"],
  "rapor-gunluk": ["veri-erisim", "zaman"],
  "rapor-toplu": ["veri-erisim", "sube-envanter", "zaman", "kayit"],
  "web-ucu": ["odunc-cekirdek", "katalog-onbellek", "uye-kayit", "ayirtma", "kimlik-dogrulama"],
  "personel-ucu": ["odunc-cekirdek", "uye-kayit", "uye-ceza", "sube-envanter", "rapor-gunluk",
    "kimlik-dogrulama", "yetki"],
  "kiosk-ucu": ["odunc-cekirdek", "katalog-onbellek", "kimlik-dogrulama"],
  "toplu-is": ["rapor-toplu", "sube-esitleme", "bildirim-kuyruk", "bildirim-eposta"],
};

// KARAR[i].govde = kararin kodda karsiligi olan moduller (kararin govdesi)
export const KARAR = [
  { ad: "veri erisimi tek katmandan gecer", govde: ["veri-erisim"] },
  { ad: "ayar degerleri tek kaynaktan okunur", govde: ["yapilandirma"] },
  { ad: "envanter olay yolu uzerinden esitlenir", govde: ["olay-yolu", "sube-esitleme"] },
  { ad: "dis kataloga tek baglayici uzerinden erisilir", govde: ["katalog-baglayici"] },
  { ad: "kimlik dogrulama tek modulde toplanir", govde: ["kimlik-dogrulama"] },
  { ad: "odunc suresi kurali yapilandirmadan okunur", govde: ["odunc-kural"] },
  { ad: "saat kaynagi tek modulden alinir", govde: ["zaman"] },
  { ad: "ceza hesabi uye kaydindan ayri durur", govde: ["uye-ceza"] },
  { ad: "gunluk rapor ayri bir modulde uretilir", govde: ["rapor-gunluk"] },
  { ad: "eposta bildirimi duz metin govdeyle gider", govde: ["bildirim-eposta"] },
  { ad: "kiosk ucu ayri bir dagitim birimidir", govde: ["kiosk-ucu"] },
];

export const MODULLER = Object.keys(DOSYA);

// b modulune dogrudan ya da dolayli olarak bagimli olan moduller (ters kapanis)
export function bagimliKapanis(cekirdek) {
  const kapali = new Set(cekirdek);
  let buyudu = true;
  while (buyudu) {
    buyudu = false;
    for (const m of MODULLER) {
      if (kapali.has(m)) continue;
      if (ITHAL[m].some((h) => kapali.has(h))) { kapali.add(m); buyudu = true; }
    }
  }
  return kapali;
}

export const dosyaTopla = (kume) => [...kume].reduce((t, m) => t + DOSYA[m], 0);
```

Ölçünün tanımı `bagimliKapanis` işlevindedir: bir modül kümesinden başlanır ve kümedeki bir
modüle bağımlı olan her modül kümeye eklenir; küme büyümeyi durdurana kadar sürer. Bu, kararın
**erişim alanı**dır. Geri alma maliyeti bu alandaki modül ve dosya sayısıdır (**MN2**). Sayı bir
üst sınırdır: bağımlı her modüle gerçekten dokunulacağı varsayılıyor, bazılarında değişiklik
gerekmeyebilir. Alt sınır değil üst sınır ölçmek, bu derste kasıtlıdır — kararın ne kadar
pahalıya mal olabileceği sorulmaktadır.

#### Ölçüm

İkinci dosya on bir kararı sıralar ve iki eşik dener.

```js
// mimari/geri-alma.mjs — her kararin geri alinma maliyeti ve iki siralamanin karsilastirmasi
import { DOSYA, KARAR, MODULLER, bagimliKapanis, dosyaTopla } from "./kod-tabani.mjs";

const toplamDosya = dosyaTopla(new Set(MODULLER));
console.log(`model kod tabani: ${MODULLER.length} modul, ${toplamDosya} dosya`);

const olcum = KARAR.map((k) => {
  const yerelDosya = k.govde.reduce((t, m) => t + DOSYA[m], 0);
  const kapali = bagimliKapanis(k.govde);
  return { ad: k.ad, yerelModul: k.govde.length, yerelDosya,
    yayilanModul: kapali.size, yayilanDosya: dosyaTopla(kapali) };
});
const sirali = [...olcum].sort((a, b) => b.yayilanDosya - a.yayilanDosya);

const sut = (s, n) => String(s).padEnd(n);
console.log("\n" + sut("karar", 46) + sut("govde", 10) + sut("geri alma", 12) + "kat");
console.log("-".repeat(74));
for (const o of sirali)
  console.log(sut(o.ad, 46) + sut(`${o.yerelModul}m/${o.yerelDosya}d`, 10) +
    sut(`${o.yayilanModul}m/${o.yayilanDosya}d`, 12) + (o.yayilanDosya / o.yerelDosya).toFixed(1) + "x");

// esik 1: acikca secilmis kural — kod tabaninin yarisindan cogu
const esikA = Math.floor(toplamDosya / 2) + 1;
const ustA = sirali.filter((o) => o.yayilanDosya >= esikA);
const ort = (d) => (d.reduce((t, o) => t + o.yayilanDosya, 0) / d.length).toFixed(1);
console.log(`\nesik A (secilmis kural, kod tabaninin yarisi) = ${esikA} dosya`);
console.log(`  ustunde ${ustA.length} karar (ort. ${ort(ustA)} dosya), altinda ${sirali.length - ustA.length} karar (ort. ${ort(sirali.slice(ustA.length))} dosya)`);
console.log(`  esige en yakin karar esigin ${esikA - sirali[ustA.length].yayilanDosya} dosya altinda`);

// esik 2: siralamadaki en buyuk mutlak bosluk
let enBosluk = 0, kesim = 0;
for (let i = 0; i < sirali.length - 1; i++) {
  const b = sirali[i].yayilanDosya - sirali[i + 1].yayilanDosya;
  if (b > enBosluk) { enBosluk = b; kesim = i + 1; }
}
console.log(`esik B (siralamadaki en buyuk bosluk) = ${sirali[kesim].yayilanDosya + 1} dosya (${sirali[kesim - 1].yayilanDosya} -> ${sirali[kesim].yayilanDosya}, ${enBosluk} dosya atlama)`);
console.log(`  ustunde ${kesim} karar, altinda ${sirali.length - kesim} karar`);
console.log(`iki esigin ortak sectigi karar = ${kesim} / ${ustA.length}; siralama ayni, sinir farkli`);

// karsilastirma: govde buyuklugune gore siralama / geri alma maliyetine gore siralama
const A = [...olcum].sort((a, b) => b.yerelDosya - a.yerelDosya).map((o) => o.ad);
const B = sirali.map((o) => o.ad);
let ters = 0;
for (let i = 0; i < A.length; i++)
  for (let j = i + 1; j < A.length; j++) if (B.indexOf(A[i]) > B.indexOf(A[j])) ters++;
const cift = (A.length * (A.length - 1)) / 2;
const ortak = A.slice(0, 4).filter((x) => B.slice(0, 4).includes(x)).length;
console.log(`\ngovde siralamasi <-> geri alma siralamasi: ${ters}/${cift} cift ters (${((ters / cift) * 100).toFixed(0)}%)`);
console.log(`ilk dort kararda ortusme = ${ortak}/4`);
const enA = olcum.find((o) => o.ad === A[0]), enB = olcum.find((o) => o.ad === B[0]);
console.log(`govdesi en buyuk karar : ${enA.yerelDosya} dosya govde, ${enA.yayilanDosya} dosya geri alma`);
console.log(`geri almasi en pahali  : ${enB.yerelDosya} dosya govde, ${enB.yayilanDosya} dosya geri alma`);
```

```
model kod tabani: 24 modul, 217 dosya

karar                                         govde     geri alma   kat
--------------------------------------------------------------------------
ayar degerleri tek kaynaktan okunur           1m/3d     23m/215d    71.7x
veri erisimi tek katmandan gecer              1m/9d     17m/179d    19.9x
envanter olay yolu uzerinden esitlenir        2m/19d    12m/142d    7.5x
saat kaynagi tek modulden alinir              1m/2d     12m/118d    59.0x
dis kataloga tek baglayici uzerinden erisilir 1m/11d    9m/108d     9.8x
odunc suresi kurali yapilandirmadan okunur    1m/5d     7m/82d      16.4x
kimlik dogrulama tek modulde toplanir         1m/8d     5m/62d      7.8x
gunluk rapor ayri bir modulde uretilir        1m/7d     2m/29d      4.1x
ceza hesabi uye kaydindan ayri durur          1m/6d     2m/28d      4.7x
eposta bildirimi duz metin govdeyle gider     1m/15d    2m/23d      1.5x
kiosk ucu ayri bir dagitim birimidir          1m/9d     1m/9d       1.0x

esik A (secilmis kural, kod tabaninin yarisi) = 109 dosya
  ustunde 4 karar (ort. 163.5 dosya), altinda 7 karar (ort. 48.7 dosya)
  esige en yakin karar esigin 1 dosya altinda
esik B (siralamadaki en buyuk bosluk) = 143 dosya (179 -> 142, 37 dosya atlama)
  ustunde 2 karar, altinda 9 karar
iki esigin ortak sectigi karar = 2 / 4; siralama ayni, sinir farkli

govde siralamasi <-> geri alma siralamasi: 31/55 cift ters (56%)
ilk dort kararda ortusme = 2/4
govdesi en buyuk karar : 19 dosya govde, 142 dosya geri alma
geri almasi en pahali  : 3 dosya govde, 215 dosya geri alma
```

Tablonun son sütunu ölçünün asıl bulgusudur. Ayar değerlerinin tek kaynaktan okunması kararı üç
dosyalık bir gövdede durur; geri alınması 23 modüle ve 215 dosyaya, yani model kod tabanının
neredeyse tamamına dokunur — **71,7 kat**. Saat kaynağının tek modülden alınması iki dosyalık bir
gövdeyle 118 dosyaya yayılır. Öteki uçta, kiosk ucunun ayrı bir dağıtım birimi olması kararı
dokuz dosyada başlar ve dokuz dosyada biter: hiçbir modül ona bağımlı değildir, oran **1,0**.

#### Eşiğin Kaynağı

Sıralama tek başına bir ayrım vermez; ayrım için bir eşik gerekir ve eşiğin bir kaynağı olmak
zorundadır. Çıktıda iki eşik denendi. Eşik A açıkça seçilmiş bir kuraldır: geri alınması kod
tabanının yarısından çoğuna dokunan karar (**MN3**). Bu kural 109 dosya sınırını verir ve dört
kararı ayırır; üstteki dördün ortalaması 163,5, alttaki yedinin ortalaması 48,7 dosyadır — aradaki
oran 3,4. Eşik B ölçülen dağılımdan gelir: sıralamadaki en büyük atlama 179'dan 142'ye düşen 37
dosyalık boşluktur ve iki kararı ayırır.

İki eşik farklı sayılar veriyor ve bu, tanımın kırılgan yeri. Eşik A'ya en yakın karar sınırın
**bir dosya** altında kalıyor; bir dosyalık bir fark kararı sınıf değiştiriyor. Buradan çıkan
kural şudur: sıralama savunulabilir, sınır tartışmaya açıktır. Bir karara "mimari açıdan önemli"
denirken söylenmesi gereken şey sınıf değil, sıradaki yer ve o yeri veren sayıdır. "Bu karar
mimaridir" cümlesi ölçüsüzdür; "bu kararı geri almak 23 modüle, 215 dosyaya dokunur" cümlesi
denetlenebilir.

#### Gövdeye Bakmak Neden Yanıltır

Karşılaştırma iki sıralamayı aynı girdide koşturuyor. Birincisi kararı **gövdesinin**
büyüklüğüne göre sıralıyor: değişiklik ne kadar yer kaplıyor. İkincisi geri alma maliyetine göre
sıralıyor. Aynı on bir karar için iki sıralama 55 çiftin 31'inde ters düşüyor — **%56**. İlk dört
sırada yalnız iki karar ortak.

Uçlar farkı açıkça gösteriyor. Gövdesi en büyük karar 19 dosyalık bir gövdeye sahip ve geri
alınması 142 dosyaya dokunuyor; geri alınması en pahalı karar ise üç dosyalık bir gövdede duruyor
ve 215 dosyaya dokunuyor. E-posta bildiriminin düz metin gövdeyle gitmesi kararı gövde
büyüklüğünde 15 dosyayla üst sıralarda, geri alma maliyetinde 23 dosyayla sondan üçüncü. Bir
gözden geçirmede "büyük değişiklik" diye işaretlenecek olan odur; geri alınamayacak olan ise üç
satırlık ayar okuma kararıdır.

Bu, ölçünün yönünü belirler. Bir kararın ağırlığı yazılırken harcanan emekten değil, kararın
başkalarınca ne kadar varsayıldığından okunur. Yazılım Tasarımı müfredatının bağlaşım ölçüsüyle
aynı yöne bakılıyor; fark, oradaki ölçünün modüller arası bağı, buradakinin bir **kararın**
erişim alanını sayması.

#### Tanım

Ölçü tanımı verir. **Yazılım mimarisi** (software architecture), bir sistemin geri alınması
pahalı kararlarının kümesidir. "Pahalı" sözcüğü bu derste bir sayıya bağlandı: kararı bozmak için
dokunulması gereken modül ve dosya sayısı. **Mimari açıdan önemli karar** (architecturally
significant decision), bu sayı seçilmiş bir eşiğin üstünde kalan karardır; eşik yazılır ve
kaynağı söylenir.

Aynı ölçü ikinci bir ayrımı da verir. **Geri döndürülebilir karar**, erişim alanı küçük olan
karardır — kiosk ucunun ayrı bir dağıtım birimi olması gibi, dokuz dosyada başlayıp biten bir
seçim. **Geri döndürülemez karar** diye anılan şey mutlak bir engel değil, alanı büyüdükçe geri
alma maliyeti kod tabanının tamamına yaklaşan karardır. İki uç arasındaki fark bu modelde 215'e
9, yani 23,9 kattır.

Tanımın pratik sonucu şudur: bir kararın mimari olup olmadığı kararın konusuna bakarak
söylenemez. Ödünç süresi kuralının nereden okunduğu küçük bir ayrıntı gibi görünür ve model kod
tabanında 82 dosyaya dokunur; bir mimari biçemin seçimi büyük bir karar gibi görünür ve o seçimin
gerçek ağırlığı da yine erişim alanından okunur. Mimari Biçemler kursunda kurulan katmanlı,
altıgen, olay güdümlü ve mikroservis biçemleri bu müfredatta yeniden anlatılmayacak; bu kursun
konusu biçemin kendisi değil, o biçemi seçen karardır.

#### Özet

- Bir kararın gövdesi kodda karşılığı olan modül kümesidir; geri alma maliyeti ise gövdeye
  doğrudan ya da dolaylı bağımlı bütün modüllerin dosya sayısıdır.
- Model kod tabanında (24 modül, 217 dosya) on bir karar ölçüldü; en pahalı kararın gövdesi üç
  dosya, erişim alanı 215 dosyaydı — 71,7 kat.
- Eşik yazılmadan ayrım olmaz: kod tabanının yarısı kuralı dört kararı ayırdı (ortalamalar 163,5
  ve 48,7 dosya), sıralamadaki en büyük boşluk kuralı iki kararı ayırdı; eşiğe en yakın karar
  sınırın bir dosya altında kaldı.
- Gövde büyüklüğüne göre sıralamayla geri alma maliyetine göre sıralama 55 çiftin 31'inde ters
  düştü; gövdesi en büyük karar 142 dosyaya, gövdesi en küçüklerden biri 215 dosyaya dokunuyor.
- Yazılım mimarisi, geri alınması pahalı kararların kümesidir; "bu karar mimaridir" cümlesi
  ölçüsüzdür, yerine dokunulan modül ve dosya sayısı yazılır.

#### Sonraki Adım

Bu ders kararları tek bir kod tabanı üzerinde ölçtü ve hepsini aynı düzlemde sıraladı. Oysa
çıktıdaki kararların hepsi aynı yerde verilmez. Ayar değerlerinin nereden okunacağı tek bir
uygulamanın içinde kalabilir; şubeler arası envanterin nasıl eşitleneceği birden çok uygulamayı
ilgilendirir; dışarıdan alınan katalog sistemine tek bağlayıcı üzerinden erişilmesi ise bütün
şubeleri ve bilgi işlem biriminin bütçesini bağlar. Sonraki ders aynı karar kümesini üç düzeye
dağıtır — uygulama, çözüm ve kurumsal mimari — ve her düzeyin kaç kararı kapsadığını, kaç birimi
etkilediğini sayar. Asıl ölçülecek olan şudur: bir karar yanlış düzeyde verildiğinde kaç birim
habersiz kalır ve aynı karar kaç kez yeniden verilir.

### Mimarlık Düzeyleri

Source: https://academia.sh/tr/kurslar/mimarin-rolu/mimarlik-duzeyleri

Uygulama, çözüm ve kurumsal mimarinin karar kapsamıyla ayrılması: aynı karar kümesinin işlettiği birimlere göre üç düzeye dağıtılması, her düzeyin kapsadığı karar ve etkilediği birim sayısı, kararın yanlış düzeyde verilmesinde habersiz kalan birim, yinelenen karar ve çelişen gerçekleştirim sayıları.

Önceki ders on bir kararı tek bir kod tabanı üzerinde ölçtü ve hepsini aynı düzlemde sıraladı.
Oysa o kararların hepsi aynı yerde verilmez. Ayar değerlerinin nereden okunacağı bütün sistemi
bağlar; günlük raporun ayrı bir modülde üretilmesi iki birimin ötesine geçmez; kiosk ucunun ayrı
bir dağıtım birimi olması yalnız kendi içinde kalır.

Mimarlık düzeyleri bu ayrımın adıdır: **uygulama mimarisi**, **çözüm mimarisi** ve **kurumsal
mimari**. Üç düzey genellikle unvanla anlatılır. Bu derste unvanla değil kapsamla tanımlanıyorlar
ve kapsam sayılıyor: bir karar kaç dağıtım birimini bağlıyor.

#### Düzeyi Kapsam Belirler

Önceki dersin erişim alanı ölçüsü modül düzeyindeydi. Düzey sorusu için bir eşleme daha gerekir:
hangi modülü hangi birim işletiyor. **Dağıtım birimi** ayrı yayınlanan, ayrı koşan ve genellikle
ayrı bir ekibin baktığı parçadır; Yazılım Tasarımı müfredatının alan odaklı tasarım kursunda
kurulan sınırlı bağlam ayrımıyla aynı yöne bakar, ama sınırı çizen şey burada alan değil işletme
sorumluluğudur.

Bir kararın kapsamı şudur: kararın erişim alanındaki modüllerden en az birini işleten birimlerin
kümesi (**MN4**). Kapsam bir birimse karar uygulama düzeyindedir; bütün ağı ya da ağın büyük
bölümünü bağlıyorsa kurumsal; ikisinin arasındaysa çözüm düzeyindedir. "Büyük bölüm" bir eşiktir
ve eşiğin kaynağı yazılmalıdır: burada birimlerin üçte ikisi seçildi (**MN5**).

İlk dosya önceki dersin ithal grafiğini ve karar gövdelerini yeniden verir; blok kendi başına
çalışsın diye grafik tekrarlanıyor.

```js
// mimari/model.mjs — MODEL kutuphane agi kod tabani: ithal grafigi ve kararlarin govdesi.
// Gercek bir kurum degildir; kenarlar ve karar govdeleri elle secilmistir.
export const ITHAL = {
  yapilandirma: [], zaman: [], kayit: ["yapilandirma"],
  "veri-erisim": ["yapilandirma", "kayit"], "olay-yolu": ["yapilandirma", "kayit"],
  "kimlik-dogrulama": ["veri-erisim", "yapilandirma", "kayit"], yetki: ["kimlik-dogrulama"],
  "katalog-baglayici": ["yapilandirma", "kayit"],
  "katalog-onbellek": ["katalog-baglayici", "zaman"],
  "odunc-kural": ["yapilandirma", "zaman"],
  "odunc-cekirdek": ["odunc-kural", "veri-erisim", "olay-yolu", "zaman", "katalog-baglayici"],
  ayirtma: ["odunc-cekirdek", "bildirim-kuyruk", "veri-erisim"],
  "uye-kayit": ["veri-erisim", "kayit"],
  "uye-ceza": ["uye-kayit", "odunc-kural", "zaman", "veri-erisim"],
  "sube-envanter": ["veri-erisim", "olay-yolu"],
  "sube-esitleme": ["sube-envanter", "olay-yolu", "katalog-baglayici", "kayit"],
  "bildirim-kuyruk": ["veri-erisim", "olay-yolu"],
  "bildirim-eposta": ["bildirim-kuyruk", "yapilandirma"],
  "rapor-gunluk": ["veri-erisim", "zaman"],
  "rapor-toplu": ["veri-erisim", "sube-envanter", "zaman", "kayit"],
  "web-ucu": ["odunc-cekirdek", "katalog-onbellek", "uye-kayit", "ayirtma", "kimlik-dogrulama"],
  "personel-ucu": ["odunc-cekirdek", "uye-kayit", "uye-ceza", "sube-envanter", "rapor-gunluk",
    "kimlik-dogrulama", "yetki"],
  "kiosk-ucu": ["odunc-cekirdek", "katalog-onbellek", "kimlik-dogrulama"],
  "toplu-is": ["rapor-toplu", "sube-esitleme", "bildirim-kuyruk", "bildirim-eposta"],
};
export const KARAR = [
  { ad: "veri erisimi tek katmandan gecer", govde: ["veri-erisim"] },
  { ad: "ayar degerleri tek kaynaktan okunur", govde: ["yapilandirma"] },
  { ad: "envanter olay yolu uzerinden esitlenir", govde: ["olay-yolu", "sube-esitleme"] },
  { ad: "dis kataloga tek baglayici uzerinden erisilir", govde: ["katalog-baglayici"] },
  { ad: "kimlik dogrulama tek modulde toplanir", govde: ["kimlik-dogrulama"] },
  { ad: "odunc suresi kurali yapilandirmadan okunur", govde: ["odunc-kural"] },
  { ad: "saat kaynagi tek modulden alinir", govde: ["zaman"] },
  { ad: "ceza hesabi uye kaydindan ayri durur", govde: ["uye-ceza"] },
  { ad: "gunluk rapor ayri bir modulde uretilir", govde: ["rapor-gunluk"] },
  { ad: "eposta bildirimi duz metin govdeyle gider", govde: ["bildirim-eposta"] },
  { ad: "kiosk ucu ayri bir dagitim birimidir", govde: ["kiosk-ucu"] },
];
export const MODULLER = Object.keys(ITHAL);
export function bagimliKapanis(cekirdek) {
  const kapali = new Set(cekirdek);
  for (let buyudu = true; buyudu; ) {
    buyudu = false;
    for (const m of MODULLER)
      if (!kapali.has(m) && ITHAL[m].some((h) => kapali.has(h))) { kapali.add(m); buyudu = true; }
  }
  return kapali;
}
```

#### Ölçüm

İkinci dosya birim eşlemesini kurar, her kararın kapsamını sayar ve aynı karar kümesini üç
düzende koşturur.

```js
// mimari/duzey.mjs — kararlarin kapsadigi birim sayisi ve uc duzeye dagilimi
import { KARAR, bagimliKapanis } from "./model.mjs";

// BIRIM — MODEL kutuphane aginin dagitim birimleri; her birim hangi modulleri isletir
const BIRIM = {
  "web-portali": ["web-ucu"],
  "personel-uygulamasi": ["personel-ucu"],
  "kiosk-agi": ["kiosk-ucu"],
  "odunc-servisi": ["odunc-cekirdek", "odunc-kural", "ayirtma"],
  "uye-servisi": ["uye-kayit", "uye-ceza"],
  "katalog-tumlestirme": ["katalog-baglayici", "katalog-onbellek"],
  "envanter-servisi": ["sube-envanter", "sube-esitleme"],
  "bildirim-servisi": ["bildirim-kuyruk", "bildirim-eposta"],
  "rapor-servisi": ["rapor-gunluk", "rapor-toplu", "toplu-is"],
  "ortak-altyapi": ["yapilandirma", "kayit", "zaman", "veri-erisim", "olay-yolu",
    "kimlik-dogrulama", "yetki"],
};
const BIRIMLER = Object.keys(BIRIM);
const B = BIRIMLER.length;
const KURUMSAL_ESIK = Math.ceil((B * 2) / 3); // secilmis kural: birimlerin ucte ikisi

const kapsam = (k) => {
  const alan = bagimliKapanis(k.govde);
  return BIRIMLER.filter((b) => BIRIM[b].some((m) => alan.has(m)));
};
const duzeyAdi = (n, e = KURUMSAL_ESIK) => (n === 1 ? "uygulama" : n >= e ? "kurumsal" : "cozum");

const olcum = KARAR.map((k) => ({ ad: k.ad, n: kapsam(k).length, kume: kapsam(k) }));
const sut = (s, n) => String(s).padEnd(n);
console.log(`${B} birim, ${KARAR.length} karar, kurumsal esigi = ${KURUMSAL_ESIK} birim\n`);
console.log(sut("karar", 46) + sut("birim", 8) + "duzey");
console.log("-".repeat(64));
for (const o of [...olcum].sort((a, b) => b.n - a.n)) console.log(sut(o.ad, 46) + sut(o.n, 8) + duzeyAdi(o.n));

console.log("");
for (const d of ["kurumsal", "cozum", "uygulama"]) {
  const g = olcum.filter((o) => duzeyAdi(o.n) === d);
  const etkilenen = new Set(g.flatMap((o) => o.kume));
  console.log(`${sut(d, 10)} karar=${sut(g.length, 4)} etkiledigi birim=${sut(etkilenen.size, 4)} ort. kapsam=${(g.reduce((t, o) => t + o.n, 0) / g.length).toFixed(1)}`);
}
console.log("esik duyarliligi: " + [6, 7, 8].map((e) =>
  `esik ${e} -> ${olcum.filter((o) => duzeyAdi(o.n, e) === "kurumsal").length} kurumsal`).join(", "));

// ---- karsilastirma: ayni karar kumesi uc duzende ----
// SECENEK[k] = kararin makul secenek sayisi; bagimsiz veren birim bunlardan birini secer
const SECENEK = [3, 4, 3, 2, 3, 4, 2, 3, 2, 3, 2];
function uretec(tohum) { let s = tohum >>> 0; return () => (s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32; }
const rast = uretec(48151); // tohum gorunur; ayni tohum ayni sayilari verir

let habersiz = 0, yineleme = 0, celisen = 0;
olcum.forEach((o, i) => {
  const oteki = o.n - 1;               // kararin sahibi disindaki kapsam birimleri
  habersiz += oteki; yineleme += oteki;
  const sahibinSecimi = Math.floor(rast() * SECENEK[i]);
  for (let j = 0; j < oteki; j++) if (Math.floor(rast() * SECENEK[i]) !== sahibinSecimi) celisen++;
});
const danismaYerel = 0, danismaUc = olcum.reduce((t, o) => t + o.n - 1, 0), danismaMerkez = KARAR.length * (B - 1);

console.log(`\n${sut("duzen", 12) + sut("habersiz", 10) + sut("yineleme", 10) + sut("celisen", 9)}danisma`);
console.log("-".repeat(50));
console.log(sut("yerel", 12) + sut(habersiz, 10) + sut(yineleme, 10) + sut(celisen, 9) + danismaYerel);
console.log(sut("uc duzey", 12) + sut(0, 10) + sut(0, 10) + sut(0, 9) + danismaUc);
console.log(sut("merkezi", 12) + sut(0, 10) + sut(0, 10) + sut(0, 9) + danismaMerkez);

console.log(`\nyerel duzen ${danismaUc} danismadan kacinir, karsiliginda ${celisen} celisen gerceklestirim alir`);
console.log(`basabas: bir celisen gerceklestirim ${(danismaUc / celisen).toFixed(2)} danismadan pahaliysa uc duzey kazanir`);
console.log(`merkezi duzen uc duzeyden ${danismaMerkez - danismaUc} fazla danisma harcar, celisen sayisi ikisinde de 0`);
const tekil = olcum.filter((o) => o.n === 1).length;
console.log(`bunun ${tekil * (B - 1)}'i kapsami tek birim olan ${tekil} karar icin harcanir`);
```

```
10 birim, 11 karar, kurumsal esigi = 7 birim

karar                                         birim   duzey
----------------------------------------------------------------
ayar degerleri tek kaynaktan okunur           10      kurumsal
veri erisimi tek katmandan gecer              9       kurumsal
envanter olay yolu uzerinden esitlenir        8       kurumsal
saat kaynagi tek modulden alinir              8       kurumsal
dis kataloga tek baglayici uzerinden erisilir 7       kurumsal
odunc suresi kurali yapilandirmadan okunur    5       cozum
kimlik dogrulama tek modulde toplanir         4       cozum
ceza hesabi uye kaydindan ayri durur          2       cozum
gunluk rapor ayri bir modulde uretilir        2       cozum
eposta bildirimi duz metin govdeyle gider     2       cozum
kiosk ucu ayri bir dagitim birimidir          1       uygulama

kurumsal   karar=5    etkiledigi birim=10   ort. kapsam=8.4
cozum      karar=5    etkiledigi birim=8    ort. kapsam=3.0
uygulama   karar=1    etkiledigi birim=1    ort. kapsam=1.0
esik duyarliligi: esik 6 -> 5 kurumsal, esik 7 -> 5 kurumsal, esik 8 -> 4 kurumsal

duzen       habersiz  yineleme  celisen  danisma
--------------------------------------------------
yerel       47        47        31       0
uc duzey    0         0         0        47
merkezi     0         0         0        99

yerel duzen 47 danismadan kacinir, karsiliginda 31 celisen gerceklestirim alir
basabas: bir celisen gerceklestirim 1.52 danismadan pahaliysa uc duzey kazanir
merkezi duzen uc duzeyden 52 fazla danisma harcar, celisen sayisi ikisinde de 0
bunun 9'i kapsami tek birim olan 1 karar icin harcanir
```

#### Dağılımın Okunması

On bir karar beş kurumsal, beş çözüm ve bir uygulama düzeyi kararına ayrıldı. Kurumsal düzeydeki
beş kararın ortalama kapsamı 8,4 birim, çözüm düzeyindeki beş kararınki 3,0 birim. Birleşim
sütunu da bilgi veriyor: kurumsal düzeydeki beş karar on birimin **tamamına** dokunuyor, çözüm
düzeyindeki beş karar sekiz birime.

Eşiğin kırılganlığı burada da ölçülü. Kurumsal eşiği yediden altıya indirmek hiçbir kararı
değiştirmiyor, çünkü kapsamı altı birim olan karar yok; sekize çıkarmak ise dış katalog
bağlayıcısı kararını kurumsal düzeyden çözüm düzeyine indiriyor. Eşik bir seçimdir, sıralama
değildir; hangi kararın hangi kararın üstünde olduğu ölçümden gelir, sınır bir kuraldan.

Dağılımın söylediği asıl şey şudur: hiçbir karar konusu gereği bir düzeye ait değildir. Saatin
nereden okunacağı, konu olarak bakıldığında bir uygulama ayrıntısıdır; kapsamı sekiz birimdir ve
bu modelde envanter eşitlemesiyle aynı düzeye düşer. Kararın düzeyi kararın konusundan değil,
kaç birimin ona bağımlı olmasından çıkar.

#### Yanlış Düzeyin Bedeli

Alt tablo aynı on bir kararı üç düzende koşturuyor. **Yerel düzende** her karar gövdesinin
bulunduğu birimde verilir ve orada kalır. **Merkezî düzende** her karar bütün birimlere
danışılarak verilir. **Üç düzeyli düzende** her karar ölçülen kapsamının düzeyinde verilir ve
yalnız kapsamdaki birimlere danışılır.

Yerel düzende kapsam içindeki 47 birim kararı hiç duymuyor. Duymayan birim işini yapmak zorunda
olduğu için aynı kararı kendisi veriyor: 47 yinelenen karar. Yinelenen kararların hepsi
çakışmıyor — her karar için makul seçenek sayısı ikiyle dört arasında (**MN6**) ve bağımsız veren
birim bunlardan birini seçiyor. Tohumu 48151 olan üreteçle 47 yinelemenin **31'i** sahibin
seçiminden farklı çıktı, yani 31 çelişen gerçekleştirim.

Yerel düzenin kazancı 47 danışmadan kaçınmasıdır. Buradan başabaş noktası okunur: bir çelişen
gerçekleştirimin uzlaştırılması **1,52 danışmadan** pahalıysa üç düzeyli düzen kazanır. Bu, bir
tercih değil bir hesaptır ve sayı modelin girdilerine bağlıdır; seçenek sayıları büyüdükçe
çelişen gerçekleştirim artar ve başabaş noktası aşağı iner.

Merkezî düzen çelişkiyi de sıfıra indiriyor, ama 99 danışmayla — üç düzeyli düzenden 52 fazla.
Bunun dokuzu tek bir karar için harcanıyor: kiosk ucunun ayrı bir dağıtım birimi olması kararının
kapsamı tek birim, buna rağmen dokuz birime daha danışılıyor. Yanlış düzeyde karar vermenin iki
yönü var ve ikisinin de bir sayısı var: kararı olduğundan alçak düzeyde vermek habersiz birim ve
çelişen gerçekleştirim üretir, olduğundan yüksek düzeyde vermek boşa danışma üretir.

#### Özet

- Bir kararın düzeyi konusundan değil kapsamından okunur; kapsam, kararın erişim alanındaki
  modülleri işleten dağıtım birimlerinin sayısıdır.
- Model ağda on birim ve on bir karar var; kurumsal eşiği birimlerin üçte ikisi (7 birim) olarak
  seçildiğinde beş kurumsal, beş çözüm ve bir uygulama düzeyi kararı çıkıyor.
- Kurumsal düzeydeki beş karar on birimin tamamına dokunuyor (ortalama kapsam 8,4); çözüm
  düzeyindeki beş karar sekiz birime (ortalama kapsam 3,0).
- Yerel düzende 47 birim kararı duymuyor, 47 karar yeniden veriliyor ve tohumu 48151 olan
  üreteçle bunların 31'i sahibin seçiminden farklı çıkıyor; başabaş noktası bir çelişen
  gerçekleştirimin 1,52 danışmaya eşit olduğu yerdir.
- Merkezî düzen çelişkiyi sıfırlar ama 99 danışma harcar; bunun dokuzu kapsamı tek birim olan
  tek bir karar içindir.

#### Sonraki Adım

İki ders de kararı verilmiş bir şey gibi ele aldı: karar vardır, kapsamı ölçülür, düzeyi
belirlenir. Kararın kim tarafından verildiği, verildikten sonra kime ve nasıl duyurulduğu ve
duyurulduktan sonra gerçekten uygulanıp uygulanmadığı hiç sorulmadı. Üç düzeyli düzenin 47
danışmasını yapan biri var; o kişinin işi yalnız karar vermek değil. Sonraki ders mimarın işini
üç sorumluluğa ayırır — karar, iletişim ve gözetim — ve üçünü bir matris olarak kurar. Ölçülecek
olan şudur: karar verilmiş ve duyurulmuş olmasına rağmen kodda karşılığı olmayan kararların oranı
ve bu oranın gözetim eklendiğinde ne kadar değiştiği.

### Mimarın Sorumlulukları

Source: https://academia.sh/tr/kurslar/mimarin-rolu/mimarin-sorumluluklari

Karar, iletişim ve gözetim sorumluluklarının bir matris olarak kurulması: kararın makinece denetlenebilir kısıt biçimine çevrilmesi, kısayol ekleyen bir kod tabanında gözetimli ve gözetimsiz düzenin aynı kenar dizisiyle koşturulması, kodda karşılığı kalmayan karar oranı ve üç sorumluluğun saat dağılımı.

Önceki iki ders kararı verilmiş bir şey gibi ele aldı: karar vardır, kapsamı ölçülür, düzeyi
belirlenir. Üç düzeyli düzenin 47 danışmasını yapan biri var ve o kişinin işi yalnız karar vermek
değil. Bu ders mimarın işini üç sorumluluğa ayırır.

**Karar** bir seçeneğin seçilmesidir. **İletişim** kararın kapsamındaki birimlere, uygulanabilir
bir biçimde ulaşmasıdır. **Gözetim** kararın kodda karşılığının kalmaya devam etmesidir. Üçü
arasında bir sıra yok; eksik olan biri ötekileri değersizleştirir. Ölçülecek şey de budur: karar
verilmiş ve duyurulmuş olmasına rağmen kodda karşılığı olmayan kararların oranı.

#### Kararın Yazılı Biçimi

Bir kararın gözetlenebilmesi için makinenin denetleyebileceği bir biçime çevrilmesi gerekir. Bu
modelde biçim şudur: **hangi modüller hangi modülü doğrudan ithal edemez** (**MN7**). "Veri
erişimi tek katmandan geçer" kararı, uç modüllerin veri erişim modülüne doğrudan kenar
çekememesi demektir; kenar varsa karar ihlal edilmiştir. Bu, Servis Mimarileri kursunda kurulan
sınır ihlali ölçüsüyle aynı biçimdir.

Her karar bu biçime çevrilemez. E-posta gövdesinin düz metin olması, günlük raporun ayrı bir
modülde üretilmesi ve kiosk ucunun ayrı bir dağıtım birimi olması ithal grafiğinde görünmez.
Bunlar başka yollarla denetlenir; ölçümde denetlenebilir kararlardan ayrı tutulur.

Model, önceki dersin ithal grafiğini yeniden kullanır; blok kendi başına çalışsın diye grafik
tekrarlanıyor.

```js
// mimari/model.mjs — MODEL kutuphane agi kod tabani: ithal grafigi ve kararlarin govdesi.
// Gercek bir kurum degildir; kenarlar ve karar govdeleri elle secilmistir.
export const ITHAL = {
  yapilandirma: [], zaman: [], kayit: ["yapilandirma"],
  "veri-erisim": ["yapilandirma", "kayit"], "olay-yolu": ["yapilandirma", "kayit"],
  "kimlik-dogrulama": ["veri-erisim", "yapilandirma", "kayit"], yetki: ["kimlik-dogrulama"],
  "katalog-baglayici": ["yapilandirma", "kayit"],
  "katalog-onbellek": ["katalog-baglayici", "zaman"],
  "odunc-kural": ["yapilandirma", "zaman"],
  "odunc-cekirdek": ["odunc-kural", "veri-erisim", "olay-yolu", "zaman", "katalog-baglayici"],
  ayirtma: ["odunc-cekirdek", "bildirim-kuyruk", "veri-erisim"],
  "uye-kayit": ["veri-erisim", "kayit"],
  "uye-ceza": ["uye-kayit", "odunc-kural", "zaman", "veri-erisim"],
  "sube-envanter": ["veri-erisim", "olay-yolu"],
  "sube-esitleme": ["sube-envanter", "olay-yolu", "katalog-baglayici", "kayit"],
  "bildirim-kuyruk": ["veri-erisim", "olay-yolu"],
  "bildirim-eposta": ["bildirim-kuyruk", "yapilandirma"],
  "rapor-gunluk": ["veri-erisim", "zaman"],
  "rapor-toplu": ["veri-erisim", "sube-envanter", "zaman", "kayit"],
  "web-ucu": ["odunc-cekirdek", "katalog-onbellek", "uye-kayit", "ayirtma", "kimlik-dogrulama"],
  "personel-ucu": ["odunc-cekirdek", "uye-kayit", "uye-ceza", "sube-envanter", "rapor-gunluk",
    "kimlik-dogrulama", "yetki"],
  "kiosk-ucu": ["odunc-cekirdek", "katalog-onbellek", "kimlik-dogrulama"],
  "toplu-is": ["rapor-toplu", "sube-esitleme", "bildirim-kuyruk", "bildirim-eposta"],
};
export const KARAR = [
  { ad: "veri erisimi tek katmandan gecer", govde: ["veri-erisim"] },
  { ad: "ayar degerleri tek kaynaktan okunur", govde: ["yapilandirma"] },
  { ad: "envanter olay yolu uzerinden esitlenir", govde: ["olay-yolu", "sube-esitleme"] },
  { ad: "dis kataloga tek baglayici uzerinden erisilir", govde: ["katalog-baglayici"] },
  { ad: "kimlik dogrulama tek modulde toplanir", govde: ["kimlik-dogrulama"] },
  { ad: "odunc suresi kurali yapilandirmadan okunur", govde: ["odunc-kural"] },
  { ad: "saat kaynagi tek modulden alinir", govde: ["zaman"] },
  { ad: "ceza hesabi uye kaydindan ayri durur", govde: ["uye-ceza"] },
  { ad: "gunluk rapor ayri bir modulde uretilir", govde: ["rapor-gunluk"] },
  { ad: "eposta bildirimi duz metin govdeyle gider", govde: ["bildirim-eposta"] },
  { ad: "kiosk ucu ayri bir dagitim birimidir", govde: ["kiosk-ucu"] },
];
export const MODULLER = Object.keys(ITHAL);
```

#### Ölçüm

İkinci dosya sorumluluk matrisini kurar, kod tabanını on tur boyunca değiştirir ve aynı kenar
dizisini iki düzende koşturur. Değişimin biçimi şudur: bir geliştirici, dolaylı olarak zaten
eriştiği bir modüle doğrudan kenar çeker — **kısayol** (**MN8**). Kısayol yeni bir erişim
yaratmaz, var olan dolaylı erişimi kısaltır; bu yüzden havuzu sonludur ve her ekleme havuzdan bir
kenar eksiltir. Dizi bir kez üretilir ve iki düzene aynen verilir.

```js
// mimari/sorumluluk.mjs — sorumluluk matrisi, gozetimli ve gozetimsiz duzenin karsilastirmasi
import { ITHAL, KARAR, MODULLER } from "./model.mjs";

const UC = ["web-ucu", "personel-ucu", "kiosk-ucu", "toplu-is"];
// KISIT — kararin ithal grafiginde denetlenebilir karsiligi: kaynaklardan hedefe dogrudan kenar yasak
const KISIT = [
  { karar: 0, kaynak: UC, hedef: "veri-erisim" },
  { karar: 1, kaynak: UC, hedef: "yapilandirma" },
  { karar: 2, kaynak: ["web-ucu", "kiosk-ucu", "personel-ucu"], hedef: "sube-envanter" },
  { karar: 3, kaynak: UC, hedef: "katalog-baglayici" },
  { karar: 4, kaynak: ["ayirtma", "uye-kayit", "uye-ceza", "sube-envanter", "rapor-gunluk", "rapor-toplu"], hedef: "kimlik-dogrulama" },
  { karar: 5, kaynak: ["web-ucu", "personel-ucu", "kiosk-ucu"], hedef: "odunc-kural" },
  { karar: 6, kaynak: UC, hedef: "zaman" },
  { karar: 7, kaynak: ["uye-kayit"], hedef: "uye-ceza" },
];
const DENETLENEMEZ = [8, 9, 10]; // gunluk raporun uretim yeri, eposta govde bicimi, kiosk dagitimi

// sorumluluk matrisi: her karar icin uc sorumlulugun durumu
// verildi = karar alinmis; yazili = makinece denetlenebilir bir kisit bicimi var; gozetilir = duzene bagli
const matris = KARAR.map((k, i) => ({
  ad: k.ad, verildi: true, yazili: !DENETLENEMEZ.includes(i),
}));
const sut = (s, n) => String(s).padEnd(n);
const im = (b) => (b ? "evet" : "hayir");
console.log(sut("karar", 46) + sut("verildi", 9) + "yazili kisit");
console.log("-".repeat(67));
for (const m of matris) console.log(sut(m.ad, 46) + sut(im(m.verildi), 9) + im(m.yazili));
console.log(`\nverilen karar = ${matris.length}/${matris.length}; yazili kisit bicimi olan = ${matris.filter((m) => m.yazili).length}/${matris.length}`);
console.log(`yazili bicimi olmayan karar gozetlenemez: ${DENETLENEMEZ.map((i) => KARAR[i].ad).join("; ")}`);

// ---- kod tabani zamanla degisir: gelistirici dolayli erisimi dogrudan kenara cevirir ----
function uretec(tohum) { let s = tohum >>> 0; return () => (s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32; }
const erisir = (g, a, b) => {
  const gor = new Set([a]), yig = [a];
  while (yig.length) for (const h of g[yig.pop()]) if (!gor.has(h)) { gor.add(h); yig.push(h); }
  return gor.has(b);
};
const kisayollar = (g) => {
  const c = [];
  for (const a of MODULLER) for (const b of MODULLER)
    if (a !== b && !g[a].includes(b) && erisir(g, a, b)) c.push([a, b]);
  return c;
};
const ihlalEder = (a, b) => KISIT.filter((c) => c.hedef === b && c.kaynak.includes(a));

const TUR = 10, TURDA = 5, TOHUM = 90210;
const temel = Object.fromEntries(MODULLER.map((m) => [m, [...ITHAL[m]]]));
const havuz = kisayollar(temel);
const rast = uretec(TOHUM);           // tohum gorunur; dizi bir kez uretilir
const kalan = [...havuz], DIZI = [];
for (let i = 0; i < TUR * TURDA; i++) DIZI.push(kalan.splice(Math.floor(rast() * kalan.length), 1)[0]);
console.log(`\nkisayol havuzu = ${havuz.length} kenar; ${DIZI.length} kenar cekildi (tohum ${TOHUM})`);
console.log(`cekilen kenarlarin ${DIZI.filter(([a, b]) => ihlalEder(a, b).length).length}'i bir kisiti ihlal ediyor`);
const baslangic = [];
for (const a of MODULLER) for (const b of ITHAL[a]) for (const c of ihlalEder(a, b)) baslangic.push(`${a} -> ${b}`);
console.log(`kararin verildigi anda zaten ihlal edilmis kisit = ${baslangic.length} (${baslangic.join(", ") || "yok"})`);

function kosu(gozetim) {
  const g = Object.fromEntries(MODULLER.map((m) => [m, [...ITHAL[m]]]));
  let eklenen = 0, geriAlinan = 0, saat = 0;
  for (let t = 0; t < TUR; t++) {
    for (const [a, b] of DIZI.slice(t * TURDA, (t + 1) * TURDA)) { g[a].push(b); eklenen++; }
    if (!gozetim) continue;
    saat += 0.5;                        // tur basina bir denetim kosumu
    for (const a of MODULLER)
      for (const b of [...g[a]]) if (!ITHAL[a].includes(b) && ihlalEder(a, b).length) {
        g[a].splice(g[a].indexOf(b), 1); geriAlinan++; saat += 1; // geri alma bedeli
      }
  }
  const bozuk = new Set();
  for (const a of MODULLER) for (const b of g[a]) for (const c of ihlalEder(a, b)) bozuk.add(c.karar);
  return { eklenen, geriAlinan, saat, bozuk: bozuk.size };
}

const D = KISIT.length;
const A = kosu(false), Bk = kosu(true);
console.log(`\n${TUR} tur, turda ${TURDA} kisayol; denetlenebilir karar = ${D}`);
console.log(sut("duzen", 12) + sut("eklenen", 10) + sut("geri alinan", 13) + sut("bozulan karar", 15) + sut("uygulanma", 11) + "gozetim saati");
console.log("-".repeat(74));
for (const [ad, r] of [["gozetimsiz", A], ["gozetimli", Bk]])
  console.log(sut(ad, 12) + sut(r.eklenen, 10) + sut(r.geriAlinan, 13) +
    sut(`${r.bozuk}/${D}`, 15) + sut(`${(((D - r.bozuk) / D) * 100).toFixed(0)}%`, 11) + r.saat);

console.log(`\ngozetimsiz duzende kodda karsiligi kalmayan karar = ${A.bozuk}/${D}; gozetimli duzende ${Bk.bozuk}/${D}`);
console.log(`gozetimin kurtardigi karar = ${A.bozuk - Bk.bozuk}; bedeli ${Bk.saat} saat, karar basina ${(Bk.saat / (A.bozuk - Bk.bozuk)).toFixed(1)} saat`);

// ---- ucun zaman dagilimi ----
const SAAT = { "karar verme": KARAR.length * 3, iletisim: 47 * 0.5, gozetim: Bk.saat };
const toplam = Object.values(SAAT).reduce((a, b) => a + b, 0);
console.log(`\n${sut("sorumluluk", 14)}saat   pay`);
console.log("-".repeat(28));
for (const [k, v] of Object.entries(SAAT)) console.log(sut(k, 14) + sut(v.toFixed(1), 7) + `${((v / toplam) * 100).toFixed(0)}%`);
console.log(sut("toplam", 14) + toplam.toFixed(1));
```

```
karar                                         verildi  yazili kisit
-------------------------------------------------------------------
veri erisimi tek katmandan gecer              evet     evet
ayar degerleri tek kaynaktan okunur           evet     evet
envanter olay yolu uzerinden esitlenir        evet     evet
dis kataloga tek baglayici uzerinden erisilir evet     evet
kimlik dogrulama tek modulde toplanir         evet     evet
odunc suresi kurali yapilandirmadan okunur    evet     evet
saat kaynagi tek modulden alinir              evet     evet
ceza hesabi uye kaydindan ayri durur          evet     evet
gunluk rapor ayri bir modulde uretilir        evet     hayir
eposta bildirimi duz metin govdeyle gider     evet     hayir
kiosk ucu ayri bir dagitim birimidir          evet     hayir

verilen karar = 11/11; yazili kisit bicimi olan = 8/11
yazili bicimi olmayan karar gozetlenemez: gunluk rapor ayri bir modulde uretilir; eposta bildirimi duz metin govdeyle gider; kiosk ucu ayri bir dagitim birimidir

kisayol havuzu = 58 kenar; 50 kenar cekildi (tohum 90210)
cekilen kenarlarin 19'i bir kisiti ihlal ediyor
kararin verildigi anda zaten ihlal edilmis kisit = 1 (personel-ucu -> sube-envanter)

10 tur, turda 5 kisayol; denetlenebilir karar = 8
duzen       eklenen   geri alinan  bozulan karar  uygulanma  gozetim saati
--------------------------------------------------------------------------
gozetimsiz  50        0            6/8            25%        0
gozetimli   50        19           1/8            88%        24

gozetimsiz duzende kodda karsiligi kalmayan karar = 6/8; gozetimli duzende 1/8
gozetimin kurtardigi karar = 5; bedeli 24 saat, karar basina 4.8 saat

sorumluluk    saat   pay
----------------------------
karar verme   33.0   41%
iletisim      23.5   29%
gozetim       24.0   30%
toplam        80.5
```

#### Gözetimsiz Kararın Uygulanma Oranı

On bir kararın hepsi verilmiş, sekizinin yazılı ve denetlenebilir bir kısıt biçimi var. On tur
boyunca 50 kısayol eklendi; bunların 19'u bir kısıtı ihlal ediyor. Gözetimsiz düzende bu 19 kenar
kalıcı oldu ve sekiz karardan **altısı** kodda karşılığını yitirdi — uygulanma oranı **%25**.
Gözetimli düzende her turun sonunda ihlal eden kenarlar geri alındı ve sonda yalnız bir karar
bozuk kaldı; uygulanma oranı **%88**.

Kalan o bir karar ölçümün en öğretici parçası. Personel uygulaması şube envanterine daha kararın
verildiği gün doğrudan bakıyordu; gözetim yalnız karardan sonra eklenen kenarları geri alıyor.
Verildiği anda ihlal edilmiş bir karar gözetimle düzelmez, ayrı bir taşıma işi ister. Bu ayrım
yazılmadığında gözetim raporu "bir karar hâlâ bozuk" der ve nedeni görünmez.

Farkın bedeli de sayılı: gözetim beş kararı kurtardı ve 24 saate mal oldu — karar başına
**4,8 saat**. Bu sayı bir savunmadır. "Mimar kararları izlemelidir" cümlesi bir karar değildir;
"gözetimsiz düzende sekiz karardan altısı on turda kodda karşılığını yitiriyor, gözetim bunun
beşini karar başına 4,8 saate kurtarıyor" cümlesi denetlenebilir.

Üç denetlenemeyen kararın durumu ayrıca not edilmeli. Ölçüm onları hiç saymadı, çünkü ithal
grafiğinde iz bırakmıyorlar. Yazılı biçimi olmayan bir karar gözetlenemez; gözetlenemeyen bir
kararın uygulanma oranı ölçülemez. Sorumluluk matrisinin "yazılı kısıt" sütunu bu yüzden karar
sütunundan daha bilgilendiricidir: 11 kararın 11'i verilmiş, 8'i denetlenebilir.

#### Zaman Dağılımı

Son tablo üç sorumluluğun saatlerini toplar. Karar verme, karar başına üç saatle 33 saat;
iletişim, önceki dersin üç düzeyli düzeninde sayılan 47 danışmanın yarım saatiyle 23,5 saat;
gözetim, ölçülen 24 saat (**MN9**). Toplam 80,5 saatin **%41'i** karar verme, **%29'u** iletişim,
**%30'u** gözetim.

Dağılımın söylediği şudur: karar verme, mimarın işinin yarısından azıdır. İletişim ve gözetim
birlikte %59 tutuyor ve ikisi de kesildiğinde görünen bir şey olmuyor — kesilen iletişim önceki
dersin 31 çelişen gerçekleştirimini, kesilen gözetim bu dersin altı bozuk kararını üretiyor.
İkisinin de bedeli kararın verildiği anda değil, aylar sonra ödeniyor.

#### Özet

- Mimarın işi üç sorumluluktur: karar, iletişim ve gözetim; ölçülebilir olması için kararın
  makinece denetlenebilir bir kısıt biçimine çevrilmesi gerekir.
- Model kod tabanında 11 kararın 11'i verilmiş, ama yalnız 8'inin ithal grafiğinde denetlenebilir
  bir karşılığı var; kalan üçü gözetlenemez ve uygulanma oranları ölçülemez.
- On tur boyunca 50 kısayol eklendi, 19'u bir kısıtı ihlal etti; gözetimsiz düzende sekiz kararın
  altısı kodda karşılığını yitirdi (uygulanma %25), gözetimli düzende bir karar bozuk kaldı (%88).
- Kalan bozuk karar, karardan önce var olan bir kenardan geliyor; gözetim yalnız karardan sonrasını
  korur, önceden var olan ihlal ayrı bir taşıma işidir.
- Gözetim beş kararı karar başına 4,8 saate kurtardı; üç sorumluluğun 80,5 saatlik toplamında
  karar verme %41, iletişim %29, gözetim %30 pay tuttu.

#### Sonraki Adım

Bu dersin gözetim düzeni bir şeyi sessizce varsaydı: kararı veren kişinin ithal grafiğini
gerçekten görebildiğini. Kısıtları yazan, ihlalleri sayan ve geri alan aynı kişi, kodun o an ne
durumda olduğunu biliyor. Bu varsayım her düzende doğru değil. Karar veren kişi koda hiç
dokunmuyorsa, kararını verdiği andaki grafik ile aylar sonraki grafik arasında bir fark birikir ve
karar bu farkın üstüne kurulur. Sonraki ders o farkı modeller: karar verenle uygulayanın bildiği
modül kümeleri ayrı ayrı tutulur, koda dokunan ve dokunmayan iki düzen aynı değişim dizisinde
koşturulur ve iki sayı karşılaştırılır — kararın uygulanabilirlik oranı ve bir ihlalin fark
edilmesine kadar geçen tur sayısı.

### Mimar ve Geliştirici İlişkisi

Source: https://academia.sh/tr/kurslar/mimarin-rolu/mimar-ve-gelistirici-iliskisi

Fildişi kule sorununun bir bilgi farkı olarak modellenmesi: karar verenin bildiği ithal grafiği ile gerçek grafiğin ayrı tutulması, koda dokunan ve dokunmayan iki düzenin aynı değişim dizisinde koşturulması, ölü doğan karar oranı, ortalama bilgi farkı ve geri bildirim gecikmesinin sayılması.

Önceki dersin gözetim düzeni bir şeyi sessizce varsaydı: kısıtları yazan, ihlalleri sayan ve geri
alan kişinin ithal grafiğini gerçekten görebildiğini. Bu varsayım her düzende doğru değil. Karar
veren kişi koda hiç dokunmuyorsa, kararını verdiği andaki grafik ile aylar sonraki grafik arasında
bir fark birikir.

**Fildişi kule** bu farkın adıdır. Genellikle bir kişilik kusuru gibi anlatılır — uzaktan
konuşan, uygulamadan kopuk bir tutum. Bu derste kusur değil, ölçülebilir bir büyüklük olarak
alınıyor: karar verenin bildiği grafik ile gerçek grafik arasındaki kenar farkı. Fark büyüdükçe
kararların ne kadarının daha yayımlandığı anda uygulanamaz olduğu sayılabilir.

#### Ölü Doğan Karar

Bir karar, gerçekleşmiş bir durumu yasakladığında ölü doğar. Kütüphane ağı modelinde bu somut bir
biçim alır: mimar "personel ucu şube envanterine doğrudan bakmasın" der; oysa o kenar üç ay önce
eklenmiştir ve mimar bunu bilmemektedir. Karar duyurulur, ekip kararın zaten ihlal edildiğini
söyler, karar geri çekilir. Kararın yanlış olması gerekmez — geç olması yeter.

Model bunu şöyle kurar. İki grafik tutulur: **gerçek** grafik ve mimarın **bildiği** grafik.
Geliştiriciler her tur kısayol ekler; bir kısayol, dolaylı olarak zaten erişilen bir modüle
doğrudan kenar çekmektir. Mimar her tur bir karar verir ve kararını yalnız bildiği grafiğe bakarak
seçer. Karar, seçtiği kenar gerçek grafikte zaten varsa ölü sayılır (**MN10**).

İki düzen karşılaştırılır. **Koda dokunan mimar** her tur kod üzerinde çalışır ve eklenen
kenarların %95'ini görür. **Koda dokunmayan mimar** altı turda bir rapor alır ve raporda
kenarların %70'i görünür; kalanı hiç görünmez (**MN11**). İki düzen aynı kısayol dizisini alır;
dizi bir kez üretilir ve tohumu yazılıdır.

#### Ölçüm

```js
// mimari/bilgi-farki.mjs — karar verenin bildigi grafik ile gercek grafik arasindaki fark
// ITHAL, onceki derslerin MODEL kutuphane agi grafigidir; blok kendi basina calissin diye tekrar veriliyor.
const ITHAL = {
  yapilandirma: [], zaman: [], kayit: ["yapilandirma"],
  "veri-erisim": ["yapilandirma", "kayit"], "olay-yolu": ["yapilandirma", "kayit"],
  "kimlik-dogrulama": ["veri-erisim", "yapilandirma", "kayit"], yetki: ["kimlik-dogrulama"],
  "katalog-baglayici": ["yapilandirma", "kayit"],
  "katalog-onbellek": ["katalog-baglayici", "zaman"],
  "odunc-kural": ["yapilandirma", "zaman"],
  "odunc-cekirdek": ["odunc-kural", "veri-erisim", "olay-yolu", "zaman", "katalog-baglayici"],
  ayirtma: ["odunc-cekirdek", "bildirim-kuyruk", "veri-erisim"],
  "uye-kayit": ["veri-erisim", "kayit"],
  "uye-ceza": ["uye-kayit", "odunc-kural", "zaman", "veri-erisim"],
  "sube-envanter": ["veri-erisim", "olay-yolu"],
  "sube-esitleme": ["sube-envanter", "olay-yolu", "katalog-baglayici", "kayit"],
  "bildirim-kuyruk": ["veri-erisim", "olay-yolu"],
  "bildirim-eposta": ["bildirim-kuyruk", "yapilandirma"],
  "rapor-gunluk": ["veri-erisim", "zaman"],
  "rapor-toplu": ["veri-erisim", "sube-envanter", "zaman", "kayit"],
  "web-ucu": ["odunc-cekirdek", "katalog-onbellek", "uye-kayit", "ayirtma", "kimlik-dogrulama"],
  "personel-ucu": ["odunc-cekirdek", "uye-kayit", "uye-ceza", "sube-envanter", "rapor-gunluk",
    "kimlik-dogrulama", "yetki"],
  "kiosk-ucu": ["odunc-cekirdek", "katalog-onbellek", "kimlik-dogrulama"],
  "toplu-is": ["rapor-toplu", "sube-esitleme", "bildirim-kuyruk", "bildirim-eposta"],
};
const MODULLER = Object.keys(ITHAL);

function uretec(tohum) { let s = tohum >>> 0; return () => (s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32; }
const kopya = (g) => Object.fromEntries(MODULLER.map((m) => [m, [...g[m]]]));
const erisir = (g, a, b) => {
  const gor = new Set([a]), yig = [a];
  while (yig.length) for (const h of g[yig.pop()]) if (!gor.has(h)) { gor.add(h); yig.push(h); }
  return gor.has(b);
};
const kisayollar = (g) => {
  const c = [];
  for (const a of MODULLER) for (const b of MODULLER)
    if (a !== b && !g[a].includes(b) && erisir(g, a, b)) c.push([a, b]);
  return c;
};
const kenarSayisi = (g) => MODULLER.reduce((t, m) => t + g[m].length, 0);

const TUR = 18, TURDA = 3, TOHUM = 31337;
const temel = kopya(ITHAL);
const havuz = kisayollar(temel);
const cek = uretec(TOHUM);
const kalan = [...havuz], DIZI = [];
for (let i = 0; i < TUR * TURDA; i++) DIZI.push(kalan.splice(Math.floor(cek() * kalan.length), 1)[0]);
console.log(`temel grafik ${kenarSayisi(temel)} kenar; ${TUR} tur boyunca ${DIZI.length} kisayol eklenir (tohum ${TOHUM})`);

// duzen: gorusKapsami = bir yenilemede gercek kenarlarin gorunen orani, yenileme = kac turda bir
function kosu(gorusKapsami, yenileme) {
  const gercek = kopya(temel), bilinen = kopya(temel);
  const rast = uretec(TOHUM + 1);          // karar cekilisi ve gorunurluk atisi, ayni tohumdan
  const eklemeTuru = new Map();
  let olu = 0, farkToplam = 0;
  const gecikme = [];
  for (let t = 0; t < TUR; t++) {
    const c = kisayollar(bilinen);         // mimar yalnizca bildigi grafige bakar
    const [a, b] = c[Math.floor(rast() * c.length)];
    if (gercek[a].includes(b)) olu++;      // yasaklanan kenar gercekte zaten var: karar olu dogar
    for (const [x, y] of DIZI.slice(t * TURDA, (t + 1) * TURDA)) {
      gercek[x].push(y); eklemeTuru.set(`${x}>${y}`, t);
    }
    farkToplam += kenarSayisi(gercek) - kenarSayisi(bilinen);
    if ((t + 1) % yenileme !== 0) continue;
    for (const x of MODULLER) for (const y of gercek[x])
      if (!bilinen[x].includes(y) && rast() < gorusKapsami) {
        bilinen[x].push(y); gecikme.push(t - eklemeTuru.get(`${x}>${y}`));
      }
  }
  const gorunmeyen = kenarSayisi(gercek) - kenarSayisi(bilinen);
  return { olu, ortFark: farkToplam / TUR, gorunmeyen,
    ortGecikme: gecikme.length ? gecikme.reduce((a, b) => a + b, 0) / gecikme.length : 0 };
}

const sut = (s, n) => String(s).padEnd(n);
const D = kosu(0.95, 1);  // koda dokunan mimar: her tur, kenarlarin %95'i
const K = kosu(0.7, 6);   // koda dokunmayan mimar: alti turda bir, kenarlarin %70'i
console.log(`\n${sut("duzen", 26) + sut("olu karar", 12) + sut("ort. bilgi farki", 18) + sut("gorunmeyen kenar", 18)}ort. gecikme (tur)`);
console.log("-".repeat(92));
for (const [ad, r] of [["koda dokunan mimar", D], ["koda dokunmayan mimar", K]])
  console.log(sut(ad, 26) + sut(`${r.olu}/${TUR}`, 12) + sut(r.ortFark.toFixed(1), 18) +
    sut(r.gorunmeyen, 18) + r.ortGecikme.toFixed(2));

console.log(`\nuygulanabilirlik orani: dokunan ${(((TUR - D.olu) / TUR) * 100).toFixed(0)}%, dokunmayan ${(((TUR - K.olu) / TUR) * 100).toFixed(0)}%`);
console.log(`olu karar farki = ${K.olu - D.olu} karar; bilgi farki ${(K.ortFark / Math.max(D.ortFark, 0.1)).toFixed(1)} kat`);
console.log(`gecikme farki = ${(K.ortGecikme - D.ortGecikme).toFixed(2)} tur; dokunmayan mimarin hic gormedigi kenar = ${K.gorunmeyen}`);
```

```
temel grafik 64 kenar; 18 tur boyunca 54 kisayol eklenir (tohum 31337)

duzen                     olu karar   ort. bilgi farki  gorunmeyen kenar  ort. gecikme (tur)
--------------------------------------------------------------------------------------------
koda dokunan mimar        0/18        3.1               1                 0.02
koda dokunmayan mimar     8/18        13.8              9                 3.40

uygulanabilirlik orani: dokunan 100%, dokunmayan 56%
olu karar farki = 8 karar; bilgi farki 4.5 kat
gecikme farki = 3.38 tur; dokunmayan mimarin hic gormedigi kenar = 9
```

#### Üç Sayının Okunması

**Uygulanabilirlik oranı.** Koda dokunmayan mimarın on sekiz kararından sekizi yayımlandığı anda
gerçekleşmiş bir durumu yasaklıyor: oran **%56**. Koda dokunan mimarda bu koşumda hiç ölü karar
çıkmadı, oran %100. İkinci sayının tam yüz olması modelin garantisi değildir — o mimarın da bir
kenarlık kör noktası vardı ve on sekiz çekilişin hiçbiri o kenara denk gelmedi; başka bir tohumla
bir iki ölü karar çıkabilir. Fark yönü ise tohumdan bağımsızdır: raporla beslenen bilgi, kodla
beslenen bilgiden geç ve eksik gelir.

**Bilgi farkı.** Gerçek grafikle bilinen grafik arasındaki ortalama kenar farkı dokunan mimarda
3,1, dokunmayan mimarda 13,8 — **4,5 kat**. Dokunan mimardaki 3,1 sıfır değil, çünkü bir turun
içinde eklenen kenarlar o turun kararından sonra gelir; bu, hiçbir düzende sıfırlanamayan bir
gecikmedir. Dokunmayan mimardaki 13,8 ise birikir: raporlar arasında eklenen kenarlar üst üste
yığılır.

**Görünmeyen kenar.** Sayının en sert olanı budur. Dokunmayan mimarın on sekiz tur sonunda hiç
görmediği kenar sayısı **9**. Bunlar gecikmiş bilgi değil, hiç gelmeyen bilgidir; rapor bir
özettir ve özetin dışında kalan her kenar kalıcı olarak görünmez. Bir sonraki kararın dayanağı
64 + 54 = 118 kenarlık bir grafik değil, dokuz kenarı eksik bir grafiktir.

**Geri bildirim gecikmesi.** Bir kenarın eklenmesiyle karar verene ulaşması arasında geçen
ortalama tur sayısı dokunan mimarda 0,02, dokunmayan mimarda **3,40**. Altı turluk rapor
aralığının ortalama gecikmesi budur. Gecikme yalnız bir bekleme değil: bu üç buçuk tur boyunca
verilen her karar eski bir grafiğe dayanır ve ölü karar oranını besleyen şey de odur.

#### Farkın Kapatılması

Ölçünün pratik sonucu, mimarın koda dokunmasının bir tercih değil bir **bilgi tazeleme yolu**
olmasıdır. Fark iki değişkene bağlı: tazeleme sıklığı ve tazelemenin kapsamı. Altı turda bir
rapor almak sıklığı düşürür; raporun kenarların %70'ini taşıması kapsamı düşürür. İkisinden
yalnız birini düzeltmek yetmez — sıklık artırılıp kapsam düşük kalırsa görünmeyen kenar birikmeye
devam eder.

Buradan iki uygulanabilir yol çıkar ve ikisi de ölçülebilir. Birincisi kapsamı yükseltmektir:
kararın dayandığı grafiği rapordan değil doğrudan koddan üretmek — önceki dersin kısıt denetimi
tam olarak bunu yapıyordu ve orada ölçülen 24 saatlik gözetim yükü, aynı zamanda bilgi farkını
kapatan yüktür. İkincisi sıklığı artırmaktır: mimarın kararı vermeden önce kararın dokunduğu
modülleri okuması, yani kararı grafiğin o parçasına bakarak vermesi.

Fildişi kulenin sorunu, kararların kötü olması değildir. Koda dokunmayan mimarın on kararı
uygulanabilirdi; sekizi geç kaldığı için değersizleşti. Aynı kişi aynı ölçütlerle karar veriyor;
değişen tek şey karar anında elindeki grafiğin yaşı.

#### Özet

- Fildişi kule bir tutum değil, karar verenin bildiği grafik ile gerçek grafik arasındaki
  ölçülebilir bilgi farkıdır.
- Aynı 54 kısayoldan oluşan değişim dizisinde koda dokunmayan mimarın on sekiz kararından sekizi
  ölü doğdu (uygulanabilirlik %56); koda dokunan mimarda bu koşumda ölü karar çıkmadı.
- Ortalama bilgi farkı 3,1 kenara karşı 13,8 kenar, yani 4,5 kat; dokunan mimardaki 3,1 hiçbir
  düzende sıfırlanamayan tur içi gecikmedir.
- Dokunmayan mimarın on sekiz tur sonunda hiç görmediği kenar sayısı 9; özet rapor bir gecikme
  değil kalıcı bir kör nokta üretir.
- Geri bildirim gecikmesi 0,02 tura karşı 3,40 tur; kararın niteliği değil, karar anındaki
  grafiğin yaşı değişiyor.

#### Sonraki Adım

Bu ders kararın **doğduğu** koşulları ölçtü: karar verenin gördüğü grafik ne kadar tazeyse karar o
kadar uygulanabilir. Kararın uygulanabilir olması ise uygulanacağı anlamına gelmiyor. Bir önceki
dersin gözetim ölçümü, kararların kodda karşılığını yitirdiğini gösterdi; o ölçüm kararın ekibe
nasıl ulaştığını hiç ayırt etmedi. Oysa aynı karar bir kural olarak duyurulabilir, gerekçesiyle
yazılabilir ya da uygulanırken birlikte çalışılarak aktarılabilir. Sonraki ders aynı kararı üç
aktarım biçiminde koşturur ve ikisini sayar: doğru uygulanma oranı ve aktarımın maliyeti — kaç
saat, kaç kişi.

### Danışmanlık ve Koçluk

Source: https://academia.sh/tr/kurslar/mimarin-rolu/danismanlik-ve-kocluk

Aynı kararın buyruk, yazılı gerekçe ve birlikte çalışma biçimlerinde aktarılması: kalıp durum ile kenar durumun ayrılması, iki dalgalı bir modelde doğru uygulanma oranının ve aktarım maliyetinin ölçülmesi, ekip değişiminden sonra hangi aktarım biçiminin ayakta kaldığının sayılması.

Önceki ders kararın doğduğu koşulları ölçtü: karar verenin gördüğü grafik ne kadar tazeyse karar o
kadar uygulanabilir. Kararın uygulanabilir olması ise uygulanacağı anlamına gelmiyor. Üçüncü
dersin gözetim ölçümü kararların kodda karşılığını yitirdiğini gösterdi ama kararın ekibe nasıl
ulaştığını hiç ayırt etmedi.

Aynı karar üç ayrı biçimde aktarılabilir. **Buyruk**: kural duyurulur, gerekçe verilmez.
**Yazılı gerekçe**: kural, eşiği ve ödünleşimiyle birlikte yazılır — Sistem Tasarımına Giriş
kursunda kurulan karar kaydının biçimi budur. **Birlikte çalışma**: kararın ilk uygulaması birkaç
geliştiriciyle beraber yapılır; **danışman mimar** ve **koçluk** sözcükleri bu biçimi anlatır. Bu
ders üçünü aynı karar ve aynı durum kümesi üzerinde koşturur.

#### Kalıp Durum ve Kenar Durum

Aktarım biçimleri arasındaki fark, kararın uygulandığı durumların hepsinde görünmez. Bir kararın
geçtiği durumlar ikiye ayrılır. **Kalıp durum**, kuralın sözüne birebir uyan durumdur: "uç
modüller veri erişim modülünü doğrudan ithal etmez" kuralı, bir uç modülde veri erişimine kenar
çekilirken doğrudan uygulanır. Bunun için gerekçeyi bilmek gerekmez, kuralı bilmek yeter.

**Kenar durum**, kuralın sözünün yetmediği durumdur: toplu iş modülü bir uç mudur, günlük rapor
sorgusunun geçmesi gereken katman hangisidir, dış katalog için yazılan yeni bir okuma yolu bu
kuralın kapsamına girer mi. Bu sorular ancak kararın **niçin** verildiği bilinerek yanıtlanır.
Modelde durumların %35'i kenar durumdur (**MN12**) ve üç aktarım biçimi yalnız bu durumlarda
ayrışır.

İkinci ayrım zamandır. Bir karar verildiği hafta uygulanıp bitmez; aylar sonra da uygulanmaya
devam eder ve o sırada ekip değişmiştir. Model bunu iki dalgayla kurar: ilk dalgada on iki
geliştirici, ikinci dalgadan önce dördü ayrılır ve yerlerine kararın aktarımını hiç almamış dört
kişi gelir (**MN13**).

#### Ölçüm

Üç biçimin her biri geliştiriciye bir anlama düzeyi ve bir maliyet verir. Buyruk herkese ulaşır ve
ucuzdur; yazılı gerekçe de herkese ulaşır ama okunması gerekir; birlikte çalışma yalnız üç kişiye
doğrudan dokunur ve pahalıdır. Bütün olasılık ve saat değerleri modelin seçilmiş girdileridir
(**MN14**); ölçülen şey bu girdiler altındaki farktır. Aynı durum kümesi ve aynı atış dizisi üç
biçime de verilir, böylece karşılaştırma eşleştirilmiş olur.

```js
// mimari/aktarim.mjs — ayni kararin uc aktarim biciminde dogru uygulanma orani ve maliyeti
// MODEL kutuphane agi; gercek kisi ve ekip yoktur. Iki dalga: ikincisinden once 4 kisi ayrilir.
function uretec(tohum) { let s = tohum >>> 0; return () => (s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32; }

const KISI = 12, D1 = 8, D2 = 6, KENAR_ORANI = 0.35, AYRILAN = 4;
const SAAT = { buyruk: 2.2, "yazili gerekce": 10.0, "birlikte calisma": 24.0 };
const DOGRUDAN = { buyruk: KISI, "yazili gerekce": KISI, "birlikte calisma": 3 };
const BICIMLER = Object.keys(SAAT);

function kosum(tohum) {
  const rast = uretec(tohum);
  const durum = (kisiler, adet) => kisiler.flatMap((k) =>
    Array.from({ length: adet }, () => ({ kisi: k, kenar: rast() < KENAR_ORANI, atis: rast() })));

  const eski = [...Array(KISI).keys()];
  const D = { bir: durum(eski, D1) };
  const okur = Array.from({ length: KISI + AYRILAN }, () => rast() < 0.7); // gerekceyi okuyanlar
  const eslik = new Set();
  while (eslik.size < 3) eslik.add(Math.floor(rast() * KISI));              // birlikte calisilanlar
  const ayrilan = new Set();
  while (ayrilan.size < AYRILAN) ayrilan.add(Math.floor(rast() * KISI));
  const yeni = Array.from({ length: AYRILAN }, (_, i) => KISI + i);
  const ikinciEkip = [...eski.filter((k) => !ayrilan.has(k)), ...yeni];
  D.iki = durum(ikinciEkip, D2);
  const eslikKalan = [...eslik].filter((k) => !ayrilan.has(k)).length;

  // olasilik: kalip durumda kuralin bilinmesi yeter, kenar durumda gerekcenin anlasilmasi gerekir
  const P = {
    buyruk: (k, kenar) => (k >= KISI ? (kenar ? 0.10 : 0.30) : kenar ? 0.15 : 0.95),
    "yazili gerekce": (k, kenar) => (kenar ? (okur[k] ? 0.60 : 0.15) : 0.95),
    "birlikte calisma": (k, kenar) => (k >= KISI
      ? (eslikKalan ? (kenar ? 0.50 : 0.95) : kenar ? 0.15 : 0.60)
      : kenar ? (eslik.has(k) ? 0.95 : 0.50) : 0.95),
  };
  const say = (bicim, liste) => liste.filter((d) => d.atis < P[bicim](d.kisi, d.kenar)).length;
  return { eslikKalan, kenar1: D.bir.filter((d) => d.kenar).length, kenar2: D.iki.filter((d) => d.kenar).length,
    n1: D.bir.length, n2: D.iki.length,
    bicim: Object.fromEntries(BICIMLER.map((b) => [b, { d1: say(b, D.bir), d2: say(b, D.iki) }])) };
}

const TOHUM = 5150;
const r = kosum(TOHUM);
const sut = (s, n) => String(s).padEnd(n);
console.log(`${KISI} gelistirici; birinci dalga ${r.n1} durum (${r.kenar1} kenar), ikinci dalga ${r.n2} durum (${r.kenar2} kenar)`);
console.log(`tohum ${TOHUM}; ikinci dalgadan once ${AYRILAN} kisi ayrildi, birlikte calisilan ${r.eslikKalan}/3 kisi kaldi\n`);
console.log(sut("aktarim bicimi", 19) + sut("dalga 1", 11) + sut("dalga 2", 11) + sut("toplam", 15) + sut("saat", 8) + "dogrudan kisi");
console.log("-".repeat(81));
for (const b of BICIMLER) {
  const v = r.bicim[b], t = v.d1 + v.d2;
  console.log(sut(b, 19) + sut(`${v.d1}/${r.n1}`, 11) + sut(`${v.d2}/${r.n2}`, 11) +
    sut(`${t}/${r.n1 + r.n2} (${((t / (r.n1 + r.n2)) * 100).toFixed(0)}%)`, 15) + sut(SAAT[b].toFixed(1), 8) + DOGRUDAN[b]);
}

console.log("\nbir onceki bicime gore artis (bu tohumda):");
for (let i = 1; i < BICIMLER.length; i++) {
  const a = r.bicim[BICIMLER[i - 1]], b = r.bicim[BICIMLER[i]];
  const dt = (b.d1 + b.d2) - (a.d1 + a.d2), ds = SAAT[BICIMLER[i]] - SAAT[BICIMLER[i - 1]];
  console.log(`  ${sut(BICIMLER[i], 19)}+${sut(dt, 4)}dogru  +${sut(ds.toFixed(1), 6)}saat  saat basina ${(dt / ds).toFixed(2)} dogru`);
}

// tek tohum gurultulu olabilir: 200 tohumda ortalama
const N = 200;
const top = Object.fromEntries(BICIMLER.map((b) => [b, { d1: 0, d2: 0 }]));
for (let t = 0; t < N; t++) {
  const k = kosum(1000 + t * 7);
  for (const b of BICIMLER) { top[b].d1 += k.bicim[b].d1; top[b].d2 += k.bicim[b].d2; }
}
console.log(`\n${N} tohumda ortalama dogru uygulama:`);
console.log(sut("aktarim bicimi", 19) + sut("dalga 1", 10) + sut("dalga 2", 10) + sut("toplam", 10) + "saat basina");
console.log("-".repeat(62));
for (const b of BICIMLER) {
  const d1 = top[b].d1 / N, d2 = top[b].d2 / N;
  console.log(sut(b, 19) + sut(d1.toFixed(1), 10) + sut(d2.toFixed(1), 10) + sut((d1 + d2).toFixed(1), 10) + ((d1 + d2) / SAAT[b]).toFixed(2));
}
const ort = (b) => (top[b].d1 + top[b].d2) / N;
console.log(`\ndalga 2 farki: yazili gerekce ${(top["yazili gerekce"].d2 / N).toFixed(1)}, birlikte calisma ${(top["birlikte calisma"].d2 / N).toFixed(1)}, buyruk ${(top.buyruk.d2 / N).toFixed(1)}`);
console.log(`yazili gerekce - buyruk = ${(ort("yazili gerekce") - ort("buyruk")).toFixed(1)} dogru, +7.8 saat -> saat basina ${((ort("yazili gerekce") - ort("buyruk")) / 7.8).toFixed(2)}`);
console.log(`birlikte calisma - yazili gerekce = ${(ort("birlikte calisma") - ort("yazili gerekce")).toFixed(1)} dogru, +14.0 saat -> saat basina ${((ort("birlikte calisma") - ort("yazili gerekce")) / 14).toFixed(2)}`);
```

```
12 gelistirici; birinci dalga 96 durum (27 kenar), ikinci dalga 72 durum (26 kenar)
tohum 5150; ikinci dalgadan once 4 kisi ayrildi, birlikte calisilan 2/3 kisi kaldi

aktarim bicimi     dalga 1    dalga 2    toplam         saat    dogrudan kisi
---------------------------------------------------------------------------------
buyruk             71/96      43/72      114/168 (68%)  2.2     12
yazili gerekce     83/96      59/72      142/168 (85%)  10.0    12
birlikte calisma   84/96      62/72      146/168 (87%)  24.0    3

bir onceki bicime gore artis (bu tohumda):
  yazili gerekce     +28  dogru  +7.8   saat  saat basina 3.59 dogru
  birlikte calisma   +4   dogru  +14.0  saat  saat basina 0.29 dogru

200 tohumda ortalama dogru uygulama:
aktarim bicimi     dalga 1   dalga 2   toplam    saat basina
--------------------------------------------------------------
buyruk             64.7      37.7      102.4     46.56
yazili gerekce     75.1      56.3      131.4     13.14
birlikte calisma   80.1      58.9      139.1     5.79

dalga 2 farki: yazili gerekce 56.3, birlikte calisma 58.9, buyruk 37.7
yazili gerekce - buyruk = 29.0 dogru, +7.8 saat -> saat basina 3.71
birlikte calisma - yazili gerekce = 7.7 dogru, +14.0 saat -> saat basina 0.55
```

#### Üç Biçimin Farkı

Tek tohumlu tabloda üç biçim sırasıyla %68, %85 ve %87 doğru uygulama veriyor. İki yüz tohumda
ortalama toplamlar 102,4, 131,4 ve 139,1. Sıra beklendiği gibi; asıl bilgi **artışların
biçimi**nde.

Buyruktan yazılı gerekçeye geçmek ortalama **29 doğru uygulama** kazandırıyor ve 7,8 saate mal
oluyor: saat başına 3,71. Yazılı gerekçeden birlikte çalışmaya geçmek **7,7 doğru uygulama**
kazandırıyor ve 14 saate mal oluyor: saat başına 0,55. İki artış arasındaki oran yaklaşık yedi
kat. Bu, koçluğun değersiz olduğunu söylemiyor; söylediği şey, gerekçenin yazılmamış olduğu bir
yerde koçlukla başlamanın en pahalı yol olduğudur.

Sağdaki "saat başına" sütunu ise ters yönde okunmalı. Buyruk saat başına 46,56 doğru uygulama
üretiyor, birlikte çalışma 5,79. Ortalama verim en ucuz biçimde en yüksektir ve bu her zaman
böyledir; ucuz olanın verimi yüksek, sonucu düşüktür. Bir aktarım biçimini ortalama verime bakarak
seçmek, buyruğu seçmek demektir. Karar, **artışa** bakılarak verilir: bir sonraki saat kaç doğru
uygulama getiriyor.

#### Ekip Değiştiğinde Ne Kalıyor

İkinci dalga sütunu bu dersin asıl bulgusudur. İlk dalgada buyruk ile yazılı gerekçe arasındaki
ortalama fark 10,4 doğru uygulama (64,7'ye karşı 75,1). İkinci dalgada, yani dört kişi ayrılıp
yerlerine yeni kişiler geldikten sonra fark **18,6**'ya çıkıyor (37,7'ye karşı 56,3). Buyruk
zamanla değil, **kişi değişimiyle** çöküyor: duyuruyu duymamış birinin elinde kalıp durum bile
belirsizdir.

Birlikte çalışmanın ikinci dalgadaki değeri 58,9, yazılı gerekçenin 56,3 — aradaki fark 2,6. Bu
fark, birlikte çalışılan kişilerin ayrılıp ayrılmadığına bağlı. Tek tohumlu koşumda üç kişiden
ikisi kalmıştı; hiçbiri kalmasaydı biçim buyruğa yaklaşırdı. Koçluğun aktardığı şey bir belgede
değil, bir kişide duruyor ve o kişiyle birlikte gidebiliyor.

Üç biçim için tek cümlelik sonuç şudur ve üçü de bir sayıya bağlı: buyruk en ucuz aktarımdır ve
kenar durumların %15'ini doğru geçer; yazılı gerekçe orta maliyetlidir, kenar durumların
yarısına yakınını doğru geçer ve ekip değiştiğinde ayakta kalır; birlikte çalışma en yüksek
doğruluğu verir, en pahalıdır ve dayanıklılığı birlikte çalışılan kişilerin kalmasına bağlıdır.

#### Özet

- Aktarım biçimleri kalıp durumlarda ayrışmaz; fark yalnız kararın gerekçesini gerektiren kenar
  durumlardan gelir, modelde durumların %35'i kenar durumdur.
- Aynı 168 durumda üç biçim %68, %85 ve %87 doğru uygulama verdi; iki yüz tohumdaki ortalamalar
  102,4, 131,4 ve 139,1 oldu.
- Artışlar eşit değil: buyruktan yazılı gerekçeye geçiş saat başına 3,71 doğru uygulama, yazılı
  gerekçeden birlikte çalışmaya geçiş saat başına 0,55 getiriyor.
- Ortalama verim en ucuz biçimde en yüksektir (buyruk 46,56, birlikte çalışma 5,79); aktarım
  biçimi ortalama verime değil artışa bakılarak seçilir.
- Ekip değişimi buyruk ile yazılı gerekçe arasındaki farkı 10,4'ten 18,6'ya çıkarıyor; koçluğun
  kazancı birlikte çalışılan kişilerin kalmasına bağlıdır, yazılı gerekçeninki değildir.

#### Sonraki Adım

Bu konu mimarın rolünü tanımladı ve her parçasını bir sayıya bağladı: kararın ne olduğu geri alma
maliyetiyle, düzeyi kapsadığı birim sayısıyla, sorumlulukları gözetimsiz kararın uygulanma
oranıyla, koddan kopmanın bedeli ölü karar oranıyla, aktarım biçimi de doğru uygulanma oranıyla
ölçüldü.

Bütün bu ölçümlerde kararlar hazır girdi olarak alındı. Karar kümesi verildi, kapsamı ölçüldü,
aktarıldı ve izlendi — ama **kararın kendisi nasıl verilir** sorusuna hiç girilmedi. Çelişen iki
kalite niteliği arasında seçim nasıl yapılır; bir sistemdeki karmaşıklığın hangisi işin
doğasından gelir ve hangisi sonradan eklenmiştir; hangi kararın geri alınabilir olduğu karar
anında nasıl bilinir; bir teknoloji seçiminin çıkış maliyeti nasıl hesaplanır. Sonraki konu bu
sorulara geçer ve ilki en zorudur: iki nitelik birbiriyle çelişiyorsa, kazananı seçen ağırlıklar
nereden gelir ve ağırlık değiştiğinde kazanan değişir mi.

## Mimar Pratiği

Kararın günlük pratiği: çelişen niteliklerin uzlaştırılması, karmaşıklığın bilinçli azaltılması, geri döndürülebilir ile döndürülemez kararların ayrı yöntemle verilmesi, teknik olmayan muhataplarla iletişim, olgunluk, ekosistem ve çıkış maliyeti üzerinden teknoloji değerlendirme ve bilgi tazeliğini sürdüren öğrenme disiplini.

### Denge Kurmak

Source: https://academia.sh/tr/kurslar/mimarin-rolu/denge-kurmak

Çelişen kalite nitelikleri arasında seçim yapma pratiği: alternatif–nitelik tablosunun bir veri yapısına çevrilmesi, aynı tablonun iki ağırlık kümesiyle puanlanması, ağırlık değiştikçe kazanan alternatifin değişmesinin duyarlılık taramasıyla sayılması ve her ağırlığın kaynağının yazılı olup olmamasının kararın savunulabilirliğine bağlanması.

Önceki konu rolün ne olduğunu ve verilmiş bir kararın ekibe nasıl aktarıldığını tanımladı.
Açıkta kalan şey kararın kendisidir: iki kalite niteliği aynı anda sağlanamadığında hangisinin
seçileceği, seçimin neye dayandığı ve seçim sorgulandığında geriye ne kalacağı.

Niteliklerin birbiriyle çelişebildiği ve bu çelişkinin bir olgu olduğu Sistem Tasarımına Giriş
kursunda ölçüldü; erişilebilirlik ile tutarlılık arasındaki gerilim orada sayılarla gösterildi.
Burada tekrarlanmaz. Bu dersin sorusu gerilimin var olup olmadığı değil, gerilim verilmişken
kararın **nasıl** verildiğidir. Ölçülecek nicelik de budur: bir kararın hangi varsayıma ne kadar
tutunduğu.

#### Kararın Nesnesi: Alternatif–Nitelik Tablosu

Through-line bölgesel bir kütüphane ağının yazılım sistemidir. Kurgu bir modeldir; gerçek bir
kurum, ekip ya da ürün anlatılmaz. Modelde on dört şube, merkezde kendi bütçesi olan bir bilgi
işlem birimi, dışarıdan alınmış bir katalog sistemi ve içeride yazılmış ödünç servisleri vardır.

Karar şudur: şubelerin ödünç kayıtlarına erişimi nasıl kurulacak? Dört alternatif ve dört nitelik
tanımlanır (**MP1**; puanlar 1–5 aralığında, büyük olan daha iyidir ve model değerleridir):

- `tek-merkez` — tek yetkili veritabanı, her şube her işlemde merkeze bağlanır.
- `sube-onbellek` — merkez yetkili, her şubede salt-okunur önbellek; yazma merkeze gider.
- `sube-kopya` — her şubede tam kopya, şube işlemi yerelde kapatır, eşitleme sonradan olur.
- `dis-modul` — dışarıdan alınmış katalog sisteminin kendi ödünç modülü kullanılır.

Karar, kafada tutulan bir tercih olduğu sürece ölçülemez. Onu ölçülebilir kılan tek şey bir veri
yapısına çevrilmesidir.

```js
// denge/tablo.mjs — alternatif-nitelik tablosu bir veri yapisi olarak; kurgu bir modeldir
export const NITELIK = ["kesinti-dayanimi", "kayit-tazeligi", "degistirilebilirlik", "isletme-maliyeti"];

// Puanlar 1-5 arasinda, buyuk olan daha iyi (MP1). Kaynaklari derste yazilidir.
export const ALTERNATIF = [
  { ad: "tek-merkez",    puan: [1, 5, 4, 5] },
  { ad: "sube-onbellek", puan: [3, 4, 3, 4] },
  { ad: "sube-kopya",    puan: [5, 2, 2, 2] },
  { ad: "dis-modul",     puan: [4, 3, 1, 3] },
];

export function puanla(agirlik) {
  return ALTERNATIF.map((a) => ({
    ad: a.ad,
    toplam: a.puan.reduce((t, p, i) => t + p * agirlik[i], 0),
  })).sort((x, y) => y.toplam - x.toplam);
}

export const kazanan = (agirlik) => puanla(agirlik)[0].ad;
```

Tabloda hiçbir satır bütün sütunlarda üstün değildir. Ödünleşim tam olarak budur: bir sütunu
yükselten alternatif başka bir sütunu düşürür. Kazananı belirleyen şey artık puanlar değil,
sütunlara verilen ağırlıklardır.

#### Aynı Tablo, İki Ağırlık Kümesi

İki uygulama biçimi aynı girdide koşturulur. Birincisi ağırlık sorusunu hiç sormaz ve dört
niteliği eşit sayar — pratikte en sık görülen biçim budur, çünkü ağırlık yazılmadığında öntanımlı
olarak eşit kabul edilmiş olur. İkincisi ağırlıkları açıkça yazar.

```js
// denge/puanla.mjs — ayni tablo iki agirlik kumesiyle: kazanan alternatif degisiyor mu
import { NITELIK, ALTERNATIF, puanla } from "./tablo.mjs";

const KUME = {
  "esit-agirlik": [0.25, 0.25, 0.25, 0.25],
  "yazili-agirlik": [0.50, 0.20, 0.15, 0.15],
};

console.log(`nitelik      : ${NITELIK.join(" ")}`);
for (const a of ALTERNATIF) console.log(`${a.ad.padEnd(13)}: ${a.puan.join("    ")}`);
console.log("");
for (const [ad, w] of Object.entries(KUME)) {
  const s = puanla(w);
  console.log(`${ad.padEnd(15)} w=[${w.join(" ")}]`);
  console.log(`  ${s.map((x) => `${x.ad}=${x.toplam.toFixed(2)}`).join("  ")}`);
  console.log(`  kazanan: ${s[0].ad} (ikinciyle fark ${(s[0].toplam - s[1].toplam).toFixed(2)})`);
}
```

```
nitelik      : kesinti-dayanimi kayit-tazeligi degistirilebilirlik isletme-maliyeti
tek-merkez   : 1    5    4    5
sube-onbellek: 3    4    3    4
sube-kopya   : 5    2    2    2
dis-modul    : 4    3    1    3

esit-agirlik    w=[0.25 0.25 0.25 0.25]
  tek-merkez=3.75  sube-onbellek=3.50  sube-kopya=2.75  dis-modul=2.75
  kazanan: tek-merkez (ikinciyle fark 0.25)
yazili-agirlik  w=[0.5 0.2 0.15 0.15]
  sube-kopya=3.50  sube-onbellek=3.35  dis-modul=3.20  tek-merkez=2.85
  kazanan: sube-kopya (ikinciyle fark 0.15)
```

Aynı puan tablosu, aynı dört alternatif; kazanan `tek-merkez` yerine `sube-kopya` oldu ve
`tek-merkez` sondan birinciliğe düştü. Kararı belirleyen şey alternatiflerin ölçülmüş
nitelikleri değil, ağırlıklardır. Ağırlıklar yazılmadığında karar yine de verilir — eşit ağırlık
da bir ağırlık kümesidir, yalnızca kimse onu seçtiğini söylememiştir.

İki kümedeki fark sütunlarının küçüklüğü de bir bilgidir: 0,25 ve 0,15. Kazanan alternatif
ikincisini yarım puan geride bırakmıyor. Bu, kararın ne kadar sağlam durduğunu sormayı gerektirir.

#### Duyarlılık Taraması

Tek bir ağırlık kümesiyle çıkan sonuç bir karar değil, bir örnektir. Kararın ne kadar dayanıklı
olduğu ancak ağırlık uzayı taranarak görülür. Tarama, dört ağırlığın toplamı 1 olacak biçimde
0,05 adımlı bir ızgara üretir ve her noktada kazananı sayar.

```js
// denge/tarama.mjs — duyarlilik taramasi: agirlik degistikce kazanan alternatif degisiyor mu
import { NITELIK, ALTERNATIF, puanla, kazanan } from "./tablo.mjs";

const ADIM = 0.05, N = NITELIK.length, ESIT = 1e-9;
const izgara = [];
(function uret(kalan, biriken) {
  if (biriken.length === N - 1) return izgara.push([...biriken, kalan]);
  for (let p = 0; p <= kalan + ESIT; p += ADIM) uret(kalan - p, [...biriken, p]);
})(1, []);

const kesin = new Map(ALTERNATIF.map((a) => [a.ad, 0]));
let berabere = 0;
for (const w of izgara) {
  const s = puanla(w);
  if (s[0].toplam - s[1].toplam < ESIT) { berabere += 1; continue; }
  kesin.set(s[0].ad, kesin.get(s[0].ad) + 1);
}
console.log(`izgara: adim ${ADIM}, ${izgara.length} agirlik vektoru`);
for (const [ad, k] of [...kesin].sort((a, b) => b[1] - a[1]))
  console.log(`  ${ad.padEnd(13)} tek basina ilk sirada: ${String(k).padStart(4)} vektor (%${(100 * k / izgara.length).toFixed(1)})`);
console.log(`  (ilk iki alternatifin esitlendigi ${berabere} vektor sayilmadi)`);

const SECILEN = [0.50, 0.20, 0.15, 0.15];
const secilenKazanan = kazanan(SECILEN);
const l1 = (a, b) => a.reduce((t, v, i) => t + Math.abs(v - b[i]), 0);
let enYakin = { d: Infinity, w: null, ad: null };
for (const w of izgara) {
  const k = kazanan(w);
  if (k === secilenKazanan) continue;
  const d = l1(w, SECILEN);
  if (d < enYakin.d) enYakin = { d, w, ad: k };
}
console.log(`\nsecilen agirlik [${SECILEN.join(" ")}] -> ${secilenKazanan}`);
console.log(`kirilma mesafesi (L1): ${enYakin.d.toFixed(2)}`);
console.log(`  en yakin farkli vektor [${enYakin.w.map((x) => x.toFixed(2)).join(" ")}] -> ${enYakin.ad}`);

console.log("\ntek agirligi 0.10 oynatinca (kalan uc agirlik oranti korunarak dengelenir):");
for (let i = 0; i < N; i++) {
  const satir = [];
  for (const delta of [-0.10, +0.10]) {
    const yeni = SECILEN.slice();
    yeni[i] = Math.max(0, Math.min(1, yeni[i] + delta));
    const pay = (1 - yeni[i]) / (1 - SECILEN[i]);
    for (let j = 0; j < N; j++) if (j !== i) yeni[j] = SECILEN[j] * pay;
    satir.push(`${delta > 0 ? "+" : ""}${delta.toFixed(2)} -> ${kazanan(yeni)}`);
  }
  const degisti = satir.some((s) => !s.endsWith(secilenKazanan));
  console.log(`  ${NITELIK[i].padEnd(20)} ${satir.join(" , ")}${degisti ? "   <- kazanan degisti" : ""}`);
}
```

```
izgara: adim 0.05, 1771 agirlik vektoru
  tek-merkez    tek basina ilk sirada: 1211 vektor (%68.4)
  sube-kopya    tek basina ilk sirada:  314 vektor (%17.7)
  sube-onbellek tek basina ilk sirada:  220 vektor (%12.4)
  dis-modul     tek basina ilk sirada:    0 vektor (%0.0)
  (ilk iki alternatifin esitlendigi 26 vektor sayilmadi)

secilen agirlik [0.5 0.2 0.15 0.15] -> sube-kopya
kirilma mesafesi (L1): 0.10
  en yakin farkli vektor [0.45 0.20 0.15 0.20] -> sube-onbellek

tek agirligi 0.10 oynatinca (kalan uc agirlik oranti korunarak dengelenir):
  kesinti-dayanimi     -0.10 -> sube-onbellek , +0.10 -> sube-kopya   <- kazanan degisti
  kayit-tazeligi       -0.10 -> sube-kopya , +0.10 -> sube-onbellek   <- kazanan degisti
  degistirilebilirlik  -0.10 -> sube-kopya , +0.10 -> sube-kopya
  isletme-maliyeti     -0.10 -> sube-kopya , +0.10 -> sube-onbellek   <- kazanan degisti
```

Tarama üç ayrı sayı üretiyor ve üçü de karar hakkında farklı şey söylüyor.

**Kazanılan bölge.** Seçilen alternatif `sube-kopya`, 1771 vektörün 314'ünde ilk sırada. Karar,
ağırlık uzayının yüzde 17,7'sinde savunulabilir bir karardır. `tek-merkez` yüzde 68,4 ile en geniş
bölgeyi tutuyor; yani seçilen alternatif "genelde en iyi" olan değil, yazılan ağırlıklar altında
en iyi olandır. Bu iki cümle arasındaki fark, kararın gerekçesinin tamamıdır.

**Kırılma mesafesi.** Seçilen vektörden kazananın değiştiği en yakın noktaya L1 uzaklığı 0,10;
işletme maliyeti ağırlığı 0,15'ten 0,20'ye çıkarıldığında kazanan `sube-onbellek` oluyor. Dört
ağırlığın üçünde 0,10'luk bir oynama kazananı değiştiriyor. Bu bir kusur değil, kararın gerçek
hassasiyetidir; sorun ancak bu hassasiyet bilinmeden karar verildiğinde başlar.

**Hiçbir ağırlıkta kazanmayan alternatif.** `dis-modul` 1771 vektörün hiçbirinde tek başına ilk
sırada değil. Bu sonuç ağırlık tartışmasından bağımsızdır: hangi ağırlık kümesi üzerinde
anlaşılırsa anlaşılsın bu alternatif seçilmeyecektir, çünkü `sube-onbellek` ile `sube-kopya`
birlikte onu her yönden kapatıyor. Toplantıda üzerinde en çok konuşulacak alternatif, tartışmaya
hiç girmeden elenebilir olandır.

#### Ağırlığın Kaynağı

Buraya kadar ölçülen her şey ağırlıkların doğru olduğunu varsaydı. Ağırlıkların kendisi nereden
geliyor? Sistem Tasarımına Giriş kursunda kurulan **eşiğin kaynağı** ölçüsü tam olarak bunu
sorar: bir sayı yazıldığında, onun neden o sayı olduğu da yazılmış olmalıdır. Ağırlık da bir
eşiktir; kaynağı yazılmamış ağırlık, kaynağı yazılmamış eşikle aynı boşluğu bırakır.

Aşağıdaki koşum her ağırlığa bir kaynak alanı ekler ve iki şeyi kesiştirir: ağırlığın kaynağı
yazılı mı ve o ağırlık kazananı değiştirebiliyor mu. Kaynak olarak gösterilen üç kayıt
modelin girdisidir (**MP2**); dördüncü ağırlığın arkasında bir kayıt yoktur.

```js
// denge/kaynak.mjs — her agirligin kaynagi yazili mi, kirilma o agirligin uzerinde mi
import { NITELIK, kazanan } from "./tablo.mjs";

const AGIRLIK = [
  { deger: 0.50, kaynak: "sube aginin kopuk kaldigi sure kaydi (MP2)" },
  { deger: 0.20, kaynak: "odunc kurallarindaki yazili iade toleransi (MP2)" },
  { deger: 0.15, kaynak: "yillik kural degisikligi sayisi kaydi (MP2)" },
  { deger: 0.15, kaynak: null },
];

function oynat(w, i, delta) {
  const yeni = w.slice();
  yeni[i] = Math.max(0, Math.min(1, yeni[i] + delta));
  const pay = (1 - yeni[i]) / (1 - w[i]);
  for (let j = 0; j < w.length; j++) if (j !== i) yeni[j] = w[j] * pay;
  return yeni;
}

function denetle(agirlik) {
  const w = agirlik.map((a) => a.deger);
  const temel = kazanan(w);
  const satir = agirlik.map((a, i) => ({
    ad: NITELIK[i],
    kaynakli: a.kaynak !== null,
    kirilgan: [-0.10, 0.10].some((d) => kazanan(oynat(w, i, d)) !== temel),
  }));
  return { temel, satir, acik: satir.filter((s) => s.kirilgan && !s.kaynakli).length };
}

for (const [ad, agirlik] of [["ilk hali", AGIRLIK],
  ["maliyet agirligi olculdukten sonra", AGIRLIK.map((a, i) =>
    i === 3 ? { deger: 0.25, kaynak: "birim butce tavani ve kopya basina yillik gider (MP3)" }
      : i === 0 ? { deger: 0.40, kaynak: a.kaynak } : a)]]) {
  const d = denetle(agirlik);
  console.log(`${ad}: w=[${agirlik.map((a) => a.deger.toFixed(2)).join(" ")}] -> ${d.temel}`);
  for (const s of d.satir)
    console.log(`  ${s.ad.padEnd(20)} kaynak: ${(s.kaynakli ? "yazili" : "yok").padEnd(7)}` +
      ` kirilgan: ${s.kirilgan ? "evet" : "hayir"}`);
  console.log(`  kazanani degistirebilen ama kaynagi yazilmamis agirlik: ${d.acik}\n`);
}
```

```
ilk hali: w=[0.50 0.20 0.15 0.15] -> sube-kopya
  kesinti-dayanimi     kaynak: yazili  kirilgan: evet
  kayit-tazeligi       kaynak: yazili  kirilgan: evet
  degistirilebilirlik  kaynak: yazili  kirilgan: hayir
  isletme-maliyeti     kaynak: yok     kirilgan: evet
  kazanani degistirebilen ama kaynagi yazilmamis agirlik: 1

maliyet agirligi olculdukten sonra: w=[0.40 0.20 0.15 0.25] -> sube-onbellek
  kesinti-dayanimi     kaynak: yazili  kirilgan: evet
  kayit-tazeligi       kaynak: yazili  kirilgan: hayir
  degistirilebilirlik  kaynak: yazili  kirilgan: hayir
  isletme-maliyeti     kaynak: yazili  kirilgan: hayir
  kazanani degistirebilen ama kaynagi yazilmamis agirlik: 0
```

İlk koşumda kararı taşıyamayan tek bir sayı var: işletme maliyeti ağırlığı hem kazananı
değiştirebiliyor hem de kaynağı yazılmamış. Karar `sube-kopya` yönünde verildi, ama gerekçesinin
bir bacağı boşta. `degistirilebilirlik` ağırlığının kaynağı yazılmış olması ise kararı hiç
sağlamlaştırmıyor — o ağırlık 0,10 oynatıldığında kazanan değişmiyor. Gerekçe yazma emeği,
kararın taşındığı yere değil, taşınmadığı yere harcanmış.

İkinci koşum eksik kaynağın kapatılmasının sonucudur: birim bütçe tavanı ve kopya başına yıllık
gider ölçülünce (**MP3**) maliyet ağırlığı 0,15 yerine 0,25 çıkıyor, kesinti ağırlığı da 0,50'den 0,40'a
iniyor. Kazanan `sube-onbellek` oluyor ve kaynağı yazılmamış kırılgan ağırlık sayısı 1'den 0'a
düşüyor. İlk karar yanlış değildi; ölçülmemişti. İki koşumun farkı, mimarın işinin ağırlıkları
tartışmak değil, ağırlıkların kaynağını bulmak olduğunu gösteriyor.

Buradan çıkan ölçü şudur: **kazananı değiştirebilen ama kaynağı yazılmamış ağırlık sayısı.** Bu
sayı sıfır değilse karar savunulabilir değildir — doğru ya da yanlış olduğu bilinmiyor demektir.
Sayı sıfırsa karar tartışılabilir kalır, ama tartışma artık ağırlık üzerinde değil, ağırlığın
dayandığı kayıt üzerinde yürür ve o kayıt ölçülebilir bir şeydir.

#### Özet

- Denge kurmak, tercih beyan etmek değil, alternatif–nitelik tablosunu bir veri yapısına çevirip
  ağırlıklı puanlamayı koşturmaktır; tabloda hiçbir alternatif bütün sütunlarda üstün değildir.
- Aynı dört alternatif ve aynı puanlar, eşit ağırlıkla `tek-merkez`, yazılı ağırlıkla
  `sube-kopya` kazandırdı; ağırlık yazılmadığında eşit ağırlık öntanımlı olarak seçilmiş olur.
- 1771 vektörlük duyarlılık taramasında `sube-kopya` yüzde 17,7'lik bir bölgede kazandı,
  `tek-merkez` yüzde 68,4'lük bölgede; kırılma mesafesi 0,10 ve dört ağırlığın üçünde 0,10'luk
  oynama kazananı değiştiriyor.
- `dis-modul` 1771 vektörün hiçbirinde tek başına ilk sırada değil; ağırlık üzerinde anlaşmaya
  gerek kalmadan elenebilen alternatif, tartışmadan önce elenir.
- Kararın savunulabilirliği tek bir sayıyla ölçülür: kazananı değiştirebilen ama kaynağı
  yazılmamış ağırlık sayısı. İlk koşumda 1, maliyet ağırlığı ölçüldükten sonra 0 ve kazanan
  `sube-onbellek` oldu.

#### Sonraki Adım

Denge kurma ölçümü kararın **hangi** alternatife gittiğini verdi, ama seçilen alternatifin
kendisinin ne kadar ağır olduğunu sormadı. `sube-onbellek` seçildiğinde ortaya bir önbellek
katmanı, bir eşitleme yolu ve bir geçersizleştirme kuralı çıkar; her biri sistemin taşıyacağı
yeni bir parçadır. Bir sonraki soru şudur: bu parçaların hangisi işin kendisinden gelir,
hangisi yalnızca çözümün kurulma biçiminden? İkisini ayırmadan yapılan her sadeleştirme, ya
gereken bir şeyi siler ya da hiçbir şeyi silmez. Sonraki ders karmaşıklığı iki bileşene ayırır
ve sadeleştirmenin kaldırabildiği payı, kaldıramadığı paydan sayarak ayırır.

### Basitleştirmek

Source: https://academia.sh/tr/kurslar/mimarin-rolu/basitlestirmek

Karmaşıklığın bilinçli azaltılması: arızi ile özsel karmaşıklığın ayrılması, bir çözümün modül grafiğindeki toplam karmaşıklığın gereksinim grafiğinden okunan özsel tabana göre iki bileşene bölünmesi, sadeleştirmenin kaldırdığı arızi payın ve kaldıramadığı payın sayılması ve aynı değişiklik kümesi iki grafikte koşturularak sadeleştirmenin karşılığında büyüyen şeyin ölçülmesi.

Önceki ders kararın hangi alternatife gittiğini ölçtü. Seçilen alternatif ortaya bir parça kümesi
çıkarır: bir önbellek katmanı, bir eşitleme yolu, bir geçersizleştirme kuralı. Zamanla bu parçalar
birikir ve sistem "karmaşık" diye anılmaya başlar. Karmaşıklık bir sıfat olarak kullanıldığı sürece
üzerine karar verilemez, çünkü azaltma isteği ile azaltma imkânı arasındaki farkı göstermez.

Bu dersin sorusu şudur: bir çözümdeki karmaşıklığın ne kadarı kaldırılabilir, ne kadarı işin
kendisinden gelir? Ayrım yapılmadan girişilen sadeleştirme iki biçimde başarısız olur — ya gereken
bir şeyi siler, ya da hiçbir şeyi silmez ve yalnızca yeniden düzenler. Bağlaşım ve bütünlük
ölçüleri önkoşul tasarım kurslarında kuruldu; burada tekrarlanmaz. Ölçülecek olan, karmaşıklığın
iki bileşene bölünmesidir.

#### Arızi ve Özsel Karmaşıklık

**Özsel karmaşıklık** (essential complexity), çözülen işin kendisinden gelen ve hiçbir
gerçekleştirimde ortadan kalkmayan paydır. Ödünç verilen bir kitabın iade tarihinin olması,
gecikmenin bir bedele dönüşmesi, uzatmanın hem ödünç kaydına hem bedele bağlı olması — bunlar
kütüphane ağının kurallarından gelir. Kod nasıl yazılırsa yazılsın bu bağlar durur.

**Arızi karmaşıklık** (accidental complexity), çözümün kurulma biçiminden gelen paydır. Aynı işi
karşılayan ikinci bir modül, hiçbir davranışı karşılamadığı halde araya girmiş bir sarmalayıcı,
tek bir ayarı okumak için kurulmuş bir katman. Bunlar işin değil, çözümün özellikleridir.

Ayrım kulağa açık gelir ama pratikte tartışmaya açıktır, çünkü herkes kendi eklediği katmanı özsel
sayar. Tartışmayı kapatan tek şey ayrımı bir ölçüye bağlamaktır: **özsel pay çözümden değil,
gereksinimden okunur.** Aynı davranış kümesini karşılayan herhangi bir çözümün inebileceği en alt
sınır, gereksinimlerin kendi grafiğidir.

#### İki Grafik: Çözüm ve Gereksinim

Model iki grafik tutar. Birincisi kütüphane ağı kurallarının dayattığı davranışlar ve aralarındaki
zorunlu bağlardır. İkincisi içeride yazılmış ödünç servislerinin bugünkü modül grafiğidir. Kurgu
bir modeldir; gerçek bir kurum ya da ürün anlatılmaz.

```js
// sade/grafik.mjs — odunc servislerinin modul grafigi ve gereksinim grafigi; kurgu bir modeldir
// GEREKSINIM: kutuphane agi kurallarinin dayattigi davranislar ve aralarindaki zorunlu bag (MP4)
export const GEREKSINIM = {
  r1: { ad: "odunc-ver", baglar: ["r7"] },
  r2: { ad: "iade-al", baglar: ["r4"] },
  r3: { ad: "uzatma", baglar: ["r1", "r4"] },
  r4: { ad: "gecikme-bedeli", baglar: [] },
  r5: { ad: "ayirtma", baglar: [] },
  r6: { ad: "subeler-arasi-istek", baglar: ["r5"] },
  r7: { ad: "uyelik-dogrulama", baglar: [] },
  r8: { ad: "ceza-affi", baglar: ["r4"] },
  r9: { ad: "raf-durumu-bildirimi", baglar: [] },
};

// MODUL: cozumun bugunku hali. ayarOkur = sube basina degisen ayari dogrudan okuyan modul (MP5)
export const MODUL = [
  { ad: "odunc-akisi", ihtiyac: ["r1"], ayarOkur: false },
  { ad: "iade-akisi", ihtiyac: ["r2"], ayarOkur: false },
  { ad: "uzatma-akisi", ihtiyac: ["r3"], ayarOkur: false },
  { ad: "bedel-hesabi", ihtiyac: ["r4"], ayarOkur: false },
  { ad: "ayirtma-akisi", ihtiyac: ["r5"], ayarOkur: false },
  { ad: "subeler-arasi", ihtiyac: ["r6"], ayarOkur: false },
  { ad: "uyelik-kapisi", ihtiyac: ["r7"], ayarOkur: false },
  { ad: "af-akisi", ihtiyac: ["r8"], ayarOkur: false },
  { ad: "raf-bildirimi", ihtiyac: ["r9"], ayarOkur: false },
  { ad: "odunc-yardimcisi", ihtiyac: ["r1"], ayarOkur: false },
  { ad: "iade-yardimcisi", ihtiyac: ["r2"], ayarOkur: false },
  { ad: "kayit-koprusu", ihtiyac: [], ayarOkur: false },
  { ad: "olay-koprusu", ihtiyac: [], ayarOkur: false },
  { ad: "ayar-sarmalayici", ihtiyac: [], ayarOkur: true },
];

export const BAG = [
  ["odunc-akisi", "odunc-yardimcisi"], ["odunc-akisi", "uyelik-kapisi"],
  ["odunc-akisi", "kayit-koprusu"], ["odunc-akisi", "ayar-sarmalayici"],
  ["iade-akisi", "iade-yardimcisi"], ["iade-akisi", "bedel-hesabi"],
  ["iade-akisi", "kayit-koprusu"], ["iade-akisi", "ayar-sarmalayici"],
  ["uzatma-akisi", "odunc-yardimcisi"], ["uzatma-akisi", "bedel-hesabi"],
  ["uzatma-akisi", "ayar-sarmalayici"], ["bedel-hesabi", "kayit-koprusu"],
  ["bedel-hesabi", "ayar-sarmalayici"], ["ayirtma-akisi", "kayit-koprusu"],
  ["ayirtma-akisi", "olay-koprusu"], ["ayirtma-akisi", "ayar-sarmalayici"],
  ["subeler-arasi", "ayirtma-akisi"], ["subeler-arasi", "olay-koprusu"],
  ["subeler-arasi", "ayar-sarmalayici"], ["af-akisi", "bedel-hesabi"],
  ["af-akisi", "kayit-koprusu"], ["raf-bildirimi", "olay-koprusu"],
  ["uyelik-kapisi", "kayit-koprusu"],
];

export const kopya = () => ({
  modul: MODUL.map((m) => ({ ...m, ihtiyac: [...m.ihtiyac] })),
  bag: BAG.map((b) => [...b]),
});

export const olcu = (g) => g.modul.length + g.bag.length;
```

Karmaşıklık ölçüsü kasten kaba tutuldu: modül sayısı artı bağ sayısı. Ölçünün inceliği burada
önemli değildir, çünkü ölçülen şey mutlak bir büyüklük değil, iki grafik arasındaki farktır.

Sadeleştirme iki adımdan oluşur ve ikisi de tek bir kurala dayanır: bir modül ancak hiçbir
davranışı ayırt etmiyorsa kaldırılabilir.

```js
// sade/sadelestir.mjs — iki sadelestirme adimi: ayni gereksinimi karsilayan modulu birlestir,
// hicbir gereksinimi karsilamayan sarmalayiciyi kaldir (isi cagiranlarina gecer)
function birlestir(g, at, kalan) {
  g.bag = g.bag.map(([a, b]) => [a === at ? kalan : a, b === at ? kalan : b])
    .filter(([a, b]) => a !== b);
  const k = g.modul.find((m) => m.ad === kalan);
  k.ayarOkur ||= g.modul.find((m) => m.ad === at).ayarOkur;
  g.modul = g.modul.filter((m) => m.ad !== at);
}

function kaldir(g, at) {
  const onceki = g.bag.filter(([, b]) => b === at).map(([a]) => a);
  const sonraki = g.bag.filter(([a]) => a === at).map(([, b]) => b);
  const okur = g.modul.find((m) => m.ad === at).ayarOkur;
  g.bag = g.bag.filter(([a, b]) => a !== at && b !== at);
  for (const o of onceki) {
    if (okur) g.modul.find((m) => m.ad === o).ayarOkur = true;
    for (const s of sonraki) if (o !== s && !g.bag.some(([a, b]) => a === o && b === s)) g.bag.push([o, s]);
  }
  g.modul = g.modul.filter((m) => m.ad !== at);
}

export function sadelestir(g) {
  birlestir(g, "odunc-yardimcisi", "odunc-akisi");
  birlestir(g, "iade-yardimcisi", "iade-akisi");
  kaldir(g, "ayar-sarmalayici");
  return g;
}
```

`kaldir` işlevindeki tek satır dersin yarısını taşıyor: kaldırılan modül `ayarOkur` ise, bu
nitelik onu çağıran modüllere geçer. Sarmalayıcı kaldırıldığında yaptığı iş yok olmaz, dağılır.

#### Ayrımın Ölçülmesi

```js
// sade/ayir.mjs — toplam karmasikligi ozsel ve arizi bilesene ayirir, sonra sadelestirmeyi kosturur
import { GEREKSINIM, kopya, olcu } from "./grafik.mjs";
import { sadelestir } from "./sadelestir.mjs";

const g = kopya();
const toplam = olcu(g);
const ozselModul = Object.keys(GEREKSINIM).length;
const ozselBag = Object.values(GEREKSINIM).reduce((t, r) => t + r.baglar.length, 0);
const ozsel = ozselModul + ozselBag;

console.log(`modul grafigi     : ${g.modul.length} modul + ${g.bag.length} bag = ${toplam}`);
console.log(`gereksinim grafigi: ${ozselModul} davranis + ${ozselBag} zorunlu bag = ${ozsel}`);
console.log(`ozsel = ${ozsel}, arizi = ${toplam - ozsel} (%${(100 * (toplam - ozsel) / toplam).toFixed(1)})`);

sadelestir(g);
const sade = olcu(g);
console.log(`\nsadelestirmeden sonra: ${g.modul.length} modul + ${g.bag.length} bag = ${sade}`);
console.log(`kaldirilan arizi pay : ${toplam - sade}`);
console.log(`kalan arizi pay      : ${sade - ozsel}`);
console.log(`inilemeyen taban     : ${ozsel} (ozsel)`);
console.log(`ayari dogrudan okuyan modul: once 1, sonra ${g.modul.filter((m) => m.ayarOkur).length}`);
```

```
modul grafigi     : 14 modul + 23 bag = 37
gereksinim grafigi: 9 davranis + 6 zorunlu bag = 15
ozsel = 15, arizi = 22 (%59.5)

sadelestirmeden sonra: 11 modul + 15 bag = 26
kaldirilan arizi pay : 11
kalan arizi pay      : 11
inilemeyen taban     : 15 (ozsel)
ayari dogrudan okuyan modul: once 1, sonra 6
```

Toplam karmaşıklık 37; bunun 15'i özsel, 22'si arızidir. Yani çözümün yarısından fazlası
gereksinimden değil, çözümün kurulma biçiminden geliyor. Bu oran tek başına bir eylem çağrısı
değildir; ayrımın ne işe yaradığını gösteren şey sonraki satırlardır.

Sadeleştirme 37'yi 26'ya indirdi, yani 22'lik arızi paydan 11'ini kaldırdı. Kalan 11 de arızidir
ama kaldırılamadı: `kayit-koprusu` ve `olay-koprusu` hiçbir davranışı karşılamıyor, buna karşılık
gerçek iş yapıyorlar — biri kayıt yazımını, öteki olay yayımını tek yerde topluyor. Onları
kaldırmak işi ortadan kaldırmaz, altı ayrı modüle kopyalar. Arızi olmak kaldırılabilir olmakla
aynı şey değildir.

Son satır ise sadeleştirmenin bedelidir. Şube başına değişen ayarı önce tek bir modül okuyordu;
sarmalayıcı kaldırıldıktan sonra altı modül okuyor. Karmaşıklık ölçüsü 11 azaldı, ama bir
niteliğin dağıldığı yer altı katına çıktı. Ölçü bunu görmez; bir sonraki koşum görür.

#### Sadeleştirmenin Karşılığı

Karşılaştırma aynı değişiklik kümesini iki grafikte koşturur. Değişiklikler önümüzdeki on iki ayda
beklenenlerdir (**MP6**) ve iki türdür: bir davranışın kuralını değiştirenler ve bir kuralı şube
başına farklılaştıran yayılan değişiklik.

```js
// sade/degisiklik.mjs — ayni degisiklik kumesi iki grafikte: dokunulan modul sayisi
import { kopya } from "./grafik.mjs";
import { sadelestir } from "./sadelestir.mjs";

// MP6: on iki ayda beklenen degisiklikler. "yayilan" = sube basina farklilasan kural.
const DEGISIKLIK = [
  { ad: "gecikme bedeli orani", tur: "gereksinim", hedef: "r4" },
  { ad: "uzatma hakki sayisi", tur: "gereksinim", hedef: "r3" },
  { ad: "ayirtma suresi", tur: "gereksinim", hedef: "r5" },
  { ad: "odunc verme kurali", tur: "gereksinim", hedef: "r1" },
  { ad: "iade akisina yeni adim", tur: "gereksinim", hedef: "r2" },
  { ad: "sube basina gecikme bedeli", tur: "yayilan", hedef: null },
];

function dokunulan(g, d) {
  if (d.tur === "yayilan") return g.modul.filter((m) => m.ayarOkur).map((m) => m.ad);
  const tasiyan = g.modul.filter((m) => m.ihtiyac.includes(d.hedef)).map((m) => m.ad);
  const cagiran = g.bag.filter(([, b]) => tasiyan.includes(b)).map(([a]) => a);
  return [...new Set([...tasiyan, ...cagiran])];
}

const grafik = { ozgun: kopya(), sade: sadelestir(kopya()) };
console.log("degisiklik                  | ozgun | sade | fark");
console.log("----------------------------|-------|------|-----");
const toplam = { ozgun: 0, sade: 0 };
for (const d of DEGISIKLIK) {
  const o = dokunulan(grafik.ozgun, d).length, s = dokunulan(grafik.sade, d).length;
  toplam.ozgun += o; toplam.sade += s;
  const fark = s - o;
  console.log(`${d.ad.padEnd(27)} | ${String(o).padStart(5)} | ${String(s).padStart(4)} | ` +
    `${fark > 0 ? "+" : ""}${fark}`);
}
console.log("----------------------------|-------|------|-----");
console.log(`${"toplam dokunulan modul".padEnd(27)} | ${String(toplam.ozgun).padStart(5)} | ` +
  `${String(toplam.sade).padStart(4)} | ${toplam.sade - toplam.ozgun}`);
const y = DEGISIKLIK.filter((d) => d.tur === "yayilan");
console.log(`bilinen ${DEGISIKLIK.length - y.length} degisiklikte sade grafik ` +
  `${toplam.ozgun - dokunulan(grafik.ozgun, y[0]).length - (toplam.sade - dokunulan(grafik.sade, y[0]).length)} modul daha az dokundu`);
console.log(`yayilan 1 degisiklikte sade grafik ` +
  `${dokunulan(grafik.sade, y[0]).length - dokunulan(grafik.ozgun, y[0]).length} modul daha fazla dokundu`);
```

```
degisiklik                  | ozgun | sade | fark
----------------------------|-------|------|-----
gecikme bedeli orani        |     4 |    4 | 0
uzatma hakki sayisi         |     1 |    1 | 0
ayirtma suresi              |     2 |    2 | 0
odunc verme kurali          |     3 |    2 | -1
iade akisina yeni adim      |     2 |    1 | -1
sube basina gecikme bedeli  |     1 |    6 | +5
----------------------------|-------|------|-----
toplam dokunulan modul      |    13 |   16 | 3
bilinen 5 degisiklikte sade grafik 2 modul daha az dokundu
yayilan 1 degisiklikte sade grafik 5 modul daha fazla dokundu
```

Sadeleştirme bilinen beş değişiklikte 2 modül kazandırdı; ikinci modülü kaldırılan iki davranışta
değişiklik tek yere düştü, geri kalan üçünde hiçbir şey değişmedi. Yayılan tek değişiklikte ise 5
modül kaybettirdi. Toplamda dokunulan modül sayısı 13'ten 16'ya çıktı.

Bu, sadeleştirmenin yanlış olduğu anlamına gelmez; sadeleştirmenin bir **fiyatı** olduğu anlamına
gelir. Kaldırılan sarmalayıcı gerçekten arızi bir katmandı — hiçbir davranışı ayırt etmiyordu — ama
bir esneklik noktası tutuyordu. O nokta silindiğinde esneklik yok olmadı, altı modüle dağıldı.
Sadeleştirmenin karşılığında büyüyen şey budur: bir değişikliğin geçmesi gereken yer sayısı.

Karar bu yüzden ölçüye değil, ölçülerin karşılaştırılmasına dayanır. Yayılan değişikliğin gerçekten
geleceğine inanılıyorsa sarmalayıcı arızi olmasına rağmen tutulur; gelmeyeceğine inanılıyorsa
kaldırılır ve geldiği gün 6 modüle dokunma maliyeti kabul edilmiş olur. İkisi de savunulabilir;
savunulamayan tek şey bu sayıyı hiç hesaplamadan katman eklemek ya da silmektir.

#### Özet

- Özsel karmaşıklık işin kendisinden gelir ve gereksinim grafiğinden okunur; arızi karmaşıklık
  çözümün kurulma biçiminden gelir ve toplamdan özsel payın çıkarılmasıyla bulunur.
- Modelde toplam karmaşıklık 37 (14 modül + 23 bağ), özsel taban 15 (9 davranış + 6 zorunlu bağ),
  arızi pay 22 — yani toplamın yüzde 59,5'i.
- Sadeleştirme arızi paydan 11'ini kaldırdı ve toplamı 26'ya indirdi; kalan 11 de arızidir ama
  kaldırılamaz, çünkü iki köprü modülü hiçbir davranışı karşılamadan gerçek iş yapıyor.
- Arızi olmak kaldırılabilir olmakla aynı şey değildir; 15'lik özsel taban hiçbir sadeleştirmenin
  altına inemeyeceği sınırdır.
- Aynı altı değişiklik iki grafikte koşturulunca sade grafik bilinen beş değişiklikte 2 modül
  kazandırdı, yayılan tek değişiklikte 5 modül kaybettirdi; toplam 13'ten 16'ya çıktı.
- Sadeleştirmenin karşılığında büyüyen şey, bir değişikliğin geçmesi gereken yer sayısıdır.

#### Sonraki Adım

Sadeleştirme kararının fiyatı hesaplandı, ama bir şey hesaplanmadı: sarmalayıcı kaldırıldıktan
sonra geri getirilebilir mi? Altı modüle dağılmış ayar okumasını tek noktaya toplamak, sarmalayıcıyı
kaldırmakla aynı büyüklükte bir iş değildir. Kararların bir kısmı böyledir — verildikten sonra geri
alınması, verilmesinden kat kat pahalıdır; bir kısmı ise ertesi gün geri alınabilir. İki sınıf aynı
yöntemle ele alındığında iki hata birden yapılır: geri alınabilir kararlar için haftalar harcanır,
geri alınamaz kararlar bir toplantıda verilir. Sonraki ders aynı karar kümesinde geri alma
maliyetini hesaplar, kararları iki sınıfa ayırır ve iki karar yöntemini her iki sınıfta koşturarak
bekleme süresi ile yanlış karar maliyetini karşılaştırır.

### Karar Verme

Source: https://academia.sh/tr/kurslar/mimarin-rolu/karar-verme

Geri döndürülebilir ve geri döndürülemez kararların ayrı yöntemle verilmesi: geri alma maliyetinin bir bağımlılık kümesinden hesaplanması, aynı karar kümesinin bu maliyete göre iki sınıfa ayrılması, hızlı deneme ile uzun değerlendirme yöntemlerinin her iki sınıfta koşturulması ve bekleme süresi ile yanlış karar maliyetinin dört politika üzerinde karşılaştırılması.

Önceki ders bir sadeleştirmenin fiyatını hesapladı ama bir soruyu açıkta bıraktı: kaldırılan
sarmalayıcı geri getirilebilir mi? Altı modüle dağılmış ayar okumasını yeniden tek noktada
toplamak, sarmalayıcıyı kaldırmakla aynı büyüklükte bir iş değildir. Kararların bir kısmı
böyledir; geri alınması, verilmesinden kat kat pahalıdır.

Bu fark pratikte çoğu zaman görülmez, çünkü bütün kararlar aynı yerde ve aynı hızda verilir.
Sonuç iki yönlü bir israftır: geri alınabilir kararlar için haftalarca toplantı yapılır, geri
alınamaz kararlar bir öğleden sonra kapatılır. Bu dersin ölçtüğü şey, bu iki hatanın kaç adam-güne
mal olduğudur.

#### Geri Alma Maliyeti Bir Bağımlılık Kümesinden Okunur

Bir kararın ne kadar geri döndürülebilir olduğu bir his değil, bir hesaptır. Karar bir bileşene
iner; geri almak o bileşeni ve ona bağlı olan her bileşeni dolaşmayı gerektirir. Model kütüphane
ağının yazılım sistemidir; kurgudur, gerçek bir kurum anlatılmaz.

```js
// karar/maliyet.mjs — geri alma maliyeti bir bagimlilik kumesinden okunur; kurgu bir modeldir
// BAGIMLILIK[x] = x'in kullandigi bilesenler. Geri alma, degisen bileseni ve ona bagli
// olan her bileseni dolasmayi gerektirir (MP7).
export const BAGIMLILIK = {
  "veri-deposu": [],
  "odunc-cekirdegi": ["veri-deposu"],
  "uyelik": ["veri-deposu"],
  "katalog-kapisi": ["veri-deposu"],
  "ayirtma": ["odunc-cekirdegi"],
  "raporlama": ["veri-deposu", "odunc-cekirdegi"],
  "odeme-kapisi": ["odunc-cekirdegi"],
  "bildirim": ["ayirtma"],
  "eslesme-hatti": ["katalog-kapisi", "veri-deposu"],
  "sube-istemcisi": ["odunc-cekirdegi", "ayirtma", "katalog-kapisi"],
};

// MP7 katsayilari (adam-gun). Bilesen basina dolasma 2; yazilmis kayitlarin bicimi degistiyse
// goc 15; disa acilmis bir arayuz surumlenmisse esgudum 20.
export const KATSAYI = { bilesen: 2, goc: 15, sozlesme: 20 };

export const KARAR = [
  { ad: "odunc-kaydi-bicimi", bilesen: "veri-deposu", bicim: true, disa: false },
  { ad: "sube-istemcisi-onbellegi", bilesen: "sube-istemcisi", bicim: false, disa: false },
  { ad: "katalog-kapisi-surumu", bilesen: "katalog-kapisi", bicim: false, disa: true },
  { ad: "bildirim-metni-sablonu", bilesen: "bildirim", bicim: false, disa: false },
  { ad: "raporlama-sorgu-plani", bilesen: "raporlama", bicim: false, disa: false },
  { ad: "odunc-kural-motoru", bilesen: "odunc-cekirdegi", bicim: false, disa: false },
  { ad: "ayirtma-siralama-kurali", bilesen: "ayirtma", bicim: false, disa: false },
  { ad: "odeme-arayuzu-surumu", bilesen: "odeme-kapisi", bicim: false, disa: true },
];

export function dolasilan(bilesen) {
  const kume = new Set([bilesen]);
  let buyudu = true;
  while (buyudu) {
    buyudu = false;
    for (const [x, kullandiklari] of Object.entries(BAGIMLILIK))
      if (!kume.has(x) && kullandiklari.some((y) => kume.has(y))) { kume.add(x); buyudu = true; }
  }
  return kume;
}

export const geriAlma = (k) => dolasilan(k.bilesen).size * KATSAYI.bilesen +
  (k.bicim ? KATSAYI.goc : 0) + (k.disa ? KATSAYI.sozlesme : 0);
```

Hesabın üç bileşeni var ve üçü de farklı bir olguyu sayıyor. Dolaşılan bileşen sayısı grafikten
okunur ve kararın nereye indiğine bağlıdır. Kayıt biçimi değiştiyse geri alma yalnız kodu değil,
yazılmış kayıtları da ilgilendirir; bu pay koda dokunmadan da orada durur. Dışa açılmış bir arayüz
sürümlendiyse geri alma tek taraflı yapılamaz, karşı tarafla eşgüdüm gerekir.

#### İki Sınıf

```js
// karar/sinifla.mjs — geri alma maliyeti hesaplanir, kararlar iki sinifa ayrilir
import { KARAR, dolasilan, geriAlma } from "./maliyet.mjs";

// MP8: esik, bir surum dongusunde geri alma icin ayrilabilen kapasitedir: 10 adam-gun.
const ESIK = 10;
console.log("karar                     | bilesen          | dolasilan | goc | disa | geri alma");
console.log("--------------------------|------------------|-----------|-----|------|----------");
for (const k of KARAR)
  console.log(`${k.ad.padEnd(25)} | ${k.bilesen.padEnd(16)} | ` +
    `${String(dolasilan(k.bilesen).size).padStart(9)} | ${(k.bicim ? "var" : "  -").padStart(3)} | ` +
    `${(k.disa ? "var" : "  -").padStart(4)} | ${String(geriAlma(k)).padStart(9)}`);

const sinif = (k) => (geriAlma(k) <= ESIK ? "dondurulebilir" : "dondurulemez");
const grup = { dondurulebilir: [], dondurulemez: [] };
for (const k of KARAR) grup[sinif(k)].push(k);
console.log(`\nesik ${ESIK} adam-gun (MP8)`);
for (const [ad, liste] of Object.entries(grup))
  console.log(`  geri ${ad.padEnd(15)}: ${liste.length} karar, maliyetler ` +
    `${liste.map(geriAlma).join(", ")} (toplam ${liste.reduce((t, k) => t + geriAlma(k), 0)})`);
```

```
karar                     | bilesen          | dolasilan | goc | disa | geri alma
--------------------------|------------------|-----------|-----|------|----------
odunc-kaydi-bicimi        | veri-deposu      |        10 | var |    - |        35
sube-istemcisi-onbellegi  | sube-istemcisi   |         1 |   - |    - |         2
katalog-kapisi-surumu     | katalog-kapisi   |         3 |   - |  var |        26
bildirim-metni-sablonu    | bildirim         |         1 |   - |    - |         2
raporlama-sorgu-plani     | raporlama        |         1 |   - |    - |         2
odunc-kural-motoru        | odunc-cekirdegi  |         6 |   - |    - |        12
ayirtma-siralama-kurali   | ayirtma          |         3 |   - |    - |         6
odeme-arayuzu-surumu      | odeme-kapisi     |         1 |   - |  var |        22

esik 10 adam-gun (MP8)
  geri dondurulebilir : 4 karar, maliyetler 2, 2, 2, 6 (toplam 12)
  geri dondurulemez   : 4 karar, maliyetler 35, 26, 12, 22 (toplam 95)
```

Sekiz kararın dördü **geri döndürülebilir karar**, dördü **geri döndürülemez karardır** ve toplam
geri alma maliyetinin 95'i, yani yüzde 88,8'i dört kararda toplanmış. Sayıların dağılımı da
öğreticidir: `odeme-arayuzu-surumu` yalnız tek bir bileşene iniyor, dolaşılan bileşen sayısı 1,
ama dışa açılmış bir arayüz sürümlendiği için maliyeti 22. `odunc-kural-motoru` altı bileşene
yayılıyor ama geri alması 12. Yani "kaç yere dokunuyor" tek başına sınıfı belirlemiyor; kararı
geri döndürülemez yapan şey çoğu zaman dokunduğu yer sayısı değil, dışarıya verdiği söz ya da
yazdığı kayıttır.

#### İki Yöntem, İki Sınıf

Karşılaştırma iki karar yöntemini aynı karar kümesinde koşturur. **Hızlı deneme** kararı iki günde
verir ve yanlış çıkma oranı yüksektir; **uzun değerlendirme** on beş gün bekletir ve yanlış çıkma
oranı düşüktür. İki yöntem iki ayrı maliyeti üretir: bekleyen her gün gecikme bedeli yazar, yanlış
çıkan her karar geri alma maliyetini yazar.

```js
// karar/yontem.mjs — iki karar yontemi iki sinifta: bekleme suresi ve yanlis karar maliyeti
import { KARAR, geriAlma } from "./maliyet.mjs";

// MP9: hizli deneme 2 gun bekletir ve kararlarin %35'i geri alinir; uzun degerlendirme
// 15 gun bekletir ve %10'u geri alinir. Bekleyen her gun 0.4 adam-gun gecikme bedeli yazar.
const YONTEM = {
  "hizli-deneme": { bekleme: 2, yanlis: 0.35 },
  "uzun-degerlendirme": { bekleme: 15, yanlis: 0.10 },
};
const GUNLUK = 0.4, ESIK = 10;
const beklenen = (y, toplamGeriAlma, adet) =>
  y.bekleme * adet * GUNLUK + y.yanlis * toplamGeriAlma;

const grup = { dondurulebilir: [], dondurulemez: [] };
for (const k of KARAR) grup[geriAlma(k) <= ESIK ? "dondurulebilir" : "dondurulemez"].push(k);

console.log("sinif           | karar | geri alma | hizli-deneme | uzun-degerlendirme | kazanan");
console.log("----------------|-------|-----------|--------------|--------------------|--------");
for (const [ad, liste] of Object.entries(grup)) {
  const t = liste.reduce((s, k) => s + geriAlma(k), 0);
  const h = beklenen(YONTEM["hizli-deneme"], t, liste.length);
  const u = beklenen(YONTEM["uzun-degerlendirme"], t, liste.length);
  console.log(`${ad.padEnd(15)} | ${String(liste.length).padStart(5)} | ${String(t).padStart(9)} | ` +
    `${h.toFixed(2).padStart(12)} | ${u.toFixed(2).padStart(18)} | ${h < u ? "hizli" : "uzun"} (fark ${Math.abs(h - u).toFixed(2)})`);
}

const a = YONTEM["hizli-deneme"], b = YONTEM["uzun-degerlendirme"];
const kirilma = (b.bekleme - a.bekleme) * GUNLUK / (a.yanlis - b.yanlis);
console.log(`\nyontem kirilma noktasi: geri alma maliyeti ${kirilma.toFixed(1)} adam-gunu asinca` +
  ` uzun degerlendirme ucuzlar`);
console.log(`sinif esigi (MP8) ${ESIK}, kirilma noktasi ${kirilma.toFixed(1)}: iki sayi ayni degil`);

const politika = {
  "hepsine-hizli": () => "hizli-deneme",
  "hepsine-uzun": () => "uzun-degerlendirme",
  "esige-gore": (k) => (geriAlma(k) <= ESIK ? "hizli-deneme" : "uzun-degerlendirme"),
  "kirilmaya-gore": (k) => (geriAlma(k) <= kirilma ? "hizli-deneme" : "uzun-degerlendirme"),
};
console.log("\npolitika        | bekleme (gun) | beklenen maliyet (adam-gun)");
console.log("----------------|---------------|----------------------------");
for (const [ad, sec] of Object.entries(politika)) {
  let gun = 0, maliyet = 0;
  for (const k of KARAR) {
    const y = YONTEM[sec(k)];
    gun += y.bekleme;
    maliyet += y.bekleme * GUNLUK + y.yanlis * geriAlma(k);
  }
  console.log(`${ad.padEnd(15)} | ${String(gun).padStart(13)} | ${maliyet.toFixed(2).padStart(27)}`);
}
```

```
sinif           | karar | geri alma | hizli-deneme | uzun-degerlendirme | kazanan
----------------|-------|-----------|--------------|--------------------|--------
dondurulebilir  |     4 |        12 |         7.40 |              25.20 | hizli (fark 17.80)
dondurulemez    |     4 |        95 |        36.45 |              33.50 | uzun (fark 2.95)

yontem kirilma noktasi: geri alma maliyeti 20.8 adam-gunu asinca uzun degerlendirme ucuzlar
sinif esigi (MP8) 10, kirilma noktasi 20.8: iki sayi ayni degil

politika        | bekleme (gun) | beklenen maliyet (adam-gun)
----------------|---------------|----------------------------
hepsine-hizli   |            16 |                       43.85
hepsine-uzun    |           120 |                       58.70
esige-gore      |            68 |                       40.90
kirilmaya-gore  |            55 |                       38.70
```

İlk tablo dersin çekirdeğidir. Aynı iki yöntem, aynı ölçütle, iki sınıfta ters sonuç veriyor. Geri
döndürülebilir sınıfta hızlı deneme 17,80 adam-gün daha ucuz; geri döndürülemez sınıfta uzun
değerlendirme 2,95 adam-gün daha ucuz. Yöntemlerden biri ötekinden iyi değildir; sınıfa
yanlış eşleştirilen yöntem kötüdür.

İki farkın büyüklüğü de eşit değil. Geri döndürülebilir kararlarda yanlış yöntemin cezası 17,80,
geri döndürülemez kararlarda 2,95. Yani geri alınabilir bir karar için uzun değerlendirme
yapmanın bedeli, geri alınamaz bir karar için hızlı denemenin bedelinden bu modelde daha
büyüktür — çünkü uzun değerlendirmenin gecikme bedeli her karar için ödenir, geri alma maliyeti
ise ancak karar yanlış çıkarsa.

#### Eşiğin Kaynağı Yeniden

Alt tablo dört politikayı aynı sekiz karar üzerinde koşturuyor. `hepsine-uzun` politikası hem en
pahalı hem en yavaş: 58,70 adam-gün ve 120 gün bekleme. `hepsine-hizli` en hızlısı, 16 gün, ama
maliyeti sınıfa göre ayıran politikalardan yüksek. İki sınıfı ayırmak, bekleme süresini
`hepsine-uzun` politikasına göre 52 gün kısaltırken maliyeti de 17,80 adam-gün düşürüyor.

Ama iki eşik arasında bir uyuşmazlık var ve bu, ilk dersteki **eşiğin kaynağı** ölçüsünün burada
karşımıza çıkışıdır. Sınıf eşiği 10 adam-gün olarak alındı; kaynağı bir sürüm döngüsünde geri alma
için ayrılabilen kapasiteydi. Yöntem kırılma noktası ise 20,8 adam-gün: bu sayı seçilmedi,
yöntemlerin bekleme süresi ve yanlışlık oranından türetildi. İkisi aynı olmadığı için
`esige-gore` politikası `odunc-kural-motoru` kararını (geri alma 12) uzun değerlendirmeye
gönderiyor, oysa o karar kırılma noktasının altında. `kirilmaya-gore` politikası aynı kararı hızlı
denemeye gönderiyor ve hem 13 gün hem 2,20 adam-gün kazanıyor.

Buradan çıkan kural, sınıflandırmanın kendisinden daha dar ve daha kullanışlıdır: **sınıf eşiği
yöntemden türetilir, seçilmez.** İki karar yönteminin bekleme süresi ve yanlışlık oranı yazıldığı
anda eşik hesaplanabilir hale gelir. Kapasite gibi başka bir yerden gelen sayı eşik olarak
kullanıldığında sınıflandırma yine bir şey kazandırır, ama kazandırabileceğinin altında kalır.

#### Özet

- Bir kararın geri alma maliyeti histen değil bağımlılık kümesinden okunur: dolaşılan bileşen
  sayısı, yazılmış kayıtların göçü ve dışa açılmış arayüzün eşgüdümü.
- Sekiz kararlık kümede toplam geri alma maliyetinin yüzde 88,8'i dört geri döndürülemez kararda
  toplandı; dolaşılan bileşen sayısı tek başına sınıfı belirlemiyor.
- Aynı iki yöntem iki sınıfta ters sonuç verdi: geri döndürülebilir sınıfta hızlı deneme 17,80,
  geri döndürülemez sınıfta uzun değerlendirme 2,95 adam-gün daha ucuz.
- Dört politika aynı küme üzerinde koşturulunca `hepsine-uzun` hem en pahalı hem en yavaş çıktı
  (58,70 adam-gün, 120 gün); sınıfa göre ayıran politika 40,90 adam-gün ve 68 güne indi.
- Sınıf eşiği 10, yöntem kırılma noktası 20,8 idi; eşiği kırılma noktasından türeten politika
  38,70 adam-gün ve 55 gün ile dördünün en iyisi oldu.
- Eşik seçilmez, iki yöntemin bekleme süresi ve yanlışlık oranından hesaplanır.

#### Sonraki Adım

Buraya kadar ölçülen her şey mimarın masasında bitiyor: ağırlık, karmaşıklık payı, geri alma
maliyeti, eşik. Sekiz kararın hiçbiri o masada uygulanmıyor. `odunc-kaydi-bicimi` kararının geri
alma maliyeti 35 adam-gün olarak hesaplandı, ama bu sayının anlamı bütçeyi tutan birimde
farklıdır, kayıt göçünü yapacak ekipte farklıdır, şubede iş yapan görevlide bambaşkadır. Hesap
aynı kalır, karşı tarafın onu okuma biçimi değişir. Sonraki ders teknik olmayan muhataplarla
kurulan iletişimi bir veri yapısına çevirir: aynı karar iki ayrı anlatımla aynı paydaşlara
sunulduğunda sorulan soru ve onay için gereken tur sayılır.

### Paydaş Yönetimi

Source: https://academia.sh/tr/kurslar/mimarin-rolu/paydas-yonetimi

Teknik olmayan muhatapla iletişimin bir paydaş modelinde ölçülmesi: aynı kararın teknik terimli anlatımı 27 soru ve 8 tur, sonuç odaklı anlatımı 0 soru ve 3 tur üretirken altı kısıttan dördünü eleyip dört sürprize dönüştürüyor, kısıtları düz dille geri koyan üçüncü anlatım dört ifade karşılığında toplam turu 3'e indiriyor.

Önceki ders kararı bir nesneye çevirdi ve geri döndürülebilirliğine göre sınıflandırdı: hangi
kararın hangi yöntemle verileceği belli oldu. Bir şey belli olmadı. Kararı onaylayacak olan,
kararı veren değil. Bölgesel kütüphane ağının modelinde ödünç servisinin veri akışını
değiştirmek bütçeye dokunur, şube personelinin işini değiştirir ve dışarıdan alınmış katalog
sisteminin sözleşmesini ilgilendirir. Bu üç kapıyı da teknik olmayan biri tutar.

Bu ders "mimar iletişim kurmalıdır" demez. İletişimi bir veri yapısına çevirir: paydaş bir
**sözlük** ile bir **ilgi** kümesidir, anlatım bir ifade dizisidir. Aynı karar iki ayrı anlatımla
aynı modelde koşturulur ve iki sayı sayılır: karar başına yanıtlanan soru ve onay için gereken
tur. Üçüncü bir sayı da sayılır, çünkü sonuç odaklı anlatımın ucuz görünmesinin bir nedeni
vardır: anlatımın **elediği kısıt sayısı**.

#### Paydaş Bir Sözlük ve Bir İlgi Kümesidir

**Paydaş** (stakeholder), kararın sonucunu üstlenen ama kararı vermeyen taraftır. Modelde üç
paydaş vardır ve hiçbiri gerçek bir kurumdan alınmamıştır: bütçe sorumlusu, hizmet sorumlusu,
satın alma sorumlusu. Her birinin bildiği terimler kümesi ve onay için karşılanması gereken
konuları vardır.

**MP10: bir paydaş, ilgi kümesindeki her konu karşılandığında ve açık sorusu kalmadığında onay
verir.** İki koşuldan biri eksikse onay gelmez; toplantı bir tur daha sürer.

**MP11: bilinmeyen terim içeren bir ifade o turda anlaşılmaz.** Konusunu karşılamaz, kısıtını
taşımaz; yerine terim başına bir soru üretir. Sorunun yanıtı terimi kalıcı olarak sözlüğe ekler,
yani aynı terim ikinci kez sorulmaz.

**MP12: taşınmayan her kısıt, o kısıttan etkilenen paydaşta sonradan bir sürpriz üretir** ve
sürpriz bir tur daha maliyet yazar. Kısıt taşınmışsa olay gerçekleştiğinde kimse şaşırmaz.

```js
// paydas/model.mjs — teknik olmayan muhatapla iletisim modeli. Gercek kurum ve kisi yoktur;
// paydas bir sozluk ile bir ilgi kumesidir, anlatim bir ifade dizisidir. Sure olculmez;
// yanitlanan soru, tur ve tasinan kisit sayilir.

// Kararin tasidigi kisitlar. Bir anlatim bunlarin hepsini tasimak zorunda degildir; tasimadigi
// her kisit sonradan bir surpriz adayidir.
export const KISITLAR = {
  K1: "gece raporu on bes dakika gec uretilir",
  K2: "sube personeli bir kez egitim alir",
  K3: "eski kayitlar iki hafta cift yazilir",
  K4: "karar bir hafta icinde geri alinabilir",
  K5: "dis katalog saglayicisiyla sozlesme degismez",
  K6: "tepe saatte birikme olursa teslim gecikir",
};

// Kurum dilinde herkesin bildigi terimler. Teknik terimler bu kumede yoktur.
const ORTAK = ["sube", "personel", "sure", "maliyet", "risk", "rapor", "okuyucu",
  "hizmet kesintisi", "egitim", "sozlesme", "saglayici"];

export const PAYDASLAR = [
  { ad: "butce sorumlusu", ilgi: ["maliyet", "geri donus"], sozluk: [...ORTAK, "butce"] },
  { ad: "hizmet sorumlusu", ilgi: ["hizmet kesintisi", "egitim"], sozluk: [...ORTAK, "raf"] },
  { ad: "satin alma sorumlusu", ilgi: ["sozlesme", "maliyet"], sozluk: [...ORTAK, "ihale"] },
];

// Mimarin, karsilanmayan bir ilgi kaldiginda ekledigi ifade. Duz dille yazilir.
export const EK_IFADE = {
  "maliyet": { terimler: ["maliyet", "personel"], ilgi: ["maliyet"], kisit: [] },
  "geri donus": { terimler: ["sure", "risk"], ilgi: ["geri donus"], kisit: ["K4"] },
  "hizmet kesintisi": { terimler: ["hizmet kesintisi"], ilgi: ["hizmet kesintisi"], kisit: [] },
  "egitim": { terimler: ["personel", "sube"], ilgi: ["egitim"], kisit: ["K2"] },
  "sozlesme": { terimler: ["sozlesme", "saglayici"], ilgi: ["sozlesme"], kisit: ["K5"] },
};

// MP10 + MP11: tek paydas, tek anlatim. Bilinmeyen terim soruya donusur; yanit sozluge eklenir.
export function toplanti(paydas, anlatim, enCokTur = 12) {
  const sozluk = new Set(paydas.sozluk);
  const karsilanan = new Set(), tasinan = new Set(), ek = [];
  let soru = 0, tur = 0;
  while (tur < enCokTur) {
    tur += 1;
    let turSorusu = 0;
    for (const f of [...anlatim, ...ek]) {
      const bilinmeyen = f.terimler.filter((t) => !sozluk.has(t));
      if (bilinmeyen.length > 0) {
        turSorusu += bilinmeyen.length;
        for (const t of bilinmeyen) sozluk.add(t);
        continue;
      }
      for (const i of f.ilgi) karsilanan.add(i);
      for (const k of f.kisit) tasinan.add(k);
    }
    soru += turSorusu;
    const eksik = paydas.ilgi.filter((i) => !karsilanan.has(i));
    if (turSorusu === 0 && eksik.length === 0) return { tur, soru, tasinan, ek: ek.length };
    if (turSorusu === 0) ek.push(EK_IFADE[eksik[0]]);
  }
  return { tur, soru, tasinan, ek: ek.length, onaysiz: true };
}

// MP12: kisiti bilmeyen paydasin sonradan sasiracagi olaylar: kisit -> etkilenen paydas.
export const OLAYLAR = {
  K1: "butce sorumlusu", K2: "hizmet sorumlusu", K3: "butce sorumlusu",
  K4: "butce sorumlusu", K5: "satin alma sorumlusu", K6: "hizmet sorumlusu",
};

// Bir anlatimin uc paydas uzerindeki toplami. Paydaslar ayri ayri bilgilendirilir.
export function anlatimiKostur(anlatim, ekSozluk = []) {
  const tasinanPaydas = new Map();
  let soru = 0, tur = 0, ek = 0;
  for (const p of PAYDASLAR) {
    const r = toplanti({ ...p, sozluk: [...p.sozluk, ...ekSozluk] }, anlatim);
    soru += r.soru; tur += r.tur; ek += r.ek;
    tasinanPaydas.set(p.ad, r.tasinan);
  }
  const surpriz = Object.entries(OLAYLAR)
    .filter(([k, ad]) => !tasinanPaydas.get(ad).has(k)).map(([k]) => k);
  const birlesik = new Set([...tasinanPaydas.values()].flatMap((s) => [...s]));
  const atlanan = Object.keys(KISITLAR).filter((k) => !birlesik.has(k));
  return { ifade: anlatim.length, soru, tur, ek, atlanan, surpriz, toplamTur: tur + surpriz.length };
}
```

#### Aynı Kararın Üç Anlatımı

Karar tektir: ödünç kayıtlarının gece toplu aktarımdan sürekli akışa çevrilmesi. Anlatım A
kararın teknik gerekçesini olduğu gibi aktarır ve altı kısıtın hepsini taşır. Anlatım B aynı
kararı sonuç diliyle anlatır. Anlatım C, B'nin dilini korur ve B'nin elediği kısıtları düz
cümlelerle geri koyar.

```js
// paydas/anlatim.mjs — ayni kararin uc anlatimi ayni paydas modelinde kosturulur
import { KISITLAR, PAYDASLAR, anlatimiKostur, toplanti } from "./model.mjs";

// A: teknik terimli anlatim. Alti kisitin hepsini tasir, maliyeti hic anmaz.
const A = [
  { terimler: ["olay akisi", "kuyruk", "geri baski"], ilgi: ["hizmet kesintisi"], kisit: ["K6"] },
  { terimler: ["cift yazim", "gecis penceresi", "rapor"], ilgi: [], kisit: ["K1", "K3"] },
  { terimler: ["surum sabitleme", "risk", "sure"], ilgi: ["geri donus"], kisit: ["K4"] },
  { terimler: ["uc nokta", "sema", "sozlesme", "saglayici"], ilgi: ["sozlesme"], kisit: ["K5"] },
  { terimler: ["istemci arayuzu", "personel", "sube"], ilgi: ["egitim"], kisit: ["K2"] },
];

// B: sonuc odakli anlatim. Her ilgiyi karsilar, terimleri kurum dilindedir, kisitlari eler.
const B = [
  { terimler: ["okuyucu", "sure", "hizmet kesintisi"], ilgi: ["hizmet kesintisi"], kisit: ["K6"] },
  { terimler: ["maliyet", "personel"], ilgi: ["maliyet"], kisit: [] },
  { terimler: ["sure", "risk"], ilgi: ["geri donus"], kisit: ["K4"] },
  { terimler: ["sube", "personel", "egitim"], ilgi: ["egitim"], kisit: [] },
  { terimler: ["sozlesme", "saglayici"], ilgi: ["sozlesme"], kisit: [] },
];

// C: sonuc odakli anlatim + elenen kisitlarin duz dille geri konmasi.
const C = [...B,
  { terimler: ["rapor", "sure"], ilgi: [], kisit: ["K1"] },
  { terimler: ["sube", "personel", "egitim"], ilgi: [], kisit: ["K2"] },
  { terimler: ["sure", "risk", "maliyet"], ilgi: [], kisit: ["K3"] },
  { terimler: ["sozlesme", "saglayici"], ilgi: [], kisit: ["K5"] },
];

console.log(`paydas ${PAYDASLAR.length}, kisit ${Object.keys(KISITLAR).length}, karar 1\n`);
console.log("anlatim  ifade  yanitlanan soru  onay turu  ek ifade  tasinan kisit  surpriz  toplam tur");
console.log("------- ------ ---------------- ---------- --------- -------------- -------- -----------");
const sonuc = {};
for (const [ad, anlatim] of [["A", A], ["B", B], ["C", C]]) {
  const r = sonuc[ad] = anlatimiKostur(anlatim);
  console.log(`${ad.padStart(7)} ${String(r.ifade).padStart(6)} ${String(r.soru).padStart(16)} ` +
    `${String(r.tur).padStart(10)} ${String(r.ek).padStart(9)} ` +
    `${`${6 - r.atlanan.length}/6`.padStart(14)} ${String(r.surpriz.length).padStart(8)} ` +
    `${String(r.toplamTur).padStart(11)}`);
}
console.log(`\nB'nin atladigi kisit: ${sonuc.B.atlanan.join(", ")}`);
console.log(`B'de surprize donusen kisit: ${sonuc.B.surpriz.join(", ")}`);
console.log(`A'nin atladigi kisit: ${sonuc.A.atlanan.length === 0 ? "yok" : sonuc.A.atlanan.join(", ")}`);
console.log(`C'nin atladigi kisit: ${sonuc.C.atlanan.length === 0 ? "yok" : sonuc.C.atlanan.join(", ")}`);

console.log(`\npaydas basina (anlatim A):`);
console.log("paydas                soru  tur  ek ifade");
for (const p of PAYDASLAR) {
  const r = toplanti(p, A);
  console.log(`${p.ad.padEnd(20)} ${String(r.soru).padStart(5)} ${String(r.tur).padStart(4)} ` +
    `${String(r.ek).padStart(9)}`);
}

console.log(`\nA'nin bedeli dinleyene baglidir (paydas sozlugune teknik terim eklenir):`);
console.log("eklenen terim  yanitlanan soru  onay turu");
const teknik = ["olay akisi", "kuyruk", "geri baski", "cift yazim", "gecis penceresi",
  "surum sabitleme", "uc nokta", "sema", "istemci arayuzu"];
for (const n of [0, 3, 6, 9]) {
  const r = anlatimiKostur(A, teknik.slice(0, n));
  console.log(`${String(n).padStart(13)} ${String(r.soru).padStart(16)} ${String(r.tur).padStart(10)}`);
}
```

```
paydas 3, kisit 6, karar 1

anlatim  ifade  yanitlanan soru  onay turu  ek ifade  tasinan kisit  surpriz  toplam tur
------- ------ ---------------- ---------- --------- -------------- -------- -----------
      A      5               27          8         2            6/6        0           8
      B      5                0          3         0            2/6        4           7
      C      9                0          3         0            6/6        0           3

B'nin atladigi kisit: K1, K2, K3, K5
B'de surprize donusen kisit: K1, K2, K3, K5
A'nin atladigi kisit: yok
C'nin atladigi kisit: yok

paydas basina (anlatim A):
paydas                soru  tur  ek ifade
butce sorumlusu          9    3         1
hizmet sorumlusu         9    2         0
satin alma sorumlusu     9    3         1

A'nin bedeli dinleyene baglidir (paydas sozlugune teknik terim eklenir):
eklenen terim  yanitlanan soru  onay turu
            0               27          8
            3               18          8
            6                9          8
            9                0          5
```

Bütün sayılar **hesap** sınıfındadır: belirlenimli bir model üzerinde sayılmışlardır.

#### Sadeleştirmenin Bedeli

Teknik anlatım tek bir karar için **27 soru** ürettiriyor ve üç paydaşın onayı **8 turda**
geliyor. Sonuç odaklı anlatım aynı kararı **0 soru** ve **3 turda** onaylatıyor. Bu tabloda
durulsaydı sonuç açık olurdu: sonuç dili turu üçte birine indiriyor.

Kısıt sütunu bu sonucu bozuyor. Anlatım B altı kısıttan **ikisini** taşıyor; K1, K2, K3 ve K5
anlatımın dışında kalıyor. Bunlar süs değil: gece raporunun on beş dakika geç üretilmesi,
personelin bir kez eğitim alması, eski kayıtların iki hafta çift yazılması ve sözleşmenin
değişmemesi. Dördü de kararın gerçek sonuçlarıdır ve dördü de zamanı gelince kendini gösterir.
Modelde bu, **4 sürpriz** olarak sayılıyor ve her sürpriz bir tur daha yazıyor: B'nin toplamı 3
değil **7**.

Buradaki asıl sayı, sonuç odaklı anlatımın toplam kazancının 8 turdan 7 tura, yani **tek bir
tur** olmasıdır. Sadeleştirme, konuşmanın maliyetini önden düşürüp arkadan geri yüklüyor.
Anlatım B yanlış bir anlatım değil; **eksik** bir anlatım ve eksikliği ölçülebiliyor.

Anlatım C bunun düzeltilebilir olduğunu gösteriyor. B'nin dilini hiç bozmadan, elenen dört
kısıtı yine kurum diliyle yazılmış dört cümleye koyuyor. Bedeli 5 ifade yerine **9 ifade**, yani
dört cümle daha yazmak. Kazancı: 0 soru, 0 sürpriz, toplam **3 tur**. Aynı karar A'ya göre
turların yaklaşık üçte birinde, B'ye göre yarısından azında onaylanıyor. Kısıt taşımanın bedeli
yazmakla ödeniyor, toplantıyla değil.

#### Terim Uyuşmazlığı ve İlgi Uyuşmazlığı

Son tablo, teknik anlatımın 27 sorusunun kararın bir özelliği olmadığını gösteriyor. Paydaşların
sözlüğüne dokuz teknik terim eklendikçe soru sayısı 27'den 18'e, 9'a ve 0'a iniyor. Aynı karar,
aynı cümlelerle, teknik terimleri bilen bir muhataba anlatıldığında hiç soru üretmiyor. Anlatımın
bedeli **dinleyenin sözlüğüne** bağlıdır.

Aynı tablonun ikinci sütunu bunun sınırını çiziyor. Soru sayısı sıfıra inerken onay turu 8'den
yalnız **5**'e iniyor, 3'e değil. Sebep anlatım A'nın hiçbir ifadesinde maliyetten söz
edilmemesi: bütçe sorumlusu ile satın alma sorumlusunun ilgi kümesinde maliyet var ve terim
öğretmek bu boşluğu kapatmıyor. Model bunu **2 ek ifade** olarak yazıyor — mimarın toplantıda
sonradan söylemek zorunda kaldığı iki cümle.

Bu iki başarısızlık ayrı ayrı ele alınır. **Terim uyuşmazlığı** çeviriyle çözülür: aynı içerik,
muhatabın sözlüğündeki sözcüklerle. **İlgi uyuşmazlığı** çeviriyle çözülmez; anlatıma o konuyu
karşılayan yeni bir ifade eklemek gerekir. Bir anlatımın kusursuz sadeleştirilmiş olması,
paydaşın sorusunu yanıtladığı anlamına gelmez.

Bunun bir sonucu da şudur: paydaş başına soru sayıları eşit (9, 9, 9) ama tur sayıları eşit değil
(3, 2, 3). Hizmet sorumlusu iki turda onay veriyor, çünkü ilgi kümesinin ikisi de anlatımın
içinde. Fark terimlerden değil, **kimin neyi sorduğundan** geliyor.

#### Özet

- Paydaş bir sözlük ve bir ilgi kümesi olarak modellenir; onay, açık soru kalmadığında ve her
  ilgi karşılandığında gelir (MP10, MP11). Bu model üç paydaş, altı kısıt ve tek bir karar
  üzerinde koşturuldu.
- Teknik terimli anlatım karar başına 27 soru ve 8 tur; sonuç odaklı anlatım 0 soru ve 3 tur
  üretti. Tek başına bu karşılaştırma sonuç dilini üçte bir maliyetle gösteriyor.
- Sonuç odaklı anlatım altı kısıttan dördünü eledi (K1, K2, K3, K5) ve dördü de sürprize dönüştü;
  toplam turu 3 değil 7 oldu. Gerçek kazanç 8 tura karşı 7 tur, yani tek bir turdur.
- Kısıtları düz dille geri koyan anlatım dört ifade daha yazma karşılığında 0 soru, 0 sürpriz ve
  **3 tur** verdi: sadeleştirmenin kaybı, dil bozulmadan geri alınabilir.
- Teknik anlatımın 27 sorusu dinleyenin sözlüğüne bağlıdır ve dokuz terim öğretildiğinde 0'a
  iner; ama tur sayısı 8'den yalnız 5'e iner. Terim uyuşmazlığı çeviriyle, ilgi uyuşmazlığı yeni
  ifadeyle çözülür.

#### Sonraki Adım

Bu ders kararın anlatımını ölçtü; kararın **içeriğini** sabit tuttu. Onaylanan karar bir akış
değişikliğiydi ve arkasında bir seçim vardı: o akışı hangi araç taşıyacak. Modelde bu seçim
henüz yapılmadı. Sıradaki ders adayları önüne koyar ve şu soruyu sorar: bir aracın olgunluğu
ve çevresindeki ekosistem nasıl bir sayıya çevrilir ve seçim yanlış çıkarsa o araçtan çıkmanın
maliyeti kaç modüle, kaç kayda ve kaç satıra karşılık gelir?

### Teknoloji Değerlendirme

Source: https://academia.sh/tr/kurslar/mimarin-rolu/teknoloji-degerlendirme

Aday araçların olgunluk, ekosistem ve çıkış maliyeti ölçütleriyle ağırlıklandırılması: on iki modüllük bir kaynak ağacı diske yazılıp taranarak çıkış maliyetinin 53,0 ile 60,5 saat arasında ölçülmesi, yerleşik yeteneğin toplam satırı 127'den 73'e indirirken çıkışı büyütmesi, kazananın ağırlık kümesine göre değişmesi ve sarmalayıcının kod payını 33,5 saatten 4,0 saate indirirken veri payını hiç azaltmaması.

Önceki ders bir kararın nasıl anlatılacağını ölçtü ve kararın içeriğini sabit tuttu: ödünç
kayıtları sürekli bir akışa taşınacaktı. O akışı hangi aracın taşıyacağı seçilmedi. Bölgesel
kütüphane ağının modelinde bu seçim bir kez yapılır ve uzun süre yaşar; ödünç servisleri
içeride yazılmıştır ama akışı taşıyan araç dışarıdan gelir.

Bu ders adayları ürün adıyla anmaz. Bir ürün adı yazmak bu dersi beş yılda eskitirdi; onun
yerine adaylar **betimleyici özelliklerle** modellenir — A, B ve C, her biri bir olgunluk
profili, bir ekosistem profili ve bir yerleşik yetenek kümesidir. Ölçülecek üç şey vardır:
**olgunluk** (maturity), ekosistem ve **çıkış maliyeti** (exit cost). Üçüncüsü ötekilerden
ayrılır, çünkü tek başına gerçek kod üzerinden okunabilir.

#### Çıkış Maliyeti Kaynak Ağacından Okunur

Olgunluk ve ekosistem, adayın kendisine ait niteliklerdir ve dışarıdan verilir. Çıkış maliyeti
öyle değildir: adayın değil, **adayın kendi kodumuza nasıl girdiğinin** özelliğidir. Bu yüzden
ölçülebilir.

Aşağıdaki modül kümesi gerçekten diske yazılır ve sonra taranır. Sayılar dosyalardan okunur.
Ödünç servisinin modelinde on iki modül vardır ve her biri yedi yetenekten bir alt kümeye
ihtiyaç duyar. Bir aday, ihtiyaç duyulan yeteneği **yerleşik** olarak sağlıyorsa modül o adaya
bağlanır; sağlamıyorsa modül o yeteneği **elde yazar** ve adaya bağlanmaz.

**MP13: çıkış maliyeti = bağ satırı × 0,5 saat + bağlı modül × 2 saat + taşınacak kayıt /
50.000.** Üç terim ayrı işleri sayar: çağrının yeniden yazılması, modülün yeniden sınanması ve
verinin taşınması. Taşınacak kayıt modelde 1.200.000'dir ve hangi aday seçilirse seçilsin aynıdır.

**MP14: adayların yaş, kırıcı sürüm sıklığı, açık kusurun kapanma süresi, uyarlayıcı sayısı,
belgelenmiş işlev oranı ve bağımsız gerçekleştirim sayısı değerleri model değerleridir**; hiçbir
gerçek araçtan alınmamıştır ve ölçütlerin nasıl ağırlıklandırıldığını göstermek için vardır.

```js
// degerlendirme/kod.mjs — aday secimini kod uzerinde olcen model. Uc aday gercek bir urun
// degil, betimleyici ozellik kumesidir. Modul kumesi diske gercekten yazilir ve cikis
// maliyeti yazilan dosyalar taranarak olculur; sayilar dosyalardan okunur, elle yazilmaz.
import { mkdirSync, writeFileSync, readFileSync, rmSync } from "node:fs";

export const YETENEKLER = ["yayin", "dinleme", "obek", "islem", "gecikmeli", "oynatma", "olu"];

// Odunc servisinin modelindeki on iki modul ve her birinin ihtiyac duydugu yetenekler.
export const MODULLER = {
  "api": ["yayin", "dinleme"],
  "uzatma": ["yayin"],
  "gecikme": ["yayin", "gecikmeli"],
  "rezervasyon": ["yayin", "dinleme", "islem"],
  "bildirim": ["dinleme", "gecikmeli", "olu"],
  "rapor": ["dinleme", "obek"],
  "sube-devri": ["yayin", "islem"],
  "ceza": ["yayin", "olu"],
  "uyelik": ["dinleme"],
  "katalog-koprusu": ["yayin", "dinleme", "oynatma"],
  "gunluk": ["obek", "oynatma"],
  "olcum": ["dinleme", "obek"],
};

// MP14: adaylar yalnizca ozellikleriyle taninir. "destek" adayin yerlesik olarak sagladigi
// yeteneklerdir; saglamadigi her yetenek modulde elde yazilir.
export const ADAYLAR = {
  A: { destek: ["yayin", "dinleme"], yas: 11, kiriciSurum: 0.4, kusurGun: 21,
       uyarlayici: 9, belgeliIslev: 0.95, bagimsizGerceklestirim: 3 },
  B: { destek: ["yayin", "dinleme", "obek", "olu"], yas: 6, kiriciSurum: 1.1, kusurGun: 9,
       uyarlayici: 38, belgeliIslev: 0.92, bagimsizGerceklestirim: 1 },
  C: { destek: YETENEKLER, yas: 2, kiriciSurum: 3.0, kusurGun: 4,
       uyarlayici: 41, belgeliIslev: 0.55, bagimsizGerceklestirim: 1 },
};

// Bir modulu gercek bir kaynak dosya olarak uretir.
function modulMetni(ad, ihtiyac, destek, istemciYolu, sarmalYolu = null) {
  const yerlesik = ihtiyac.filter((y) => destek.includes(y));
  const elde = ihtiyac.filter((y) => !destek.includes(y));
  const s = [];
  if (yerlesik.length > 0) s.push(`import { istemci } from "${sarmalYolu ?? istemciYolu}";`);
  for (const y of elde) {
    s.push(`function elde_${y}(kayit) {`);
    s.push(`  const kuyruk = [];`);
    s.push(`  for (const k of kayit) kuyruk.push({ ad: "${y}", k });`);
    s.push(`  return kuyruk;`);
    s.push(`}`);
  }
  s.push(`export async function ${ad.replace(/-/g, "_")}(kayit) {`);
  for (const y of yerlesik) s.push(`  await istemci.${y}(kayit);`);
  for (const y of elde) s.push(`  elde_${y}(kayit);`);
  s.push(`  return kayit.length;`);
  s.push(`}`);
  return s.join("\n") + "\n";
}

// Sarmalayici: yalnizca kendisine verilen yetenek kumesini disa acar. Her yetenek icin
// cagri aktarimi ve hata cevirisi yazilir.
function sarmalMetni(kapsam) {
  const s = [`import { istemci as ham } from "../aday/istemci.mjs";`, `export const istemci = {`];
  for (const y of kapsam) {
    s.push(`  ${y}: async (kayit) => {`);
    s.push(`    try { return await ham.${y}(kayit); }`);
    s.push(`    catch (e) { throw new Error("ileti araci hatasi: " + e.message); }`);
    s.push(`  },`);
  }
  s.push(`};`);
  return s.join("\n") + "\n";
}

// Uretilen dosyalar taranir: adayin istemcisine baglanan modul ve cagri satiri sayilir.
function tara(kok, modulAdlari, ekDosya = []) {
  let bagliModul = 0, bagSatiri = 0, toplamSatir = 0, eldeIslev = 0;
  const dosyalar = [...modulAdlari.map((a) => `${kok}/${a}.mjs`), ...ekDosya];
  for (const yol of dosyalar) {
    const satirlar = readFileSync(yol, "utf8").trimEnd().split("\n");
    toplamSatir += satirlar.length;
    const ham = satirlar.some((s) => /from "\.\.\/aday\/istemci\.mjs"/.test(s));
    if (ham) bagliModul += 1;
    if (ham) bagSatiri += satirlar.filter((s) => /(istemci|ham)\.\w+\(/.test(s)).length;
    eldeIslev += satirlar.filter((s) => /^function elde_/.test(s)).length;
  }
  return { bagliModul, bagSatiri, toplamSatir, eldeIslev };
}

// Bir adayin dogrudan kullanimini uretir ve olcer.
export function dogrudan(kok, aday) {
  rmSync(kok, { recursive: true, force: true });
  mkdirSync(`${kok}/aday`, { recursive: true });
  mkdirSync(`${kok}/odunc`, { recursive: true });
  writeFileSync(`${kok}/aday/istemci.mjs`, `export const istemci = {};\n`);
  for (const [ad, ihtiyac] of Object.entries(MODULLER))
    writeFileSync(`${kok}/odunc/${ad}.mjs`, modulMetni(ad, ihtiyac, aday.destek, "../aday/istemci.mjs"));
  return tara(`${kok}/odunc`, Object.keys(MODULLER));
}

// Ayni adayin sarmalayici arkasindan kullanimi. Sarmalayicinin kapsamadigi yetenege ihtiyaci
// olan modul, istemciye dogrudan baglanmak zorundadir: sizinti budur.
export function sarmalli(kok, aday, kapsam) {
  rmSync(kok, { recursive: true, force: true });
  mkdirSync(`${kok}/aday`, { recursive: true });
  mkdirSync(`${kok}/ortak`, { recursive: true });
  mkdirSync(`${kok}/odunc`, { recursive: true });
  writeFileSync(`${kok}/aday/istemci.mjs`, `export const istemci = {};\n`);
  writeFileSync(`${kok}/ortak/sarmal.mjs`, sarmalMetni(kapsam));
  let sizan = 0;
  for (const [ad, ihtiyac] of Object.entries(MODULLER)) {
    const yerlesik = ihtiyac.filter((y) => aday.destek.includes(y));
    const disarida = yerlesik.filter((y) => !kapsam.includes(y));
    if (disarida.length > 0) sizan += 1;
    const yol = disarida.length > 0 ? "../aday/istemci.mjs" : "../ortak/sarmal.mjs";
    writeFileSync(`${kok}/odunc/${ad}.mjs`,
      modulMetni(ad, ihtiyac, aday.destek, "../aday/istemci.mjs", yol));
  }
  const sarmalSatiri = readFileSync(`${kok}/ortak/sarmal.mjs`, "utf8").trimEnd().split("\n").length;
  return { ...tara(`${kok}/odunc`, Object.keys(MODULLER), [`${kok}/ortak/sarmal.mjs`]),
    sizan, sarmalSatiri };
}

// MP13: cikis maliyeti = baglayan cagri satiri x 0,5 saat + bagli modul x 2 saat sinama
// + tasinacak kayit / 50.000 saat. Veri payi adaydan bagimsizdir.
export const TASINACAK_KAYIT = 1_200_000;
export const cikisMaliyeti = (o) =>
  o.bagSatiri * 0.5 + o.bagliModul * 2 + TASINACAK_KAYIT / 50_000;
```

#### Ağırlık Kazananı Belirler

Ölçütler farklı birimlerdedir: yıl, gün, adet, oran, saat. Toplanabilmeleri için hepsi sıfır ile
bir arasına çekilir ve yüksek değer her zaman iyiyi gösterir. Bundan sonrası bir ağırlık
kararıdır ve ağırlık teknik bir sayı değil, bir tercih beyanıdır.

```js
// degerlendirme/secim.mjs — olgunluk, ekosistem ve cikis maliyeti agirliklandirilir
import { ADAYLAR, MODULLER, YETENEKLER, dogrudan, sarmalli, cikisMaliyeti, TASINACAK_KAYIT }
  from "./kod.mjs";

const KOK = "./uretilen";
const olcum = {};
for (const [ad, aday] of Object.entries(ADAYLAR)) olcum[ad] = dogrudan(`${KOK}/${ad}`, aday);

console.log(`modul ${Object.keys(MODULLER).length}, yetenek ${YETENEKLER.length}, tasinacak kayit ${TASINACAK_KAYIT}\n`);
console.log("aday  destek  bagli modul  bag satiri  elde yazilan islev  toplam satir  cikis (saat)");
console.log("---- ------- ------------ ----------- ------------------- ------------- -------------");
for (const [ad, aday] of Object.entries(ADAYLAR)) {
  const o = olcum[ad];
  console.log(`${ad.padStart(4)} ${`${aday.destek.length}/7`.padStart(7)} ${String(o.bagliModul).padStart(12)} ` +
    `${String(o.bagSatiri).padStart(11)} ${String(o.eldeIslev).padStart(19)} ` +
    `${String(o.toplamSatir).padStart(13)} ${cikisMaliyeti(o).toFixed(1).padStart(13)}`);
}

// Butun olcutler 0-1 araligina cekilir; yuksek her zaman iyidir.
const olcut = {
  yas: (a) => Math.min(1, a.yas / 10),
  kiriciSurum: (a) => 1 / (1 + a.kiriciSurum),
  kusurGun: (a) => 1 / (1 + a.kusurGun / 10),
  bagimsizGerceklestirim: (a) => Math.min(1, a.bagimsizGerceklestirim / 3),
  uyarlayici: (a) => Math.min(1, a.uyarlayici / 40),
  belgeliIslev: (a) => a.belgeliIslev,
  kapsam: (a) => a.destek.length / YETENEKLER.length,
  cikis: (a, ad) => 1 / (1 + cikisMaliyeti(olcum[ad]) / 50),
  azSatir: (a, ad) => 1 / (1 + olcum[ad].toplamSatir / 100),
};

const bir = Object.fromEntries(Object.keys(olcut).map((k) => [k, 1]));
const AGIRLIK = {
  "olgunluk agirlikli": { ...bir, yas: 3, kiriciSurum: 3, kusurGun: 3, bagimsizGerceklestirim: 3 },
  "ekosistem agirlikli": { ...bir, uyarlayici: 3, belgeliIslev: 3, kapsam: 3 },
  "cikis agirlikli": { ...bir, cikis: 6 },
  "gelistirme agirlikli": { ...bir, kapsam: 3, azSatir: 4 },
  "esit": { ...bir },
};

const puanla = (ad, w) => {
  let t = 0, top = 0;
  for (const [k, f] of Object.entries(olcut)) { t += w[k] * f(ADAYLAR[ad], ad); top += w[k]; }
  return t / top;
};

console.log(`\nagirlik kumesi          A       B       C   kazanan   fark`);
console.log(`--------------------- ------- ------- ------- ------- ------`);
for (const [ad, w] of Object.entries(AGIRLIK)) {
  const p = Object.fromEntries(Object.keys(ADAYLAR).map((k) => [k, puanla(k, w)]));
  const s = Object.entries(p).sort((x, y) => y[1] - x[1]);
  console.log(`${ad.padEnd(21)} ${p.A.toFixed(4).padStart(7)} ${p.B.toFixed(4).padStart(7)} ` +
    `${p.C.toFixed(4).padStart(7)} ${s[0][0].padStart(7)} ${(s[0][1] - s[1][1]).toFixed(4).padStart(6)}`);
}

// Sarmalayici, adaylarin ortak kesisimini kapsayabilir; kesisim disi her yetenek sizintidir.
const kesisim = YETENEKLER.filter((y) => Object.values(ADAYLAR).every((a) => a.destek.includes(y)));
console.log(`\nadaylarin ortak yetenek kesisimi: ${kesisim.join(", ")} (${kesisim.length}/7)`);
console.log(`\naday B secilirse sarmalayici kapsami:`);
console.log("kapsam                  sarmal satiri  sizan modul  bagli modul  bag satiri  cikis (saat)  dusus");
console.log("---------------------- -------------- ------------ ------------ ----------- ------------- ------");
const ham = cikisMaliyeti(olcum.B);
for (const kapsam of [kesisim, ["yayin", "dinleme", "obek"], ADAYLAR.B.destek]) {
  const o = sarmalli(`${KOK}/sarmal`, ADAYLAR.B, kapsam);
  const m = cikisMaliyeti(o);
  console.log(`${kapsam.join(",").padEnd(22)} ${String(o.sarmalSatiri).padStart(14)} ` +
    `${String(o.sizan).padStart(12)} ${String(o.bagliModul).padStart(12)} ${String(o.bagSatiri).padStart(11)} ` +
    `${m.toFixed(1).padStart(13)} ${`${((1 - m / ham) * 100).toFixed(1)}%`.padStart(6)}`);
}
const tam = sarmalli(`${KOK}/sarmal`, ADAYLAR.B, ADAYLAR.B.destek);
const veri = TASINACAK_KAYIT / 50_000;
const kazanc = ham - cikisMaliyeti(tam);
console.log(`\nB'de cikis: sarmalayicisiz ${ham.toFixed(1)} saat, tam kapsamli sarmalayiciyla ${cikisMaliyeti(tam).toFixed(1)} saat`);
console.log(`kod payi ${(ham - veri).toFixed(1)} -> ${(cikisMaliyeti(tam) - veri).toFixed(1)} saat; veri payi ${veri.toFixed(1)} saat iki durumda da ayni`);
console.log(`MP15: sarmalayicinin ${tam.sarmalSatiri} satiri yilda ${(tam.sarmalSatiri * 0.1).toFixed(1)} saat bakim ister`);
console.log(`basabas gecis olasiligi = yillik bakim / kazanc = ${(tam.sarmalSatiri * 0.1 / kazanc).toFixed(3)}`);
const eksik = YETENEKLER.filter((y) => !ADAYLAR.A.destek.includes(y));
console.log(`A secilseydi ${olcum.A.eldeIslev} elde yazilan islev gerekirdi; ayni islevler bir sarmalayicinin ardinda ${eksik.length} kez yazilirdi`);
```

```
modul 12, yetenek 7, tasinacak kayit 1200000

aday  destek  bagli modul  bag satiri  elde yazilan islev  toplam satir  cikis (saat)
---- ------- ------------ ----------- ------------------- ------------- -------------
   A     2/7           11          14                  11           127          53.0
   B     4/7           12          19                   6           103          57.5
   C     7/7           12          25                   0            73          60.5

agirlik kumesi          A       B       C   kazanan   fark
--------------------- ------- ------- ------- ------- ------
olgunluk agirlikli     0.6763  0.5416  0.4749       A 0.1347
ekosistem agirlikli    0.5563  0.6812  0.6785       B 0.0026
cikis agirlikli        0.5608  0.5472  0.5243       A 0.0136
gelistirme agirlikli   0.5226  0.5683  0.6294       C 0.0612
esit                   0.6026  0.5928  0.5642       A 0.0098

adaylarin ortak yetenek kesisimi: yayin, dinleme (2/7)

aday B secilirse sarmalayici kapsami:
kapsam                  sarmal satiri  sizan modul  bagli modul  bag satiri  cikis (saat)  dusus
---------------------- -------------- ------------ ------------ ----------- ------------- ------
yayin,dinleme                      11            5            6          11          41.5  27.8%
yayin,dinleme,obek                 15            2            3           7          33.5  41.7%
yayin,dinleme,obek,olu             19            0            1           4          28.0  51.3%

B'de cikis: sarmalayicisiz 57.5 saat, tam kapsamli sarmalayiciyla 28.0 saat
kod payi 33.5 -> 4.0 saat; veri payi 24.0 saat iki durumda da ayni
MP15: sarmalayicinin 19 satiri yilda 1.9 saat bakim ister
basabas gecis olasiligi = yillik bakim / kazanc = 0.064
A secilseydi 11 elde yazilan islev gerekirdi; ayni islevler bir sarmalayicinin ardinda 5 kez yazilirdi
```

İlk tablonun bütün sayıları diske yazılmış dosyalardan okunmuştur; ikinci tablo bu sayıları
girdi alan bir hesaptır.

#### Yerleşik Yetenek Hem Tasarruf Hem Bağdır

İlk tablo tek bir eğilim gösteriyor ve iki yöne birden gidiyor. Yerleşik yetenek 2/7'den 7/7'ye
çıktıkça toplam satır **127'den 73'e** iniyor (yüzde 42 azalma) ve elde yazılan işlev **11'den
0'a** düşüyor. Aynı yönde çıkış maliyeti **53,0 saatten 60,5 saate** çıkıyor ve bağ satırı 14'ten
25'e yükseliyor.

İki sütun aynı olayı sayıyor. Adayın sağladığı her yetenek, yazılmayan bir işlev **ve** kurulan
bir bağdır. En zengin adayla hiç kod yazılmıyor; ayrılırken yeniden yazılacak yirmi beş satır
kalıyor. En dar adayla on bir işlev elde yazılıyor; o işlevler ayrılırken **taşınıyor**, çünkü
kimseye bağlı değiller. Zengin bir araç geliştirmeyi hızlandırdığı için değil, hızlandırdığı
ölçüde pahalı bir çıkış bırakır.

#### Kazanan Ağırlığa Bağlıdır

İkinci tabloda beş ağırlık kümesi ve **üç ayrı kazanan** var. Olgunluk ağırlıklandırıldığında A,
ekosistem ağırlıklandırıldığında B, geliştirme yükü ağırlıklandırıldığında C kazanıyor. Adaylar
değişmedi; yalnız ölçütlerin çarpanları değişti.

Fark sütunu ikinci bir uyarı taşıyor. Ekosistem ağırlıklı satırda B, C'yi **0,0026** farkla
geçiyor; olgunluk ağırlıklı satırdaki fark 0,1347, yani elli kattan fazlası. İlk satırda kazanan
bir sonuç, ikincisinde bir yuvarlama artığıdır. Bir değerlendirme tablosu tek bir kazanan adı
üretiyorsa eksiktir; farkı da yazmalıdır, çünkü küçük fark ölçütün birini biraz farklı
tanımlamanın kazananı değiştireceği anlamına gelir.

Çıkış ağırlıklı satırda kazanan değişmiyor. Sebebi son bölümde görünüyor: çıkış maliyetinin
büyük kısmı adaydan bağımsızdır.

#### Sarmalayıcının Ödettiği

Üçüncü tablo, seçim yanlış çıkarsa çıkışı ucuzlatmak için konan **sarmalayıcı** katmanı ölçüyor.
Sarmalayıcı yalnız kendisine verilen yeteneği dışa açar; kapsamadığı bir yeteneğe ihtiyaç duyan
modül araca doğrudan bağlanmak zorundadır. Bu **sızıntıdır** ve sayılabilir.

Üç adayın ortak yetenek kesişimi 2/7'dir. Sarmalayıcı gerçekten taşınabilir olsun isteniyorsa
kapsamı en fazla bu kesişim olabilir — ve o kapsamda **5 modül sızıyor**, çıkış maliyeti 57,5
saatten yalnız 41,5 saate iniyor (yüzde 27,8). Kapsam adayın kendi yetenek kümesine kadar
genişletildiğinde sızıntı sıfırlanıyor ve çıkış 28,0 saate iniyor (yüzde 51,3) — ama artık
sarmalayıcı seçilen adayın yeteneklerini dışa açtığı için başka bir adaya geçiş, o yetenekleri
sarmalayıcının ardında elde yazmayı gerektirir. Son satır bunun ölçüsünü veriyor: dar bir aday
doğrudan kullanıldığında 11 elde yazılan işlev gerekiyor, aynı işlevler bir sarmalayıcının
ardında **5 kez** yazılıyor.

Asıl sınır kod payıyla veri payının ayrılmasında. Sarmalayıcı kod payını **33,5 saatten 4,0
saate** indiriyor; veri payı **24,0 saat** iki durumda da aynı kalıyor, çünkü 1.200.000 kayıt
hangi araca geçilirse geçilsin taşınacaktır. Sarmalayıcının azaltabileceği en büyük miktar toplam
çıkışın yarısı kadardır.

Bedelin kendisi de bir sayıdır. **MP15: sarmalayıcının her satırı yılda 0,1 saat bakım ister.**
On dokuz satır yılda 1,9 saat eder; kazanç 29,5 saattir. Sarmalayıcı, araç değiştirme olasılığı
yıllık **0,064**'ten büyükse kendini ödüyor. Bu eşik, sarmalayıcının yazılıp yazılmayacağını bir
tahmine değil, bir karşılaştırmaya bağlar.

#### Özet

- Aday ürün adıyla değil, olgunluk ve ekosistem ölçütleriyle betimlenir; çıkış maliyeti
  adayın değil, adayın koda nasıl girdiğinin özelliğidir ve on iki modüllük bir kaynak ağacı
  diske yazılıp taranarak ölçülür (MP13, MP14).
- Yerleşik yetenek 2/7'den 7/7'ye çıktığında toplam satır 127'den 73'e, elde yazılan işlev
  11'den 0'a iner; aynı anda çıkış maliyeti 53,0 saatten 60,5 saate çıkar. Sağlanan her yetenek
  hem yazılmayan bir işlev hem kurulan bir bağdır.
- Beş ağırlık kümesi üç ayrı kazanan üretti. Kazanan, adayların değil ağırlıkların sonucudur;
  ekosistem ağırlıklı satırda fark 0,0026, olgunluk ağırlıklı satırda 0,1347 — birinci fark bir
  sonuç değildir ve tablo kazananla birlikte farkı da yazmalıdır.
- Sarmalayıcının kapsamı adayların ortak kesişimiyle sınırlıdır (2/7); o kapsamda 5 modül sızar
  ve çıkış yalnız yüzde 27,8 azalır. Tam kapsam sızıntıyı sıfırlar ama sarmalayıcıyı seçilen
  adaya bağlar.
- Sarmalayıcı çıkışın kod payını 33,5 saatten 4,0 saate indirir, veri payı olan 24,0 saati hiç
  azaltmaz; on dokuz satırlık bakım yüküyle karşılaştırıldığında yıllık geçiş olasılığı
  0,064'ten büyükse kendini öder (MP15).

#### Sonraki Adım

Bu dersin bütün sayıları bir ana bağlıdır. Adayın yaşı, kırıcı sürüm sıklığı, uyarlayıcı sayısı
ve belgelenmiş işlev oranı ölçüldükleri gün doğrudur; ağırlıklar da o günün önceliklerini
yansıtır. Karar bu tabloyla verilir ve tablo yerinde durur — ama tablonun dayandığı sayılar
durmaz. Sıradaki ders, kursun son dersi, bunu bir modele çevirir: bir kararın dayanağının
geçerlilik süresi vardır, yenilenmeyen dayanağa yaslanan kararın yanlış çıkma oranı vardır ve
öğrenmeye ayrılan pay bu oranı düşürür. Sorusu şudur: bilgi tazeliği bir erdem değil, bir bütçe
dağıtımıysa o bütçe nasıl dağıtılır?

### Sürekli Öğrenme Disiplini

Source: https://academia.sh/tr/kurslar/mimarin-rolu/surekli-ogrenme-disiplini

Bilgi tazeliğinin bir bütçe dağıtımı olarak ölçülmesi: kararın dayandığı bilginin geçerlilik süresine bağlanması, yenilenmeyen dayanağa yaslanan kararın yanlış çıkma oranının 72 aylık bir koşumda sayılması ve aynı yıllık 72 saatin eşit, eskimeye göre ve en bayat önce dağıtıldığında oranı 0,3958, 0,3715 ve 0,2222 vermesi.

Önceki ders bir aday tablosu kurdu ve bir kazanan çıkardı. Tablonun her hücresi ölçüldüğü gün
doğruydu: adayın yaşı, kırıcı sürüm sıklığı, uyarlayıcı sayısı, belgelenmiş işlev oranı. Karar
verildi, tablo yerinde duruyor. Tablonun dayandığı sayılar durmuyor.

Bu, bütün kursun ölçtüğü kararlar için geçerlidir. Bir denge kararının ağırlıkları, bir
sadeleştirmenin arızi karmaşıklık payı, bir geri alma maliyeti — hepsi bir ölçümden gelir ve
her ölçüm bir tarihe aittir. Bu son ders bunu bir modele çevirir: bir kararın **dayanağının**
geçerlilik süresi vardır, süresi geçmiş dayanağa yaslanan kararın yanlış çıkma olasılığı
yükselir ve öğrenmeye ayrılan saatler bu olasılığı düşürür. Öğrenme bir erdem değil, bir
**bütçe dağıtımıdır**; ve dağıtımın kendisi, bütçenin büyüklüğünden daha çok fark yaratır.

#### Dayanağın Geçerlilik Süresi

Modelde her karar üç **dayanağa** yaslanır. Bir dayanak bir bilgi parçasıdır ve kategorisine
göre yaşlanır.

**MP16: bir dayanağın geçerlilik süresi kategorisine bağlıdır.** Bir ölçümden gelen sayı altı
ay, bir aracın olgunluk ve ekosistem profili on sekiz ay, yapısal bir ilke yüz yirmi ay geçerli
kalır. Tazeleme maliyetleri de ayrışır: bir ölçümü yeniden koşturmak bir saat, bir aracın
profilini yeniden çıkarmak dört saat, yapısal bir ilkeyi yeniden gözden geçirmek on iki saat.

**MP17: yanlış çıkma olasılığı dayanak tazeyken tabandadır ve yaş geçerlilik süresini aştıkça
artar**; yaş ömrün üç katına ulaştığında olasılık bire çıkar. Taban 0,05'tir, yani taze bir
dayanak bile yanılabilir. Bir karar üç dayanağının hepsi doğru çıktığında doğrudur.

```js
// ogrenme/model.mjs — bilgi tazeliginin surec ici modeli. Gercek kurum, arac ve kisi yoktur.
// Sure olculmez; ay, karar, bayat dayanak ve yanlis cikan karar sayilir. Rastgelelik kendi
// yazilan bir uretecten gelir ve tohum gorunurdur.

// MP16: bir dayanagin gecerlilik suresi kategorisine baglidir (ay).
export const KATEGORI = {
  olcum: { adet: 30, omur: 6, tazelemeSaat: 1 },
  arac: { adet: 20, omur: 18, tazelemeSaat: 4 },
  yapi: { adet: 10, omur: 120, tazelemeSaat: 12 },
};

export const AY = 72, AYLIK_KARAR = 4, DAYANAK_BASINA_KARAR = 3, TABAN = 0.05;

export function uretec(tohum) {
  let t = tohum;
  return () => ((t = (t * 1103515245 + 12345) % 2147483648) / 2147483648);
}

export function dayanaklar(rast) {
  const d = [];
  for (const [ad, k] of Object.entries(KATEGORI))
    for (let i = 0; i < k.adet; i++) d.push({ kategori: ad, yas: rast() * k.omur });
  return d;
}

// MP17: yanlis cikma olasiligi dayanak tazeyken TABAN'dir ve yas gecerlilik suresini astikca
// artar; yas omrun uc katina ulastiginda 1'e cikar.
export const hataOlasiligi = (d) => {
  const omur = KATEGORI[d.kategori].omur;
  return TABAN + (1 - TABAN) * Math.min(1, Math.max(0, (d.yas - omur) / (2 * omur)));
};

// Dagitim stratejileri: aylik butceyi kategorilere boler. Pay toplami 1'dir.
export const DAGITIM = {
  "esit": () => ({ olcum: 1 / 3, arac: 1 / 3, yapi: 1 / 3 }),
  "eskimeye gore": () => {
    const h = Object.fromEntries(Object.entries(KATEGORI).map(([a, k]) => [a, k.adet / k.omur]));
    const t = Object.values(h).reduce((x, y) => x + y, 0);
    return Object.fromEntries(Object.entries(h).map(([a, v]) => [a, v / t]));
  },
  "yalniz olcum": () => ({ olcum: 1, arac: 0, yapi: 0 }),
  "yalniz yapi": () => ({ olcum: 0, arac: 0, yapi: 1 }),
};

// Kategori payi olmadan, en bayat dayanaktan baslayarak harcayan strateji.
const enBayatOnce = (d, butce) => {
  let kalan = butce;
  for (const x of [...d].sort((a, b) =>
      b.yas / KATEGORI[b.kategori].omur - a.yas / KATEGORI[a.kategori].omur)) {
    const m = KATEGORI[x.kategori].tazelemeSaat;
    if (m > kalan) continue;
    kalan -= m; x.yas = 0;
  }
  return kalan;
};

// Kategori payiyla harcayan strateji: her kategoride en eski dayanak once tazelenir.
const payaGore = (d, butce, pay, kasa) => {
  for (const ad of Object.keys(KATEGORI)) {
    kasa[ad] = (kasa[ad] ?? 0) + butce * pay[ad];
    const m = KATEGORI[ad].tazelemeSaat;
    const sirali = d.filter((x) => x.kategori === ad).sort((a, b) => b.yas - a.yas);
    for (const x of sirali) {
      if (m > kasa[ad]) break;
      kasa[ad] -= m; x.yas = 0;
    }
  }
};

export function kosum({ strateji, butce, tohum = 20260801 }) {
  const rast = uretec(tohum);
  const d = dayanaklar(rast);
  const kasa = {};
  let karar = 0, yanlis = 0, bayatDayanak = 0, kullanilanDayanak = 0;
  for (let ay = 0; ay < AY; ay++) {
    for (const x of d) x.yas += 1;
    if (butce > 0 && strateji === "en bayat once") enBayatOnce(d, butce);
    else if (butce > 0) payaGore(d, butce, DAGITIM[strateji](), kasa);
    for (let i = 0; i < AYLIK_KARAR; i++) {
      let dogru = 1;
      for (let j = 0; j < DAYANAK_BASINA_KARAR; j++) {
        const x = d[Math.floor(rast() * d.length)];
        kullanilanDayanak += 1;
        if (x.yas > KATEGORI[x.kategori].omur) bayatDayanak += 1;
        dogru *= 1 - hataOlasiligi(x);
      }
      karar += 1;
      if (rast() > dogru) yanlis += 1;
    }
  }
  return { karar, yanlis, oran: yanlis / karar, bayatOran: bayatDayanak / kullanilanDayanak,
    yillikSaat: butce * 12 };
}
```

#### Aynı Bütçe, Farklı Dağıtım

Altı saat aylık bütçe, yılda yetmiş iki saattir. Aşağıdaki koşum bu saatleri beş ayrı biçimde
dağıtır ve altmış dayanak ile 288 karar üzerinde yanlış çıkan kararı sayar.

```js
// ogrenme/butce.mjs — ayni saat butcesi farkli dagitilinca yanlis cikan karar orani degisir
import { KATEGORI, AY, AYLIK_KARAR, TABAN, DAYANAK_BASINA_KARAR, DAGITIM, kosum } from "./model.mjs";

const BUTCE = 6;
console.log(`ay ${AY}, aylik karar ${AYLIK_KARAR}, toplam karar ${AY * AYLIK_KARAR}, tohum 20260801`);
console.log(`dayanak: ${Object.entries(KATEGORI).map(([a, k]) => `${a} ${k.adet} (omur ${k.omur} ay, tazeleme ${k.tazelemeSaat} saat)`).join("; ")}\n`);

const sifir = kosum({ strateji: "esit", butce: 0 });
console.log(`butce ${BUTCE} saat/ay = ${BUTCE * 12} saat/yil`);
console.log("strateji           olcum   arac   yapi   bayat dayanak  yanlis karar  oran   dususu");
console.log("----------------- ------ ------ ------ --------------- ------------- ------ -------");
console.log(`${"butce yok".padEnd(17)} ${"-".padStart(6)} ${"-".padStart(6)} ${"-".padStart(6)} ` +
  `${sifir.bayatOran.toFixed(4).padStart(15)} ${String(sifir.yanlis).padStart(13)} ` +
  `${sifir.oran.toFixed(4).padStart(6)} ${"-".padStart(7)}`);
for (const ad of [...Object.keys(DAGITIM), "en bayat once"]) {
  const r = kosum({ strateji: ad, butce: BUTCE });
  const p = DAGITIM[ad] ? DAGITIM[ad]() : null;
  const s = (k) => (p ? p[k].toFixed(2) : "-").padStart(6);
  console.log(`${ad.padEnd(17)} ${s("olcum")} ${s("arac")} ${s("yapi")} ` +
    `${r.bayatOran.toFixed(4).padStart(15)} ${String(r.yanlis).padStart(13)} ` +
    `${r.oran.toFixed(4).padStart(6)} ${`${((1 - r.oran / sifir.oran) * 100).toFixed(1)}%`.padStart(7)}`);
}

console.log(`\nbutce buyudukce (strateji: eskimeye gore):`);
console.log("saat/ay  saat/yil  bayat dayanak  yanlis karar  oran   saat basina dusen hata");
console.log("------- --------- --------------- ------------- ------ ----------------------");
let oncekiOran = sifir.oran, oncekiSaat = 0;
for (const b of [0, 2, 4, 6, 12, 24, 48]) {
  const r = kosum({ strateji: "eskimeye gore", butce: b });
  const marj = b === 0 ? null : (oncekiOran - r.oran) / ((b - oncekiSaat) * 12);
  console.log(`${String(b).padStart(7)} ${String(b * 12).padStart(9)} ${r.bayatOran.toFixed(4).padStart(15)} ` +
    `${String(r.yanlis).padStart(13)} ${r.oran.toFixed(4).padStart(6)} ` +
    `${(marj === null ? "-" : marj.toExponential(2)).padStart(22)}`);
  oncekiOran = r.oran; oncekiSaat = b;
}

console.log(`\ntohum duyarliligi (butce ${BUTCE}, strateji: eskimeye gore):`);
console.log("tohum       oran");
for (const t of [20260801, 991, 4242]) {
  const r = kosum({ strateji: "eskimeye gore", butce: BUTCE, tohum: t });
  console.log(`${String(t).padStart(9)} ${r.oran.toFixed(4).padStart(9)}`);
}

console.log(`\ntaban: butun dayanaklar taze olsa bile karar basina yanlislik = ${(1 - (1 - TABAN) ** DAYANAK_BASINA_KARAR).toFixed(4)}`);
```

```
ay 72, aylik karar 4, toplam karar 288, tohum 20260801
dayanak: olcum 30 (omur 6 ay, tazeleme 1 saat); arac 20 (omur 18 ay, tazeleme 4 saat); yapi 10 (omur 120 ay, tazeleme 12 saat)

butce 6 saat/ay = 72 saat/yil
strateji           olcum   arac   yapi   bayat dayanak  yanlis karar  oran   dususu
----------------- ------ ------ ------ --------------- ------------- ------ -------
butce yok              -      -      -          0.8461           261 0.9063       -
esit                0.33   0.33   0.33          0.4039           114 0.3958   56.3%
eskimeye gore       0.81   0.18   0.01          0.2662           107 0.3715   59.0%
yalniz olcum        1.00   0.00   0.00          0.3403           150 0.5208   42.5%
yalniz yapi         0.00   0.00   1.00          0.7778           260 0.9028    0.4%
en bayat once          -      -      -          0.2940            64 0.2222   75.5%

butce buyudukce (strateji: eskimeye gore):
saat/ay  saat/yil  bayat dayanak  yanlis karar  oran   saat basina dusen hata
------- --------- --------------- ------------- ------ ----------------------
      0         0          0.8461           261 0.9063                      -
      2        24          0.6227           206 0.7153                7.96e-3
      4        48          0.4144           138 0.4792                9.84e-3
      6        72          0.2662           107 0.3715                4.48e-3
     12       144          0.2130            67 0.2326                1.93e-3
     24       288          0.0648            49 0.1701                4.34e-4
     48       576          0.0475            47 0.1632                2.41e-5

tohum duyarliligi (butce 6, strateji: eskimeye gore):
tohum       oran
 20260801    0.3715
      991    0.3854
     4242    0.3715

taban: butun dayanaklar taze olsa bile karar basina yanlislik = 0.1426
```

Bütün sayılar bu koşuma aittir; üreteç kendi yazılmıştır ve tohum görünür. Tohum
duyarlılığı satırları oranın 0,3715 ile 0,3854 arasında oynadığını gösteriyor, yani
karşılaştırmalar tohuma bağlı değil.

#### Dağıtımın Sonucu

İlk tablo, aynı yetmiş iki saatin nereye konduğuna göre yanlış karar oranını 0,9028 ile 0,2222
arasında herhangi bir yere koyabildiğini gösteriyor. Aradaki fark dört kattan fazla ve bütçe
hiç değişmedi.

En keskin satır `yalniz yapi`. Bütün bütçe yapısal ilkelere harcandığında oran 0,9028; hiç
bütçe olmadığındaki 0,9063'ten yalnız yüzde 0,4 daha iyi. Yapısal ilkeler yüz yirmi ay geçerli
kaldığı için yetmiş iki aylık koşumda zaten bayatlamıyorlar; onları tazelemek hiçbir kararı
kurtarmıyor. Öğrenmenin en saygın görünen biçimi, bu modelde ölçülebilir hiçbir şey
değiştirmiyor.

Karşı uç da tek başına doğru değil. `yalniz olcum` bütçenin tamamını en hızlı eskiyen kategoriye
koyuyor ve oranı 0,5208'e indiriyor — eşit dağıtımın 0,3958'inden kötü. Bir kategoriyi tamamen
ihmal etmek, oradaki dayanakların hepsini bayatlatıyor.

`eskimeye gore` dağıtımı payları kategorinin eskime hızından çıkarıyor: ölçüm 0,81, araç 0,18,
yapı 0,01. Sonuç 0,3715 ile eşit dağıtımdan iyi ama en iyisi değil. **`en bayat once`** hiç pay
hesaplamıyor; her ay elindeki bütçeyi, geçerlilik süresini en çok aşmış dayanaktan başlayarak
harcıyor ve oranı **0,2222**'ye indiriyor — yanlış karar sayısı 107 yerine 64.

Sabit pay, bir kategoride harcanacak bayat dayanak kalmadığında bile o saati oraya harcamak
zorunda; `en bayat once` bütün dayanakları tek sırada tutuyor. Bir yan ölçüsü de var: bayat
dayanak oranı `eskimeye gore` ile 0,2662, `en bayat once` ile 0,2940 — daha **çok** bayat
dayanak kalmasına rağmen daha **az** yanlış karar çıkıyor. Bayat dayanak saymak yeterli
değildir; ne kadar bayat olduğu sayılmalıdır.

#### Bütçenin Sınırı

İkinci tablo bütçeyi büyütüyor. Yıllık 24 saatten 48 saate çıkıldığında saat başına düşen hata
kazancı 7,96e-3'ten 9,84e-3'e yükseliyor; ondan sonra sürekli düşüyor ve 288 saatten 576 saate
geçişte 2,41e-5'e iniyor. O son adımda yılda 288 saat daha harcanıyor ve oran yalnız 0,0069
azalıyor.

Sebebi son satırda yazılı: taban 0,1426. Bütün dayanaklar taze olsa bile üç dayanağa yaslanan
bir kararın yanlış çıkma olasılığı bu kadardır, çünkü taze bir ölçüm de yanılabilir. Öğrenme
bütçesi bu tabanı azaltamaz; yalnız bayatlıktan gelen fazlalığı kesebilir.

Öğrenme kararı böylece iki sayıya iner: bütçe hangi noktada tabana yaklaşıyor ve eldeki bütçe
hangi kurala göre dağıtılıyor. İkincisi daha çok fark yaratıyor — yetmiş iki saatte dağıtım
kuralını değiştirmek oranı 0,3958'den 0,2222'ye indiriyor, bütçeyi yetmiş iki saatten yüz kırk
dört saate çıkarmak ise 0,3715'ten 0,2326'ya.

#### Özet

- Bir kararın dayanağı geçerlilik süresi olan bir nesnedir; süre kategoriye bağlıdır (ölçüm 6,
  araç 18, yapı 120 ay) ve süresi aşıldıkça kararın yanlış çıkma olasılığı tabandan bire doğru
  yükselir (MP16, MP17).
- Yetmiş iki aylık koşumda hiç öğrenme bütçesi olmayan düzen 288 kararın 261'ini yanlış çıkardı
  (oran 0,9063); aynı bütçeyle yalnız yapısal ilkeleri tazelemek oranı 0,9028'e, yani yüzde 0,4
  düşürdü.
- Aynı yıllık 72 saat, dağıtıma göre 0,3958 (eşit), 0,3715 (eskimeye göre) ve 0,2222 (en bayat
  önce) verdi. Öğrenme bir bütçe dağıtımıdır ve dağıtım kuralı bütçenin kendisinden daha çok
  fark yaratır.
- Bayat dayanak sayısı tek başına yanıltıcıdır: en iyi sonucu veren strateji daha çok bayat
  dayanak bıraktı (0,2940'a karşı 0,2662) ama yanlış kararı 107'den 64'e indirdi.
- Bütçe büyütmenin getirisi azalır ve bir tabanda durur: 0,1426, bütün dayanaklar taze olsa bile
  kalan yanlışlık payıdır. Yıllık 288 saatten sonra harcanan her saatin karşılığı 2,41e-5'tir.

#### Kurs Kapanışı

| Ders | Modellenen nesne | Ölçülen nicelik | Karşılaştırmanın sonucu |
|---|---|---|---|
| Yazılım Mimarisi Tanımı | Karar–modül eşlemesi ve bağımlı kapanış | Geri alma maliyeti (erişilen dosya) | Gövde büyüklüğü sıralaması ile geri alma sıralaması 55 çiftin 31'inde ters düştü |
| Mimarlık Düzeyleri | Karar kapsamı ve dağıtım birimi eşlemesi | Kapsanan birim, habersiz birim, yinelenen karar | Yerel düzen 47 habersiz birim ve 31 çelişen gerçekleştirim; merkezî düzen 0 çelişki ama 99 danışma |
| Mimarın Sorumlulukları | Sorumluluk matrisi ve makinece denetlenebilir kısıt | Kodda karşılığını yitiren karar oranı | Gözetimsiz düzende uygulanma yüzde 25, gözetimli düzende yüzde 88 |
| Mimar ve Geliştirici İlişkisi | Karar verenin bildiği ithal grafiği ile gerçek grafik | Ölü doğan karar oranı ve bilgi farkı (kenar) | Koda dokunmayan mimarda 18 kararın 8'i ölü doğdu, dokunanda hiç; bilgi farkı 13,8 kenara karşı 3,1 |
| Danışmanlık ve Koçluk | Karar aktarım biçimi ve kalıp/kenar durum ayrımı | Doğru uygulanma oranı ve aktarım saati başına artış | 168 durumda buyruk yüzde 68, yazılı gerekçe yüzde 85, birlikte çalışma yüzde 87; saat başına artış 3,71'e karşı 0,55 |
| Denge Kurmak | Alternatif–nitelik tablosu ve ağırlık vektörü | Kazananı değiştirebilen ama kaynağı yazılmamış ağırlık sayısı | 1771 vektörde kazanan bölgeler yüzde 17,7 ve yüzde 68,4; yazılmamış ağırlık 1'den 0'a indi |
| Basitleştirmek | Modül grafiği ile gereksinim grafiği | Özsel ve arızi karmaşıklık payı | Sadeleştirme toplamı 37'den 26'ya indirdi, değişikliğin yayıldığı modül 13'ten 16'ya çıktı |
| Karar Verme | Karar kümesi ve bağımlılık kümesi | Geri alma maliyeti ve bekleme süresi | `hepsine-uzun` politikası 58,70 adam-gün ve 120 gün; eşiği kırılma noktasından türeten politika 38,70 adam-gün ve 55 gün |
| Paydaş Yönetimi | Paydaş sözlüğü, ilgi kümesi ve ifade dizisi | Yanıtlanan soru, onay turu, atlanan kısıt | Teknik anlatım 27 soru ve 8 tur; sonuç odaklı anlatım 0 soru ama 4 sürprizle toplam 7 tur; kısıt taşıyan anlatım 3 tur |
| Teknoloji Değerlendirme | Aday özellik kümesi ve on iki modüllük kaynak ağacı | Çıkış maliyeti (saat), ağırlığa göre kazanan | Beş ağırlık kümesi üç ayrı kazanan verdi; sarmalayıcı kod payını 33,5 saatten 4,0 saate indirdi, veri payı 24,0 saat değişmedi |
| Sürekli Öğrenme Disiplini | Dayanak yaşı ve geçerlilik süresi | Yanlış çıkan karar oranı | Aynı yıllık 72 saat dağıtıma göre 0,3958, 0,3715 ve 0,2222 verdi; bütçesiz düzen 0,9063 |

On bir satırın ortak biçimi kursun kuralıdır: **bir pratiğin değeri ancak ölçülen farkla
savunulur.** Hiçbir derste "mimar dengeli olmalıdır", "mimar sade tasarlamalıdır", "mimar
iletişim kurmalıdır" cümlesi bir sonuç sayılmadı. Her seferinde pratiğin ürünü bir veri yapısına
çevrildi, iki uygulama biçimi aynı girdide koşturuldu ve aradaki fark bir sayı olarak yazıldı.
Fark ölçülemiyorsa ortada savunulacak bir pratik de yoktur.

Bu kurs boyunca kararlar verildi: dengeler kuruldu, alternatifler elendi, eşikler türetildi,
kısıtlar paydaşlara taşındı, adaylar ağırlıklandırıldı ve dayanaklar tazelendi. Hepsinin ortak
bir kusuru var. Hepsi **kararı verenin belleğinde** duruyor. Ağırlık vektörünün kaynağı, elenen
alternatifin neden elendiği, eşiğin hangi kırılma noktasından geldiği, sarmalayıcının hangi
başabaş olasılığıyla yazıldığı — bunların hiçbiri koda yazılmadı. Altı ay sonra "bu neden böyle"
diye soran birine verilecek bir şey yok. Sıradaki kurs, **Mimari Karar ve Dokümantasyon**,
buradan başlar.

