---
title: 'Kurumsal Bağlam ve Tümleştirme'
source: 'https://academia.sh/tr/kurslar/kurumsal-baglam'
language: tr
updated: '2026-08-17T04:42:31+00:00'
license: 'CC BY-SA 4.0'
lessons: 10
outcomes:
    - 'Kurumsal mimari çerçevelerinin amacını ve sınırlarını açıklar'
    - 'Kurum içi sistemler arasında tümleştirme kalıpları seçer'
    - 'Al veya geliştir kararını ölçütlerle verir'
---

# Kurumsal Bağlam ve Tümleştirme

Sistemin tek başına durmadığı ölçek: kurumsal mimarinin iş ve teknoloji hizalaması, çerçevelerin ortak yapısı ve sınırları, iş süreç modelleme ile otomasyon sınırları, iş yeteneğinden sisteme izlenebilirlik, dosya, veritabanı, uzak çağrı ve mesajlaşma tümleştirme kalıpları, merkezî tümleştirmenin artıları ile eksileri, kaynak sistem ve altın kayıtla ana veri yönetimi, çözümleme yükünü ayıran dönüştürme hatları, eski sistemlerin sarmalanarak aşamalı değiştirilmesi ve toplam sahip olma maliyetiyle bağımlılık riskine dayanan al veya geliştir kararı.

## Kurumsal Mimari

Tek sistemin üstündeki düzey: iş ile teknolojinin hizalanmasının ne anlama geldiği, kurumsal mimari çerçevelerinin ortak yapısı ve nerede işe yaramadığı, iş süreçlerinin gösterimi ile otomasyon sınırının çizilmesi ve iş yeteneğinden onu karşılayan sisteme izlenebilirliğin kurulması.

### Kurumsal Mimari Kavramı

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/kurumsal-mimari-kavrami

Tek sistemin dışına çıkan düzey: kurumun sistemlerini, sahiplerini, bütçelerini ve iş yeteneklerini bir veri yapısına çevirmek, iş ile teknoloji arasındaki hizalamayı üç sayıya bağlamak — hiçbir sistemin karşılamadığı yetenek, birden çok sistemin karşıladığı yetenek ve hiçbir yeteneğe bağlanamayan sistem.

Önceki kurs kararı bir kayda, sistemi bir görünüme çevirdi ve her belgeyi yanıtladığı soru
sayısıyla ölçtü. O kayıtların ve görünümlerin hepsinin ortak bir sınırı vardı: tek bir sistemin
içinde duruyorlardı. Oysa bir sistem kendi başına durmaz. Yanında, aynı üyeye aynı gün hizmet
veren başka sistemler vardır; bazısı dışarıdan alınmıştır, bazısının bütçesi başka bir birimin
kaleminden çıkar, bazısına o kurumun hiçbir çalışanı kod yazamaz.

Bu ders ölçeği bir basamak yukarı taşıyor. Mimarın Rolü kursundaki mimarlık düzeyleri dersi
kurumsal düzeyi kapsamla tanımlamıştı: bir kararın bağladığı dağıtım birimi sayısı. O dersin
habersiz birim ölçümü burada tekrarlanmaz, girdi olarak alınır. Değişen şey birimin kendisidir:
artık ayrı yayınlanan bir dağıtım birimi değil, **ayrı sahibi ve ayrı bütçesi olan bir sistem**
sayılıyor. Kurumsal mimari (enterprise architecture) bu ölçeğin adıdır ve ilk sorusu şudur: kurumun
yapmak zorunda olduğu işler ile elindeki sistemler birbirini ne kadar karşılıyor.

#### Kurum Bir Veri Yapısıdır

**İş ve teknoloji hizalaması** (business–IT alignment), söz olarak bakıldığında ölçülemez bir
iddiadır. Ölçülebilir hale gelmesi için iki listenin yan yana konması gerekir: kurumun karşılamak
zorunda olduğu **iş yetenekleri** (business capability) ve bu yetenekleri karşıladığını iddia eden
sistemler. Yetenek listesi sistemlerden türetilmez; kurumun kendi işinden gelir (**KM1**). Bu ayrım
ölçümün tamamını taşır: liste sistemlerden türetilseydi karşılanmayan bir yetenek hiç görünmezdi.

Model olarak bölgesel bir kütüphane ağı kullanılıyor. Kurgudur; gerçek bir kurum, satıcı, ürün ya
da kişi anlatılmaz. Ağda şube sistemleri, dışarıdan alınmış bir katalog sistemi, içeride yazılmış
ödünç ve ücretlendirme servisleri, ayrı bir üyelik sistemi, belediye tarafında duran bir kimlik
doğrulama servisi ve raporlama isteyen bir yönetim birimi var. Sahipler ve bütçeler ayrıdır.

Bir sistem, ayrı bütçeden ödenen, ayrı sahibi olan ve ayrı yayınlanan yazılımdır (**KM2**). Sistem
kaydındaki karşılama listesi bir **iddiadır**; iddianın kodda karşılığı olup olmadığı bu derste
sınanmaz (**KM3**). **Bağ** (integration edge), aynı veri varlığı üzerinden yazan sistemden okuyan
sisteme giden yönlü çifttir (**KM4**) — bu kursun ölçü birimi budur.

```js
// kurum/model.mjs — MODEL bolgesel kutuphane agi: sistemler, sahipler, yetenekler, veri.
// Kurgudur; gercek bir kurum, satici, urun ya da kisi anlatilmaz.
export const SISTEM = {
  katalog: { sahip: "dis-saglayici", butce: "hizmet-bedeli" },
  odunc: { sahip: "bt-birimi", butce: "ic-gelistirme" },
  ucretlendirme: { sahip: "bt-birimi", butce: "ic-gelistirme" },
  uyelik: { sahip: "uye-hizmetleri", butce: "uye-hizmetleri" },
  kimlik: { sahip: "belediye-bt", butce: "belediye" },
  "sube-yerel": { sahip: "sube-yonetimi", butce: "sube" },
  kiosk: { sahip: "sube-yonetimi", butce: "sube" },
  raporlama: { sahip: "yonetim-birimi", butce: "yonetim" },
  arsiv: { sahip: "yok", butce: "yok" },
};
// YETENEK — kurumun karsilamak zorunda oldugu is yetenekleri (sistemden bagimsiz liste)
export const YETENEK = ["materyal-arama", "odunc-verme", "iade-alma", "ayirtma",
  "uyelik-acma", "uye-dogrulama", "ucret-hesaplama", "ucret-tahsilati",
  "subeler-arasi-aktarim", "demirbas-sayimi", "kullanim-raporlama",
  "satin-alma-onerisi", "gecikme-bildirimi"];
// KARSILAMA[s] = s sisteminin karsiladigini iddia ettigi yetenekler
export const KARSILAMA = {
  katalog: ["materyal-arama", "demirbas-sayimi"],
  odunc: ["odunc-verme", "iade-alma", "ayirtma", "gecikme-bildirimi"],
  ucretlendirme: ["ucret-hesaplama", "gecikme-bildirimi"],
  uyelik: ["uyelik-acma", "uye-dogrulama"],
  kimlik: ["uye-dogrulama"],
  "sube-yerel": ["iade-alma", "subeler-arasi-aktarim", "demirbas-sayimi"],
  kiosk: ["odunc-verme", "materyal-arama"],
  raporlama: ["kullanim-raporlama"],
  arsiv: [],
};
// VERI[v] = veri varligi; hangi sistem yaziyor, hangileri okuyor
export const VERI = {
  "uye-kaydi": { yazan: ["uyelik"], okuyan: ["odunc", "ucretlendirme", "kiosk", "raporlama"] },
  "kimlik-eslesmesi": { yazan: ["kimlik", "uyelik"], okuyan: ["odunc", "kiosk"] },
  "materyal-kaydi": { yazan: ["katalog"], okuyan: ["odunc", "kiosk", "sube-yerel", "raporlama"] },
  "nusha-durumu": { yazan: ["katalog", "odunc", "sube-yerel"], okuyan: ["kiosk", "raporlama"] },
  "odunc-hareketi": { yazan: ["odunc", "kiosk"], okuyan: ["ucretlendirme", "raporlama"] },
  "ucret-kaydi": { yazan: ["ucretlendirme"], okuyan: ["uyelik", "raporlama", "kiosk"] },
  "ceza-kurali": { yazan: ["ucretlendirme"], okuyan: ["odunc", "kiosk"] },
  "aktarim-istegi": { yazan: ["sube-yerel"], okuyan: ["odunc", "katalog"] },
  "eski-kayit": { yazan: [], okuyan: ["arsiv", "raporlama"] },
  "sayim-farki": { yazan: ["sube-yerel"], okuyan: [] },
};
export const SISTEMLER = Object.keys(SISTEM);
export const sahibi = (s) => SISTEM[s].sahip;
// bag = ayni veri varligi uzerinden yazan sistemden okuyan sisteme giden yonlu cift
export function baglar() {
  const b = new Map();
  for (const [v, d] of Object.entries(VERI))
    for (const y of d.yazan) for (const o of d.okuyan)
      if (y !== o) b.set(`${y}->${o}`, [...(b.get(`${y}->${o}`) ?? []), v]);
  return b;
}
```

#### Ölçüm

İkinci dosya hizalamayı üç sayıya indirger ve aynı modeli iki envanter biçiminde okur.

```js
// kurum/hizalama.mjs — bosluk, ortusme, yetim sistem; iki envanter biciminin gordugu
import { SISTEM, YETENEK, KARSILAMA, VERI, SISTEMLER, sahibi, baglar } from "./model.mjs";

const sut = (s, n) => String(s).padEnd(n);
const sahipler = [...new Set(SISTEMLER.map(sahibi))].filter((o) => o !== "yok");
const karsilayan = (y) => SISTEMLER.filter((s) => KARSILAMA[s].includes(y));
const B = baglar();
const ciftYonlu = [...B.keys()].filter((k) => {
  const [a, b] = k.split("->");
  return B.has(`${b}->${a}`) && a < b;
});
const sahipAsan = [...B.keys()].filter((k) => {
  const [a, b] = k.split("->");
  return sahibi(a) !== sahibi(b);
});

console.log(`MODEL kurum: ${SISTEMLER.length} sistem, ${sahipler.length} sahip, ` +
  `${YETENEK.length} is yetenegi, ${Object.keys(VERI).length} veri varligi`);
console.log(`bag: ${B.size} yonlu bag, ${ciftYonlu.length} cift yonlu, ` +
  `${sahipAsan.length} tanesi sahip degistiriyor\n`);

console.log(sut("is yetenegi", 24) + sut("sistem", 8) + sut("sahip", 7) + "durum");
console.log("-".repeat(60));
const durumu = (n, os) => (n === 0 ? "bosluk" : n === 1 ? "tek" : os > 1 ? "ortusme+cakisma" : "ortusme");
for (const y of YETENEK) {
  const k = karsilayan(y);
  const os = new Set(k.map(sahibi)).size;
  console.log(sut(y, 24) + sut(k.length, 8) + sut(os, 7) + durumu(k.length, os));
}

const bosluk = YETENEK.filter((y) => karsilayan(y).length === 0);
const ortusme = YETENEK.filter((y) => karsilayan(y).length > 1);
const cakisma = ortusme.filter((y) => new Set(karsilayan(y).map(sahibi)).size > 1);
const yetim = SISTEMLER.filter((s) => KARSILAMA[s].length === 0);
const uzlasma = ortusme.reduce((t, y) => t + new Set(karsilayan(y).map(sahibi)).size - 1, 0);

console.log(`\nbosluk=${bosluk.length} (${bosluk.join(", ")})`);
console.log(`ortusme=${ortusme.length}, bunlarin ${cakisma.length}'i sahiplik cakismasi`);
console.log(`yetim sistem=${yetim.length} (${yetim.join(", ")})`);
console.log(`hizalama orani = ${YETENEK.length - bosluk.length}/${YETENEK.length} = ` +
  `${(((YETENEK.length - bosluk.length) / YETENEK.length) * 100).toFixed(1)}%`);
console.log(`ortusen yetenekler icin gereken uzlasma sayisi = ${uzlasma}`);

// ---- iki envanter bicimi ayni modelden turetiliyor ----
// A: sistem envanteri  — kayit birimi sistemdir, yetenek adi sistem kaydinin icinde gecer
// B: yetenek envanteri — kayit birimi yetenektir, sistem adi yetenek kaydinin icinde gecer
const bulgu = [...bosluk.map((y) => ["bosluk", y]), ...ortusme.map((y) => ["ortusme", y]),
  ...yetim.map((s) => ["yetim", s])];
const evrenA = new Set(Object.values(KARSILAMA).flat()); // A yalniz iddia edilen yetenekleri bilir
const gorurA = (t) => t !== "bosluk";                    // yetim sistem A'da bos kayit olarak durur
const gorurB = (t) => t !== "yetim";                     // yetenek kaydi hicbir sistemi anmaz
const sayA = bulgu.filter(([t]) => gorurA(t)).length;
const sayB = bulgu.filter(([t]) => gorurB(t)).length;
console.log(`\nA sistem envanterinin yetenek evreni: ${evrenA.size}/${YETENEK.length} yetenek`);
console.log(sut("bicim", 20) + sut("gorulen bulgu", 16) + "gormedigi");
console.log("-".repeat(60));
console.log(sut("A sistem envanteri", 20) + sut(`${sayA}/${bulgu.length}`, 16) + `${bosluk.length} bosluk`);
console.log(sut("B yetenek envanteri", 20) + sut(`${sayB}/${bulgu.length}`, 16) + `${yetim.length} yetim sistem`);
console.log(sut("kurum modeli (A+B)", 20) + sut(`${bulgu.length}/${bulgu.length}`, 16) + "-");
```

```
MODEL kurum: 9 sistem, 6 sahip, 13 is yetenegi, 10 veri varligi
bag: 23 yonlu bag, 4 cift yonlu, 20 tanesi sahip degistiriyor

is yetenegi             sistem  sahip  durum
------------------------------------------------------------
materyal-arama          2       2      ortusme+cakisma
odunc-verme             2       2      ortusme+cakisma
iade-alma               2       2      ortusme+cakisma
ayirtma                 1       1      tek
uyelik-acma             1       1      tek
uye-dogrulama           2       2      ortusme+cakisma
ucret-hesaplama         1       1      tek
ucret-tahsilati         0       0      bosluk
subeler-arasi-aktarim   1       1      tek
demirbas-sayimi         2       2      ortusme+cakisma
kullanim-raporlama      1       1      tek
satin-alma-onerisi      0       0      bosluk
gecikme-bildirimi       2       1      ortusme

bosluk=2 (ucret-tahsilati, satin-alma-onerisi)
ortusme=6, bunlarin 5'i sahiplik cakismasi
yetim sistem=1 (arsiv)
hizalama orani = 11/13 = 84.6%
ortusen yetenekler icin gereken uzlasma sayisi = 5

A sistem envanterinin yetenek evreni: 11/13 yetenek
bicim               gorulen bulgu   gormedigi
------------------------------------------------------------
A sistem envanteri  7/9             2 bosluk
B yetenek envanteri 8/9             1 yetim sistem
kurum modeli (A+B)  9/9             -
```

#### Hizalamanın Üç Sayısı

Hizalama tek bir sayı değil, üç ayrı sayıdır ve üçü farklı şeyi söyler.

**Boşluk**, hiçbir sistemin karşılamadığı iş yeteneğidir. Modelde iki tane var: ücret tahsilatı ve
satın alma önerisi. İkisi de yapılıyor — ücret bankoda alınıyor, satın alma önerileri elde
tutulan çizelgelerde toplanıyor — ama hiçbir sistemin kaydında geçmiyor. Boşluk, işin yapılmadığı
anlamına gelmez; **işin sistem dışında yapıldığı** anlamına gelir. Hizalama oranı bu modelde
11/13, yani %84,6.

**Örtüşme**, birden çok sistemin aynı yeteneği karşıladığı durumdur: altı tane. Örtüşmenin kendisi
kusur değildir; kiosk ile ödünç servisinin ikisinin de ödünç verebilmesi bir gerekliliktir.
Belirleyici olan örtüşmenin **kaç sahibe** yayıldığıdır. Altı örtüşmenin beşinde karşılayan
sistemlerin sahibi farklı; bunlar **sahiplik çakışmasıdır** (ownership conflict). Gecikme bildirimi
iki sistem tarafından karşılanıyor ama ikisinin de sahibi aynı birim; kuralın değişmesi tek bir
masada halledilir. Diğer beşinde kural değişikliği iki ayrı bütçenin, iki ayrı takvimin ve iki
ayrı önceliğin uzlaşmasını gerektirir. Modelde uzlaşma sayısı beştir ve bu sayı kurumun
koordinasyon yükünün alt sınırıdır.

**Yetim sistem**, hiçbir yeteneğe bağlanamayan sistemdir: arşiv. Sahibi de yok. Yetim sistem
kendiliğinden kapatılacak bir şey değildir — arşiv kaydını hâlâ raporlama okuyor — ama savunması
olmayan bir kalemdir: bütçe tartışmasında onu kimin savunacağı belirsizdir.

Bağ sayısı bu üç sayının üstüne oturur. On veri varlığı üzerinden yirmi üç yönlü bağ çıkıyor;
dördü çift yönlü, yirmisi bir sahiplik sınırını geçiyor. Yirmi üç bağın yirmisinin sahip
değiştirmesi, kurum ölçeğinde tümleştirmenin teknik değil örgütsel bir işlem olduğunu sayıyla
söyler: bağların %87'sinde bir tarafın yaptığı değişiklik başka bir bütçenin sahibini ilgilendirir.

#### Envanterin Biçimi Bulguyu Belirler

Aynı model iki biçimde yazılabilir. **Sistem envanterinde** kayıt birimi sistemdir; her sistemin
kaydında karşıladığı yetenekler listelenir. **Yetenek envanterinde** kayıt birimi yetenektir; her
yeteneğin kaydında onu karşılayan sistemler listelenir. İkisi de aynı model üzerinden yazılıyor,
ama gördükleri bulgu kümesi aynı değil.

Modelde toplam dokuz bulgu var: iki boşluk, altı örtüşme, bir yetim sistem. Sistem envanteri
bunların yedisini gösteriyor. Göremediği boşluktur, çünkü sistem envanterinin yetenek evreni
sistem kayıtlarından türer: on üç yeteneğin yalnız on biri herhangi bir kayıtta geçer, hiç
geçmeyen iki yetenek envanterde hiç yoktur. Yetenek envanteri sekiz bulguyu gösteriyor; göremediği
yetim sistemdir, çünkü hiçbir yeteneğin kaydında adı geçmeyen bir sistem o envantere hiç girmez.

Dokuzun tamamını yalnız iki yönlü eşleme — kurum modeli — gösterir. Kurumsal mimarinin ilk ürünü
bu yüzden bir liste değil bir **eşlemedir**: iki listenin hangi noktalarda birbirine değmediği,
listelerin kendisinden daha çok bilgi taşır.

#### Özet

- Kurumsal mimarinin birimi dağıtım birimi değil, ayrı sahibi ve ayrı bütçesi olan sistemdir;
  model kurumda 9 sistem, 6 sahip, 13 iş yeteneği ve 10 veri varlığı var.
- İş ve teknoloji hizalaması tek sayı değil üç sayıdır: 2 boşluk, 6 örtüşme, 1 yetim sistem;
  hizalama oranı 11/13 (%84,6).
- Örtüşmenin maliyetini sahip sayısı belirler: 6 örtüşmenin 5'i iki ayrı sahibe yayılıyor ve
  toplam 5 uzlaşma gerektiriyor; aynı sahipteki örtüşme tek masada çözülür.
- Model kurumda 23 yönlü bağ var, 4'ü çift yönlü ve 20'si bir sahiplik sınırını geçiyor.
- Sistem envanteri 9 bulgunun 7'sini, yetenek envanteri 8'ini gösterir; dokuzunun tamamı yalnız
  iki listenin eşlemesinden okunur.

#### Sonraki Adım

Bu ders kurum modelini bir kez kurdu ve üç sayı üretti. Modelin **nasıl belgeleneceği** hiç
sorulmadı: hangi katmanlara ayrılacağı, kaç ayrı görünümle yazılacağı, kimin ne sıklıkta gözden
geçireceği ve bu belgenin kendisinin ne kadar bakım isteyeceği açık değil. Kurumsal mimari
çerçeveleri tam olarak bu soruya yanıt verme iddiasındadır. Sonraki ders aynı kurum modelini iki
çerçeve biçiminde — ayrıntılı katmanlı ve hafif — belgeler; her birinin kaç soruyu yanıtladığını,
kaç kalem bakım istediğini ve çerçevenin kendi bakım maliyetinin ne zaman yanıtladığı sorunun
değerini aştığını sayar.

### Çerçeveler

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/cerceveler

Kurumsal mimari çerçevelerinin ortak yapısı — katman ayrımı, görünüm kümesi, yönetişim döngüsü ve olgunluk basamağı — ile aynı kurum modelinin ayrıntılı katmanlı ve hafif biçimde belgelenmesi: her biçimin yanıtladığı soru sayısı, taşıdığı kalem sayısı, değişiklik başına dokunulan kalem ve çerçevenin hiçbir biçimde yanıtlamadığı sorular.

Önceki ders kurum modelini kurdu ve hizalamayı üç sayıya bağladı. Model bir kez çıkarıldı, ama
nereye yazılacağı hiç konuşulmadı: hangi katmanlara ayrılacağı, kaç ayrı görünümle tutulacağı,
kimin ne sıklıkta gözden geçireceği belirsiz. Kurumsal mimari çerçeveleri (framework) bu boşluğu
doldurma iddiasındadır ve iddia genellikle tartışma konusu olur — hangi çerçevenin seçileceği,
ağırın mı hafifin mi doğru olduğu. Bu ders tartışmayı bir ölçüme çevirir. Marka ve çerçeve adı
yazılmaz; çerçeveler ortak yapılarıyla anılır.

#### Çerçevelerin Ortak Yapısı

Adları ve ayrıntıları ne olursa olsun, kurumsal mimari çerçeveleri dört parçadan kurulur.

**Katman ayrımı**, kurumu birbirinden ayrı ama birbirine eşlenen düzlemlere böler: iş yetenekleri
ve sahipleri, sistemler, veri varlıkları, sistemleri taşıyan altyapı. **Görünüm kümesi**, aynı
modelin farklı okuyucular için hazırlanmış kesitleridir. **Yönetişim döngüsü**, hangi kaydın kim
tarafından ne sıklıkta gözden geçirileceğini bağlar. **Olgunluk basamağı**, kurumun bu kayıtların
ne kadarını tuttuğunu sıralayan bir merdivendir.

Bu dört parçanın ortak yanı şudur: hiçbiri bilgi üretmez, bilginin **nereye yazılacağını** söyler.
Bu yüzden bir çerçeve, ancak taşıdığı kayıt türleri üzerinden ölçülebilir. Ölçüm için üç tanım
gerekir. **Kalem**, bağımsız olarak bakılan bir kayıt satırıdır; aynı satıra düşen alanlar ayrı
kalem sayılmaz (**KM5**). **Soru kümesi**, sonradan gelen birinin sorduğu on iki sorudur; ölçü
biçimi Mimari Karar ve Dokümantasyon kursundan ödünç alınmıştır — bir belgenin değeri yanıtladığı
soru sayısıdır (**KM6**). **Olgunluk basamağı**, unvan değil, belirli kayıt türlerinin varlığına
bağlı bir yüklemdir (**KM7**).

İlk dosya önceki dersin kurum modelini yeniden verir; blok kendi başına çalışsın diye tekrarlanıyor.

```js
// kurum/model.mjs — MODEL bolgesel kutuphane agi: sistemler, sahipler, yetenekler, veri.
// Kurgudur; gercek bir kurum, satici, urun ya da kisi anlatilmaz.
export const SISTEM = {
  katalog: { sahip: "dis-saglayici", butce: "hizmet-bedeli" },
  odunc: { sahip: "bt-birimi", butce: "ic-gelistirme" },
  ucretlendirme: { sahip: "bt-birimi", butce: "ic-gelistirme" },
  uyelik: { sahip: "uye-hizmetleri", butce: "uye-hizmetleri" },
  kimlik: { sahip: "belediye-bt", butce: "belediye" },
  "sube-yerel": { sahip: "sube-yonetimi", butce: "sube" },
  kiosk: { sahip: "sube-yonetimi", butce: "sube" },
  raporlama: { sahip: "yonetim-birimi", butce: "yonetim" },
  arsiv: { sahip: "yok", butce: "yok" },
};
// YETENEK — kurumun karsilamak zorunda oldugu is yetenekleri (sistemden bagimsiz liste)
export const YETENEK = ["materyal-arama", "odunc-verme", "iade-alma", "ayirtma",
  "uyelik-acma", "uye-dogrulama", "ucret-hesaplama", "ucret-tahsilati",
  "subeler-arasi-aktarim", "demirbas-sayimi", "kullanim-raporlama",
  "satin-alma-onerisi", "gecikme-bildirimi"];
// KARSILAMA[s] = s sisteminin karsiladigini iddia ettigi yetenekler
export const KARSILAMA = {
  katalog: ["materyal-arama", "demirbas-sayimi"],
  odunc: ["odunc-verme", "iade-alma", "ayirtma", "gecikme-bildirimi"],
  ucretlendirme: ["ucret-hesaplama", "gecikme-bildirimi"],
  uyelik: ["uyelik-acma", "uye-dogrulama"],
  kimlik: ["uye-dogrulama"],
  "sube-yerel": ["iade-alma", "subeler-arasi-aktarim", "demirbas-sayimi"],
  kiosk: ["odunc-verme", "materyal-arama"],
  raporlama: ["kullanim-raporlama"],
  arsiv: [],
};
// VERI[v] = veri varligi; hangi sistem yaziyor, hangileri okuyor
export const VERI = {
  "uye-kaydi": { yazan: ["uyelik"], okuyan: ["odunc", "ucretlendirme", "kiosk", "raporlama"] },
  "kimlik-eslesmesi": { yazan: ["kimlik", "uyelik"], okuyan: ["odunc", "kiosk"] },
  "materyal-kaydi": { yazan: ["katalog"], okuyan: ["odunc", "kiosk", "sube-yerel", "raporlama"] },
  "nusha-durumu": { yazan: ["katalog", "odunc", "sube-yerel"], okuyan: ["kiosk", "raporlama"] },
  "odunc-hareketi": { yazan: ["odunc", "kiosk"], okuyan: ["ucretlendirme", "raporlama"] },
  "ucret-kaydi": { yazan: ["ucretlendirme"], okuyan: ["uyelik", "raporlama", "kiosk"] },
  "ceza-kurali": { yazan: ["ucretlendirme"], okuyan: ["odunc", "kiosk"] },
  "aktarim-istegi": { yazan: ["sube-yerel"], okuyan: ["odunc", "katalog"] },
  "eski-kayit": { yazan: [], okuyan: ["arsiv", "raporlama"] },
  "sayim-farki": { yazan: ["sube-yerel"], okuyan: [] },
};
export const SISTEMLER = Object.keys(SISTEM);
export const sahibi = (s) => SISTEM[s].sahip;
// bag = ayni veri varligi uzerinden yazan sistemden okuyan sisteme giden yonlu cift
export function baglar() {
  const b = new Map();
  for (const [v, d] of Object.entries(VERI))
    for (const y of d.yazan) for (const o of d.okuyan)
      if (y !== o) b.set(`${y}->${o}`, [...(b.get(`${y}->${o}`) ?? []), v]);
  return b;
}
```

#### Ölçüm

İkinci dosya iki biçimi tanımlar. Ayrıntılı katmanlı biçim her kayıt türünü kendi katmanında ayrı
kalem olarak tutar; hafif biçim tek bir sistem tablosu ile bir yetenek listesinden ibarettir ve
sahip, bütçe, karşılama bilgisini sistem satırının sütunlarına katlar.

```js
// kurum/cerceve.mjs — ayni kurum modeli iki cerceve biciminde: yanit, kalem, bakim
import { SISTEM, YETENEK, KARSILAMA, VERI, SISTEMLER, sahibi, baglar } from "./model.mjs";

const sut = (s, n) => String(s).padEnd(n);
const B = baglar();
// KALEM[tur] = o kayit turunun model kurumdaki satir sayisi
const KALEM = {
  yetenek: YETENEK.length,
  sahip: new Set(SISTEMLER.map(sahibi)).size - 1,
  butce: new Set(SISTEMLER.map((s) => SISTEM[s].butce)).size - 1,
  sistem: SISTEMLER.length,
  "yetenek-eslemesi": Object.values(KARSILAMA).flat().length,
  veri: Object.keys(VERI).length, bag: B.size,
  tasiyici: 4, "sistem-tasiyici": SISTEMLER.length,
  gorunum: 4, yonetisim: 4, olgunluk: 1,
};
// BICIM[b].tasiyici[tur] = o kayit turunu tasiyan bagimsiz kalem; null ise bicim tutmaz.
// Ayni kaleme dusen kayitlar ayri bakim istemez (marka degil, ortak yapi anlatiliyor).
const kendi = (l) => Object.fromEntries(l.map((k) => [k, k]));
const BICIM = {
  "ayrintili katmanli": kendi(Object.keys(KALEM)),
  hafif: { sistem: "sistem", sahip: "sistem", butce: "sistem",
    "yetenek-eslemesi": "sistem", yetenek: "yetenek" },
};
const tutar = (b, tur) => Boolean(BICIM[b][tur]);
const kalemSayisi = (b) => [...new Set(Object.values(BICIM[b]))].reduce((t, k) => t + KALEM[k], 0);

// SORU[i] = sonradan gelen birinin sordugu soru; gerek = yanit icin gereken kayit turleri
const SORU = [
  ["hangi sistem hangi yetenegi karsiliyor", ["yetenek-eslemesi"]],
  ["bir sistemin sahibi kim", ["sahip"]],
  ["hangi yetenek hicbir sistemde karsilanmiyor", ["yetenek", "yetenek-eslemesi"]],
  ["bir sistem kapatilsa hangi yetenek bosta kalir", ["yetenek-eslemesi"]],
  ["bir sistemin gideri hangi butceden odeniyor", ["butce"]],
  ["bir veriyi hangi sistem yaziyor", ["veri"]],
  ["iki sistem arasinda hangi veri geciyor", ["bag"]],
  ["bir sistem hangi tasiyicida kosuyor", ["sistem-tasiyici"]],
  ["belgenin hangi bolumu ne zaman gozden gecirildi", ["yonetisim"]],
  ["bir konu hangi gorunumde belgelenmis", ["gorunum"]],
  ["bir veri hangi siklikta geciyor", ["bag-sikligi"]],
  ["bir bag koparsa kim haberdar edilir", ["bag-sorumlusu"]],
];
const yanitlar = (b, gerek) => gerek.every((g) => tutar(b, g));

// DEGISIKLIK[i][1] = degisiklik gerceklestiginde guncellenmesi gereken kayitlar
const DEGISIKLIK = [
  ["yeni sistem devreye alinir", { sistem: 1, "yetenek-eslemesi": 1, bag: 2,
    tasiyici: 1, "sistem-tasiyici": 1, gorunum: 2, yonetisim: 1 }],
  ["sistem baska birime devredilir", { sistem: 1, sahip: 1, butce: 1, gorunum: 1, yonetisim: 1 }],
  ["veri varligina yeni okuyan eklenir", { veri: 1, bag: 1, gorunum: 1, yonetisim: 1 }],
];
function dokunulan(b, d) {
  const grup = new Map(); // ayni kaleme dusen kayitlar tek bakim sayilir
  for (const [tur, n] of Object.entries(d)) {
    const k = BICIM[b][tur];
    if (k) grup.set(k, Math.max(grup.get(k) ?? 0, n));
  }
  return [...grup.values()].reduce((t, n) => t + n, 0);
}

// OLGUNLUK — basamaklar; her basamak belirli kayit turlerini ister
const OLGUNLUK = [
  ["sistem envanteri var", ["sistem"]],
  ["her sistemin sahibi yazili", ["sistem", "sahip"]],
  ["yetenek eslemesi var", ["yetenek", "yetenek-eslemesi"]],
  ["veri sahipligi yazili", ["veri"]],
  ["degisimin etkisi hesaplanabilir", ["veri", "bag"]],
];
const basamak = (b) => {
  let n = 0;
  for (const [, gerek] of OLGUNLUK) { if (!gerek.every((g) => tutar(b, g))) break; n++; }
  return n;
};

const bicimler = Object.keys(BICIM);
console.log(`MODEL kurum: ${SISTEMLER.length} sistem, ${YETENEK.length} yetenek, ` +
  `${Object.keys(VERI).length} veri, ${B.size} bag; soru kumesi ${SORU.length} soru\n`);
console.log(sut("soru", 50) + bicimler.map((b) => sut(b, 20)).join(""));
console.log("-".repeat(88));
for (const [s, gerek] of SORU)
  console.log(sut(s, 50) + bicimler.map((b) => sut(yanitlar(b, gerek) ? "yanit" : "-", 20)).join(""));

console.log("");
console.log(sut("bicim", 20) + sut("yanit", 8) + sut("kalem", 8) + sut("basamak", 9) +
  sut("kalem/yanit", 13) + "degisiklik basina dokunulan kalem");
console.log("-".repeat(100));
for (const b of bicimler) {
  const y = SORU.filter(([, g]) => yanitlar(b, g)).length;
  const k = kalemSayisi(b);
  const d = DEGISIKLIK.map(([, o]) => dokunulan(b, o));
  console.log(sut(b, 20) + sut(`${y}/${SORU.length}`, 8) + sut(k, 8) + sut(`${basamak(b)}/5`, 9) +
    sut((k / y).toFixed(1), 13) + d.join(" + ") + ` = ${d.reduce((t, n) => t + n, 0)}`);
}

const [a, h] = bicimler;
const yA = SORU.filter(([, g]) => yanitlar(a, g)).length;
const yH = SORU.filter(([, g]) => yanitlar(h, g)).length;
console.log(`\nfark: ${kalemSayisi(a) - kalemSayisi(h)} fazla kalem -> ${yA - yH} fazla yanit = ` +
  `${((kalemSayisi(a) - kalemSayisi(h)) / (yA - yH)).toFixed(1)} kalem/ek yanit`);
const gorulmeyen = DEGISIKLIK.filter(([, o]) => dokunulan(h, o) === 0);
console.log(`hafif bicimde hic kalem dokunmayan degisiklik: ${gorulmeyen.length} ` +
  `(${gorulmeyen.map(([ad]) => ad).join("; ")})`);
const hicbiri = SORU.filter(([, g]) => bicimler.every((b) => !yanitlar(b, g)));
console.log(`hicbir bicimin yanitlamadigi soru: ${hicbiri.length} -> ` +
  hicbiri.map(([s]) => s).join(" / "));
console.log("yillik gozden gecirme turu (kapasite duyarliligi):");
for (const kap of [20, 40, 60])
  console.log("  tur basina " + sut(kap, 4) + "kalem -> " + bicimler.map((b) =>
    `${b}=${Math.ceil(kalemSayisi(b) / kap)}`).join(", "));
```

```
MODEL kurum: 9 sistem, 13 yetenek, 10 veri, 23 bag; soru kumesi 12 soru

soru                                              ayrintili katmanli  hafif               
----------------------------------------------------------------------------------------
hangi sistem hangi yetenegi karsiliyor            yanit               yanit               
bir sistemin sahibi kim                           yanit               yanit               
hangi yetenek hicbir sistemde karsilanmiyor       yanit               yanit               
bir sistem kapatilsa hangi yetenek bosta kalir    yanit               yanit               
bir sistemin gideri hangi butceden odeniyor       yanit               yanit               
bir veriyi hangi sistem yaziyor                   yanit               -                   
iki sistem arasinda hangi veri geciyor            yanit               -                   
bir sistem hangi tasiyicida kosuyor               yanit               -                   
belgenin hangi bolumu ne zaman gozden gecirildi   yanit               -                   
bir konu hangi gorunumde belgelenmis              yanit               -                   
bir veri hangi siklikta geciyor                   -                   -                   
bir bag koparsa kim haberdar edilir               -                   -                   

bicim               yanit   kalem   basamak  kalem/yanit  degisiklik basina dokunulan kalem
----------------------------------------------------------------------------------------------------
ayrintili katmanli  10/12   106     5/5      10.6         9 + 5 + 4 = 18
hafif               5/12    22      3/5      4.4          1 + 1 + 0 = 2

fark: 84 fazla kalem -> 5 fazla yanit = 16.8 kalem/ek yanit
hafif bicimde hic kalem dokunmayan degisiklik: 1 (veri varligina yeni okuyan eklenir)
hicbir bicimin yanitlamadigi soru: 2 -> bir veri hangi siklikta geciyor / bir bag koparsa kim haberdar edilir
yillik gozden gecirme turu (kapasite duyarliligi):
  tur basina 20  kalem -> ayrintili katmanli=6, hafif=2
  tur basina 40  kalem -> ayrintili katmanli=3, hafif=1
  tur basina 60  kalem -> ayrintili katmanli=2, hafif=1
```

#### İki Biçimin Farkı

Ayrıntılı katmanlı biçim on iki sorunun onunu yanıtlıyor ve 106 kalem taşıyor. Hafif biçim beşini
yanıtlıyor ve 22 kalem taşıyor. Fark tek bir sayıya iner: **84 fazla kalem, 5 fazla yanıt** —
ek yanıt başına 16,8 kalem. Çerçeve seçimi bu oranın karşılığında verilir. Bir kurum "bir veriyi
hangi sistem yazıyor" sorusunun yanıtını 16,8 kalemin sürekli bakımına değer buluyorsa ayrıntılı
biçim kazanır; bulmuyorsa hafif biçim kazanır. Bu bir tercih değil bir hesaptır ve sayılar kurum
modelinin büyüklüğüne bağlıdır: bağ sayısı arttıkça ayrıntılı biçimin kalem sayısı hızla büyür,
çünkü 106 kalemin 23'ü bağdır.

Değişiklik başına maliyet farkı daha keskin: aynı üç değişiklik ayrıntılı biçimde 18, hafif
biçimde 2 kalem güncelletiyor. Bunun içinde bir uyarı var. "Bir sistem başka birime devredilir"
değişikliği ayrıntılı biçimde beş kalem dokunduruyor; sistemin kendisi değişmiyor, yalnız sahibi
ve bütçesi değişiyor. Kurum ölçeğinde bakımın büyük bölümü teknik değişiklikten değil, **sahiplik
değişikliğinden** gelir.

Üçüncü değişiklik ayrımı görünür kılıyor: bir veri varlığına yeni bir okuyan eklendiğinde hafif
biçimde **hiçbir kalem** dokunmuyor. Bu, hafif biçimin ucuzluğunun kaynağıdır ve aynı zamanda
sınırıdır. Belge yanlış duruma düşmez, çünkü o konuda hiçbir iddiada bulunmamıştır; sessiz kalır.
Kurumda yeni bir bağ oluşur ve belgeye bakan kimse bunu göremez.

Olgunluk basamağı aynı farkın kısaltmasıdır: ayrıntılı biçim beş basamağın beşini, hafif biçim
üçünü karşılıyor. Basamak bir başarı sıralaması değildir; hangi soruların yanıtlanabilir olduğunun
tek sayıya indirgenmiş halidir. Hafif biçim dördüncü basamakta duruyor, çünkü veri sahipliğini
hiç tutmuyor — ve beşinci basamak, yani değişimin etkisinin hesaplanabilmesi, tam olarak bu
kursun ölçü birimine bağlıdır.

#### Çerçevenin Yanıtlamadığı Soru

İki soru hiçbir biçimde yanıtsız kalıyor: bir verinin hangi sıklıkta geçtiği ve bir bağ koptuğunda
kimin haberdar edileceği. Bunun nedeni çerçevenin seçimi değildir. Model bu alanları hiç
taşımıyor; taşımadığı için hiçbir katman ayrımı, hiçbir görünüm kümesi bunları üretemez. Çerçeve
tartışması bilgi üretmez, var olan bilgiyi düzenler — ve düzenlenecek bilgi yoksa daha ayrıntılı
bir çerçeve yalnız daha çok boş kalem üretir.

Yönetişim döngüsünün maliyeti de buradan okunur. Tur başına elden geçirilebilen kalem sayısı bir
eşiktir ve eşiğin kaynağı yazılmalıdır: bu modelde tur başına kırk kalem seçildi (**KM8**). Bu
eşikte ayrıntılı biçim üç turda, hafif biçim tek turda gözden geçirilir. Eşik yirmiye indiğinde
ayrıntılı biçim altı tura çıkar; altmışa çıktığında ikiye iner. Gözden geçirme kapasitesi kalem
sayısının altında kalırsa belge güncelliğini kaybeder, yani çerçevenin kendisi ölçtüğü sapmanın
kaynağı olur.

#### Özet

- Kurumsal mimari çerçeveleri marka farklarından bağımsız olarak dört parçadan kurulur: katman
  ayrımı, görünüm kümesi, yönetişim döngüsü ve olgunluk basamağı; hiçbiri bilgi üretmez, bilginin
  yerini belirler.
- Aynı kurum modeli ayrıntılı katmanlı biçimde 12 sorunun 10'unu yanıtlar ve 106 kalem taşır;
  hafif biçimde 5'ini yanıtlar ve 22 kalem taşır.
- Kararın sayısı ek yanıt başına düşen kalemdir: 84 fazla kalem karşılığında 5 fazla yanıt, yani
  16,8 kalem/ek yanıt; değişiklik başına bakım 18'e karşı 2 kalem.
- Hafif biçimde bir değişiklik hiçbir kaleme dokunmuyor — yeni bir okuyanın eklenmesi. Ucuzluğun
  kaynağı budur ve belgenin sessiz kaldığı yer de burasıdır.
- İki soru hiçbir biçimde yanıtlanmıyor (verinin sıklığı ve bağın sorumlusu), çünkü model o
  alanları hiç taşımıyor; çerçeve seçmek eksik alanı doldurmaz.

#### Sonraki Adım

İki ders de kurumu duran bir yapı olarak ele aldı: sistemler, sahipler, yetenekler, kayıtlar. Oysa
bir iş yeteneği bir liste satırı değil, adım adım işleyen bir süreçtir; üyenin kapıdan girmesiyle
materyali eline alması arasında sırayla gerçekleşen işlemler vardır ve bu adımların
hepsi yazılımın içinde geçmez. Sonraki ders bir iş sürecini adım adım modeller ve her adımı üç
sınıfa ayırır — tümüyle otomatik, insan kararı gerektiren, sistem dışı. Ölçülecek olan şudur:
otomasyon sınırının nereden geçtiği ve sınırı zorlamanın, yani insan kararı gerektiren bir adımı
otomatikleştirmenin ürettiği geri dönüş sayısı.

### İş Süreç Modelleme

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/is-surec-modelleme

Bir iş sürecinin adım adım modellenmesi ve her adımın üç sınıfa ayrılması — tümüyle otomatik, insan kararı gerektiren, sistem dışı: otomasyon sınırının modelden türetilmesi, sürecin dolaştığı aktör ve sahip sayısı, sınırı zorlayarak otomatikleştirilen adımın ürettiği yanlış karar ve geri dönüş sayısı.

Önceki iki ders kurumu duran bir yapı olarak ele aldı: sistemler, sahipler, yetenekler, kayıtlar.
Oysa bir iş yeteneği envanterde tek satırdır ama gerçekleşirken adım adım işleyen bir süreçtir.
"Ödünç verme" satırının arkasında kart okutmadan güvenlik etiketine kadar sıralanan onlarca işlem
vardır ve bunların hepsi yazılımın içinde geçmez. Bu ders o satırı açar ve otomasyonun nerede
durduğunu bir kurala bağlar.

#### Süreç Bir Adım Dizisidir

Süreç gösterimleri sembol kümesi bakımından farklılaşır; marka ve gösterim adı burada yazılmaz.
Ortak yanları şudur: her adımın bir **aktörü**, bir **girdi kümesi** ve bir **çıktısı** vardır.
Bu üç alan yazıldığında gösterimin kendisi ikincil kalır, çünkü ölçülebilir olan alanlardır.

Aktör her zaman bir sistem değildir. Ücretin bankoda tahsil edilmesi de, güvenlik etiketinin
devre dışı bırakılması da sürecin adımıdır; ikisinin de aktörü yazılımın dışındadır. Bir süreç
modelinin ilk işi bu adımları silmek değil, **sınıflandırmaktır**. Üç sınıf kullanılıyor: tümüyle
otomatik, insan kararı gerektiren, sistem dışı.

Sınıflandırma bir görüşe bırakılmaz, modelden türetilir (**KM9**): bir adım ancak bütün girdileri
**yazanı olan** bir veri varlığından geliyorsa ve karar için gereken hiçbir bilgi kalemi veri
modelinin dışında kalmıyorsa otomatiktir. Bu kural iki farklı engeli birbirinden ayırır. Birincisi
bilginin hiçbir yerde bulunmamasıdır — materyalin hasar derecesi hiçbir veri varlığında yoktur.
İkincisi bilginin bir veri varlığı olarak var görünmesi ama onu yazan bir sistemin bulunmamasıdır;
kurum modelindeki eski kayıt böyledir ve buna **sahipsiz veri** (ownerless data) deniyor.

```js
// kurum/model.mjs — MODEL bolgesel kutuphane agi: sistemler, sahipler, yetenekler, veri.
// Kurgudur; gercek bir kurum, satici, urun ya da kisi anlatilmaz.
export const SISTEM = {
  katalog: { sahip: "dis-saglayici", butce: "hizmet-bedeli" },
  odunc: { sahip: "bt-birimi", butce: "ic-gelistirme" },
  ucretlendirme: { sahip: "bt-birimi", butce: "ic-gelistirme" },
  uyelik: { sahip: "uye-hizmetleri", butce: "uye-hizmetleri" },
  kimlik: { sahip: "belediye-bt", butce: "belediye" },
  "sube-yerel": { sahip: "sube-yonetimi", butce: "sube" },
  kiosk: { sahip: "sube-yonetimi", butce: "sube" },
  raporlama: { sahip: "yonetim-birimi", butce: "yonetim" },
  arsiv: { sahip: "yok", butce: "yok" },
};
// YETENEK — kurumun karsilamak zorunda oldugu is yetenekleri (sistemden bagimsiz liste)
export const YETENEK = ["materyal-arama", "odunc-verme", "iade-alma", "ayirtma",
  "uyelik-acma", "uye-dogrulama", "ucret-hesaplama", "ucret-tahsilati",
  "subeler-arasi-aktarim", "demirbas-sayimi", "kullanim-raporlama",
  "satin-alma-onerisi", "gecikme-bildirimi"];
// KARSILAMA[s] = s sisteminin karsiladigini iddia ettigi yetenekler
export const KARSILAMA = {
  katalog: ["materyal-arama", "demirbas-sayimi"],
  odunc: ["odunc-verme", "iade-alma", "ayirtma", "gecikme-bildirimi"],
  ucretlendirme: ["ucret-hesaplama", "gecikme-bildirimi"],
  uyelik: ["uyelik-acma", "uye-dogrulama"],
  kimlik: ["uye-dogrulama"],
  "sube-yerel": ["iade-alma", "subeler-arasi-aktarim", "demirbas-sayimi"],
  kiosk: ["odunc-verme", "materyal-arama"],
  raporlama: ["kullanim-raporlama"],
  arsiv: [],
};
// VERI[v] = veri varligi; hangi sistem yaziyor, hangileri okuyor
export const VERI = {
  "uye-kaydi": { yazan: ["uyelik"], okuyan: ["odunc", "ucretlendirme", "kiosk", "raporlama"] },
  "kimlik-eslesmesi": { yazan: ["kimlik", "uyelik"], okuyan: ["odunc", "kiosk"] },
  "materyal-kaydi": { yazan: ["katalog"], okuyan: ["odunc", "kiosk", "sube-yerel", "raporlama"] },
  "nusha-durumu": { yazan: ["katalog", "odunc", "sube-yerel"], okuyan: ["kiosk", "raporlama"] },
  "odunc-hareketi": { yazan: ["odunc", "kiosk"], okuyan: ["ucretlendirme", "raporlama"] },
  "ucret-kaydi": { yazan: ["ucretlendirme"], okuyan: ["uyelik", "raporlama", "kiosk"] },
  "ceza-kurali": { yazan: ["ucretlendirme"], okuyan: ["odunc", "kiosk"] },
  "aktarim-istegi": { yazan: ["sube-yerel"], okuyan: ["odunc", "katalog"] },
  "eski-kayit": { yazan: [], okuyan: ["arsiv", "raporlama"] },
  "sayim-farki": { yazan: ["sube-yerel"], okuyan: [] },
};
export const SISTEMLER = Object.keys(SISTEM);
export const sahibi = (s) => SISTEM[s].sahip;
// bag = ayni veri varligi uzerinden yazan sistemden okuyan sisteme giden yonlu cift
export function baglar() {
  const b = new Map();
  for (const [v, d] of Object.entries(VERI))
    for (const y of d.yazan) for (const o of d.okuyan)
      if (y !== o) b.set(`${y}->${o}`, [...(b.get(`${y}->${o}`) ?? []), v]);
  return b;
}
```

#### Ölçüm

İkinci dosya ödünç alma sürecini on altı adım olarak modeller, sınıflandırmayı kuraldan türetir ve
iki sınırı aynı iki yüz işlemde koşturur. İnsan kararı gerektiren adımların ne sıklıkta ortaya
çıktığı, yanlış kararın kaç adımı geri döndürdüğü ve düzeltmenin kaç sistemde yazma gerektirdiği
seçilmiş değerlerdir (**KM10**). Eksik bilgi kalemi başına yanlış karar olasılığı 0,15 alındı;
eşiğin kaynağı budur ve duyarlılığı ayrıca basılıyor (**KM11**).

```js
// kurum/surec.mjs — odunc alma sureci: adim siniflari, otomasyon siniri ve siniri zorlamanin bedeli
import { VERI, sahibi } from "./model.mjs";

const sut = (s, n) => String(s).padEnd(n);
// ADIM — MODEL odunc alma sureci; sistem null ise adim yazilimin disinda gecer (banko, raf).
// eksik = adimin ihtiyac duydugu ama hicbir veri varliginda bulunmayan bilgi kalemi sayisi.
const ADIM = [
  { ad: "uye kart okutur", sistem: "kiosk", girdi: [] },
  { ad: "kimlik dogrulanir", sistem: "kimlik", girdi: ["kimlik-eslesmesi"] },
  { ad: "uyelik durumu sorgulanir", sistem: "uyelik", girdi: ["uye-kaydi"] },
  { ad: "odenmemis ucret kontrol edilir", sistem: "ucretlendirme", girdi: ["ucret-kaydi"] },
  { ad: "birikmis ucret vezneden tahsil edilir", sistem: null, girdi: [] },
  { ad: "materyal barkodu okutulur", sistem: "kiosk", girdi: ["materyal-kaydi"] },
  { ad: "nusha durumu sorgulanir", sistem: "katalog", girdi: ["nusha-durumu"] },
  { ad: "baska subedeki nusha icin aktarim acilir", sistem: "sube-yerel", girdi: ["nusha-durumu"],
    eksik: 2, siklik: 0.12, duzeltmeAdim: 3, duzeltme: ["sube-yerel", "katalog", "odunc"] },
  { ad: "materyalin hasar derecesi kaydedilir", sistem: "odunc", girdi: ["materyal-kaydi"],
    eksik: 1, siklik: 0.06, duzeltmeAdim: 2, duzeltme: ["odunc", "ucretlendirme"] },
  { ad: "odunc suresi hesaplanir", sistem: "odunc", girdi: ["ceza-kurali", "uye-kaydi"] },
  { ad: "arastirmaci uzatmasi taninir", sistem: "odunc", girdi: ["uye-kaydi"],
    eksik: 2, siklik: 0.04, duzeltmeAdim: 2, duzeltme: ["odunc", "uyelik"] },
  { ad: "eski kayittaki borc sorgulanir", sistem: "odunc", girdi: ["eski-kayit"],
    siklik: 0.09, duzeltmeAdim: 4, duzeltme: ["odunc", "ucretlendirme", "raporlama"] },
  { ad: "odunc kaydi yazilir", sistem: "odunc", girdi: ["uye-kaydi"] },
  { ad: "nusha durumu guncellenir", sistem: "odunc", girdi: ["nusha-durumu"] },
  { ad: "guvenlik etiketi devre disi birakilir", sistem: null, girdi: [] },
  { ad: "gecikme bildirimi planlanir", sistem: "odunc", girdi: ["odunc-hareketi", "ceza-kurali"] },
];
// Otomasyon sinirinin kurali: adim ancak butun girdileri yazani olan bir veri varligindaysa ve
// disarida kalan bilgi kalemi yoksa otomatiklestirilebilir.
const kaynaksiz = (a) => a.girdi.filter((v) => VERI[v].yazan.length === 0);
function sinifla(a) {
  if (a.sistem === null) return ["sistem-disi", "yazilimin disinda gecer"];
  if (a.eksik) return ["insan-karari", `${a.eksik} bilgi kalemi hicbir veride yok`];
  if (kaynaksiz(a).length) return ["insan-karari", `yazani olmayan veri: ${kaynaksiz(a)[0]}`];
  return ["otomatik", "-"];
}

console.log(sut("adim", 42) + sut("aktor", 15) + sut("sinif", 14) + "neden");
console.log("-".repeat(102));
for (const a of ADIM) {
  const [s, n] = sinifla(a);
  console.log(sut(a.ad, 42) + sut(a.sistem ?? "banko/raf", 15) + sut(s, 14) + n);
}

const sinif = (s) => ADIM.filter((a) => sinifla(a)[0] === s);
let enUzun = 0, akan = 0;
for (const a of ADIM) { akan = sinifla(a)[0] === "otomatik" ? akan + 1 : 0; enUzun = Math.max(enUzun, akan); }
const aktor = (a) => a.sistem ?? "banko/raf";
const sahip = (a) => (a.sistem ? sahibi(a.sistem) : "sube-yonetimi");
const elDegistirme = ADIM.slice(1).filter((a, i) => aktor(a) !== aktor(ADIM[i]));
const sahipAsan = ADIM.slice(1).filter((a, i) => sahip(a) !== sahip(ADIM[i]));
console.log(`\n${ADIM.length} adim: ${sinif("otomatik").length} otomatik, ` +
  `${sinif("insan-karari").length} insan karari, ${sinif("sistem-disi").length} sistem disi`);
console.log(`en uzun kesintisiz otomatik dizi: ${enUzun} adim`);
console.log(`el degistirme: ${elDegistirme.length}, bunlarin ${sahipAsan.length}'i sahip degistiriyor; ` +
  `surec ${new Set(ADIM.map(aktor)).size} aktor ve ${new Set(ADIM.map(sahip)).size} sahip dolasiyor`);

// ---- siniri zorlamak: insan karari gerektiren adimlar otomatiklestirilirse ----
const P = 0.15; // secilmis kural: eksik her bilgi kalemi icin yanlis karar olasiligi
const hata = (a) => 1 - (1 - P) ** (a.eksik ?? 1);
const uretec = (t) => { let s = t >>> 0; return () => (s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32; };
const rast = uretec(90210); // tohum gorunur; ayni tohum ayni sayilari verir
const N = 200;
const insan = sinif("insan-karari");
let olay = 0, yanlis = 0, geriAdim = 0, duzeltmeYazma = 0, sahipAsanDuzeltme = 0;
for (let i = 0; i < N; i++)
  for (const a of insan) {
    if (rast() >= a.siklik) continue;
    olay++;
    if (rast() >= hata(a)) continue;
    yanlis++; geriAdim += a.duzeltmeAdim; duzeltmeYazma += a.duzeltme.length;
    if (new Set(a.duzeltme.map(sahibi)).size > 1) sahipAsanDuzeltme++;
  }

console.log(`\n${N} odunc islemi, tohum 90210, yanlis karar olasiligi kalem basina ${P}`);
console.log(sut("sinir", 18) + sut("insan dokunusu", 16) + sut("yanlis karar", 14) +
  sut("geri donulen adim", 19) + "duzeltme yazmasi");
console.log("-".repeat(84));
console.log(sut("mevcut", 18) + sut(olay, 16) + sut(0, 14) + sut(0, 19) + 0);
console.log(sut("zorlanmis", 18) + sut(0, 16) + sut(yanlis, 14) + sut(geriAdim, 19) + duzeltmeYazma);
console.log(`\nzorlanmis sinir ${olay} insan dokunusundan kacinir, karsiliginda ${yanlis} yanlis ` +
  `karar uretir`);
console.log(`bu ${yanlis} geri donusun ${sahipAsanDuzeltme}'i birden cok sahibi ilgilendiriyor`);
console.log(`basabas: bir geri donus ${(olay / yanlis).toFixed(2)} insan dokunusundan pahaliysa ` +
  `mevcut sinir kazanir`);
console.log("olasilik duyarliligi (beklenen deger):");
for (const p of [0.1, 0.15, 0.2]) {
  const bek = insan.reduce((t, a) => t + N * a.siklik * (1 - (1 - p) ** (a.eksik ?? 1)), 0);
  const bekOlay = insan.reduce((t, a) => t + N * a.siklik, 0);
  console.log(`  p=${p.toFixed(2)} -> beklenen yanlis ${bek.toFixed(1)}, ` +
    `basabas ${(bekOlay / bek).toFixed(2)} dokunus`);
}
```

```
adim                                      aktor          sinif         neden
------------------------------------------------------------------------------------------------------
uye kart okutur                           kiosk          otomatik      -
kimlik dogrulanir                         kimlik         otomatik      -
uyelik durumu sorgulanir                  uyelik         otomatik      -
odenmemis ucret kontrol edilir            ucretlendirme  otomatik      -
birikmis ucret vezneden tahsil edilir     banko/raf      sistem-disi   yazilimin disinda gecer
materyal barkodu okutulur                 kiosk          otomatik      -
nusha durumu sorgulanir                   katalog        otomatik      -
baska subedeki nusha icin aktarim acilir  sube-yerel     insan-karari  2 bilgi kalemi hicbir veride yok
materyalin hasar derecesi kaydedilir      odunc          insan-karari  1 bilgi kalemi hicbir veride yok
odunc suresi hesaplanir                   odunc          otomatik      -
arastirmaci uzatmasi taninir              odunc          insan-karari  2 bilgi kalemi hicbir veride yok
eski kayittaki borc sorgulanir            odunc          insan-karari  yazani olmayan veri: eski-kayit
odunc kaydi yazilir                       odunc          otomatik      -
nusha durumu guncellenir                  odunc          otomatik      -
guvenlik etiketi devre disi birakilir     banko/raf      sistem-disi   yazilimin disinda gecer
gecikme bildirimi planlanir               odunc          otomatik      -

16 adim: 10 otomatik, 4 insan karari, 2 sistem disi
en uzun kesintisiz otomatik dizi: 4 adim
el degistirme: 10, bunlarin 9'i sahip degistiriyor; surec 8 aktor ve 5 sahip dolasiyor

200 odunc islemi, tohum 90210, yanlis karar olasiligi kalem basina 0.15
sinir             insan dokunusu  yanlis karar  geri donulen adim  duzeltme yazmasi
------------------------------------------------------------------------------------
mevcut            62              0             0                  0
zorlanmis         0               10            30                 27

zorlanmis sinir 62 insan dokunusundan kacinir, karsiliginda 10 yanlis karar uretir
bu 10 geri donusun 8'i birden cok sahibi ilgilendiriyor
basabas: bir geri donus 6.20 insan dokunusundan pahaliysa mevcut sinir kazanir
olasilik duyarliligi (beklenen deger):
  p=0.10 -> beklenen yanlis 9.1, basabas 6.83 dokunus
  p=0.15 -> beklenen yanlis 13.4, basabas 4.63 dokunus
  p=0.20 -> beklenen yanlis 17.5, basabas 3.54 dokunus
```

#### Sınır Nereden Geçiyor

On altı adımın onu otomatik, dördü insan kararı, ikisi sistem dışı. Bu üç sayı tek başına
otomasyon oranını verir ama sınırın **yerini** vermez. Yeri veren sayı, en uzun kesintisiz
otomatik dizinin uzunluğudur: dört adım. Süreç dört adım otomatik ilerliyor, sonra bankoya
düşüyor; iki adım daha otomatik gidiyor, sonra iki insan kararına takılıyor. Otomasyonun değeri
adım sayısında değil, kesintisiz dizinin uzunluğundadır — her kesinti bir bekleme, bir devir ve
yeniden başlama demektir.

Kurum ölçeğinde asıl sayı el değiştirmedir. On altı adım boyunca on kez aktör değişiyor ve bu on
değişimin dokuzunda **sahip de değişiyor**. Süreç sekiz aktör ve beş ayrı sahip dolaşıyor.
Bir sürecin kurumsal maliyeti buradan okunur: teknik olarak on altı adımlık bir akış, örgütsel
olarak dokuz sınır geçişidir.

İnsan kararı gerektiren dört adımın gerekçeleri aynı değil. Üçünde bilgi hiçbir veri varlığında
yok. Dördüncüsü farklıdır: eski kayıttaki borcun sorgulanması bir veri varlığına dayanıyor, ama o
veriyi yazan sistem yok. Sahipsiz veri, sürecin içinde bir insan kararı olarak geri dönüyor —
kurumsal mimarideki bir boşluk, süreçte bir personel adımına dönüşür.

#### Sınırı Zorlamanın Bedeli

İkinci tablo aynı iki yüz ödünç işlemini iki sınırla koşturuyor. **Mevcut sınırda** dört adım
personele bırakılıyor; iki yüz işlemde bu adımlar 62 kez ortaya çıkıyor ve 62 insan dokunuşu
harcanıyor. **Zorlanmış sınırda** dördü de otomatikleştiriliyor; insan dokunuşu sıfıra iniyor,
karşılığında yanlış kararlar başlıyor.

Tohumu 90210 olan üreteçle bu koşumda 10 yanlış karar çıktı; beklenen değer 13,4 olduğu için sayı
koşuma bağlıdır ve tohum değişirse değişir. On yanlış karar 30 adımı geri döndürüyor ve düzeltme
27 kez sistemde yazma gerektiriyor. Asıl kurumsal sayı sonuncusudur: on geri dönüşün **sekizi
birden çok sahibi** ilgilendiriyor. Yanlış otomatikleştirilen bir adımın bedeli tek bir ekranın
düzeltilmesi değil, iki ya da üç ayrı bütçenin sahibinin aynı kaydı uzlaştırmasıdır.

Karar buradan okunur: bir geri dönüşün uzlaştırılması 6,20 insan dokunuşundan pahalıysa mevcut
sınır kazanır. Bu sayı olasılığa duyarlıdır — eksik bilgi kalemi başına yanlış karar olasılığı
0,10 olduğunda başabaş 6,83 dokunuşa çıkıyor, 0,20 olduğunda 3,54'e iniyor. Otomasyon sınırını
zorlamak bir cesaret sorunu değil, bu iki sayının karşılaştırılmasıdır: kaçınılan dokunuş ve
üretilen geri dönüş.

#### Özet

- Bir süreç adımının üç alanı ölçülebilir: aktör, girdi kümesi, çıktı; gösterimin sembol kümesi
  bu alanların yanında ikincildir.
- Otomasyon sınırı kuraldan türetilir: adım ancak bütün girdileri yazanı olan bir veri
  varlığındaysa ve dışarıda kalan bilgi kalemi yoksa otomatiktir.
- Model süreçte 16 adımın 10'u otomatik, 4'ü insan kararı, 2'si sistem dışı; en uzun kesintisiz
  otomatik dizi 4 adım.
- Süreç 8 aktör ve 5 sahip dolaşıyor; 10 el değiştirmenin 9'unda sahip de değişiyor.
- Sınır zorlandığında 62 insan dokunuşundan kaçınılıyor, karşılığında bu koşumda 10 yanlış karar,
  30 geri dönülen adım ve 27 düzeltme yazması çıkıyor; geri dönüşlerin 8'i birden çok sahibi
  ilgilendiriyor ve başabaş noktası 6,20 dokunuştur.

#### Sonraki Adım

Bu ders tek bir yeteneğin tek bir sürecini açtı ve o sürecin hangi sistemlerden geçtiğini saydı.
Kurumda on üç yetenek var ve her birinin arkasında benzer bir zincir duruyor. Bir yetenek
değiştiğinde — ödünç süresi kuralı yenilendiğinde, üyelik koşulu değiştiğinde — hangi sistemlere
dokunulacağı, o sistemlerin hangi veriyi yazdığı ve o veriyi kimin okuduğu tek tek izlenmedikçe
bilinmez. Sonraki ders yetenek, sistem ve veri arasında bir izlenebilirlik zinciri kurar; bir
yeteneğin değişmesi durumunda dokunulacak sistem sayısını ve zincirin koptuğu yerleri sayar.

### Yetenek Haritalama

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/yetenek-haritalama

İş yeteneğinden onu karşılayan sisteme ve o sistemin yazdığı veriye uzanan izlenebilirlik zincirinin kurulması: bir yetenek değiştiğinde dokunulacak sistem ve sahip sayısı, kısa zincirle tam zincirin farkı ve zincirin koptuğu noktalar — izlenemeyen yetenek, yetim sistem, sahipsiz veri, okunmayan veri.

Önceki ders tek bir yeteneğin tek bir sürecini açtı ve o sürecin sekiz aktör ile beş sahip
dolaştığını saydı. Kurumda on üç yetenek var ve her birinin arkasında benzer bir zincir duruyor.
Bir yetenek değiştiğinde — ödünç süresi kuralı yenilendiğinde, üyelik koşulu değiştiğinde —
kimlerin haberdar edileceği soruldu mu diye bakılınca ortada bir liste yok: envanter hangi sistemin
hangi yeteneği karşıladığını söylüyor, ama o sistemin yazdığı veriyi kimin okuduğunu söylemiyor.
Bu ders o eksik halkayı ekler.

#### İzlenebilirlik Zinciri

**İzlenebilirlik**, bir iş yeteneğinden başlayıp onu gerçekleştiren yazılım parçalarına ve o
parçaların ürettiği veriye kesintisiz gidebilmektir. Zincir üç halkadan kurulur (**KM12**):
yetenek, o yeteneği karşıladığını iddia eden sistemler, o sistemlerin yazdığı veri varlıkları. Bir
halka daha eklenir: yazılan veriyi **okuyan** sistemler. Bu son halka tek sıçramayla sınırlı
tutuluyor; okuyanların yazdığı verilere kadar açılmıyor.

Zincirin ölçtüğü şey şudur: bir yeteneğin tanımı değiştiğinde dokunulacak sistemlerin kümesi.
Doğrudan halka o yeteneği karşılayan sistemlerdir; değişikliği onlar gerçekleştirir. Dolaylı
halka, değişen verinin okuyucularıdır; onlar kod değiştirmeyebilir ama değişikliği görmeleri
gerekir, çünkü okudukları alan başkalaşır. Koordinasyon turu, etkilenen ayrı sahip sayısının bir
eksiği alınıyor (**KM13**): bir sahip kendi içinde konuşmaz, her ek sahip bir uzlaşma turu ekler.

```js
// kurum/model.mjs — MODEL bolgesel kutuphane agi: sistemler, sahipler, yetenekler, veri.
// Kurgudur; gercek bir kurum, satici, urun ya da kisi anlatilmaz.
export const SISTEM = {
  katalog: { sahip: "dis-saglayici", butce: "hizmet-bedeli" },
  odunc: { sahip: "bt-birimi", butce: "ic-gelistirme" },
  ucretlendirme: { sahip: "bt-birimi", butce: "ic-gelistirme" },
  uyelik: { sahip: "uye-hizmetleri", butce: "uye-hizmetleri" },
  kimlik: { sahip: "belediye-bt", butce: "belediye" },
  "sube-yerel": { sahip: "sube-yonetimi", butce: "sube" },
  kiosk: { sahip: "sube-yonetimi", butce: "sube" },
  raporlama: { sahip: "yonetim-birimi", butce: "yonetim" },
  arsiv: { sahip: "yok", butce: "yok" },
};
// YETENEK — kurumun karsilamak zorunda oldugu is yetenekleri (sistemden bagimsiz liste)
export const YETENEK = ["materyal-arama", "odunc-verme", "iade-alma", "ayirtma",
  "uyelik-acma", "uye-dogrulama", "ucret-hesaplama", "ucret-tahsilati",
  "subeler-arasi-aktarim", "demirbas-sayimi", "kullanim-raporlama",
  "satin-alma-onerisi", "gecikme-bildirimi"];
// KARSILAMA[s] = s sisteminin karsiladigini iddia ettigi yetenekler
export const KARSILAMA = {
  katalog: ["materyal-arama", "demirbas-sayimi"],
  odunc: ["odunc-verme", "iade-alma", "ayirtma", "gecikme-bildirimi"],
  ucretlendirme: ["ucret-hesaplama", "gecikme-bildirimi"],
  uyelik: ["uyelik-acma", "uye-dogrulama"],
  kimlik: ["uye-dogrulama"],
  "sube-yerel": ["iade-alma", "subeler-arasi-aktarim", "demirbas-sayimi"],
  kiosk: ["odunc-verme", "materyal-arama"],
  raporlama: ["kullanim-raporlama"],
  arsiv: [],
};
// VERI[v] = veri varligi; hangi sistem yaziyor, hangileri okuyor
export const VERI = {
  "uye-kaydi": { yazan: ["uyelik"], okuyan: ["odunc", "ucretlendirme", "kiosk", "raporlama"] },
  "kimlik-eslesmesi": { yazan: ["kimlik", "uyelik"], okuyan: ["odunc", "kiosk"] },
  "materyal-kaydi": { yazan: ["katalog"], okuyan: ["odunc", "kiosk", "sube-yerel", "raporlama"] },
  "nusha-durumu": { yazan: ["katalog", "odunc", "sube-yerel"], okuyan: ["kiosk", "raporlama"] },
  "odunc-hareketi": { yazan: ["odunc", "kiosk"], okuyan: ["ucretlendirme", "raporlama"] },
  "ucret-kaydi": { yazan: ["ucretlendirme"], okuyan: ["uyelik", "raporlama", "kiosk"] },
  "ceza-kurali": { yazan: ["ucretlendirme"], okuyan: ["odunc", "kiosk"] },
  "aktarim-istegi": { yazan: ["sube-yerel"], okuyan: ["odunc", "katalog"] },
  "eski-kayit": { yazan: [], okuyan: ["arsiv", "raporlama"] },
  "sayim-farki": { yazan: ["sube-yerel"], okuyan: [] },
};
export const SISTEMLER = Object.keys(SISTEM);
export const sahibi = (s) => SISTEM[s].sahip;
// bag = ayni veri varligi uzerinden yazan sistemden okuyan sisteme giden yonlu cift
export function baglar() {
  const b = new Map();
  for (const [v, d] of Object.entries(VERI))
    for (const y of d.yazan) for (const o of d.okuyan)
      if (y !== o) b.set(`${y}->${o}`, [...(b.get(`${y}->${o}`) ?? []), v]);
  return b;
}
```

#### Ölçüm

İkinci dosya her yetenek için zinciri kurar, iki zincir biçimini karşılaştırır ve kopma
noktalarını sayar.

```js
// kurum/izleme.mjs — yetenek -> sistem -> veri -> okuyan zinciri; degisimin dokundugu sistem sayisi
import { SISTEM, YETENEK, KARSILAMA, VERI, SISTEMLER, sahibi } from "./model.mjs";

const sut = (s, n) => String(s).padEnd(n);
const karsilayan = (y) => SISTEMLER.filter((s) => KARSILAMA[s].includes(y));
const yazdigi = (s) => Object.entries(VERI).filter(([, d]) => d.yazan.includes(s)).map(([v]) => v);
const sahipKumesi = (l) => new Set(l.map(sahibi).filter((o) => o !== "yok"));

function zincir(y) {
  const dogrudan = karsilayan(y);
  const veri = [...new Set(dogrudan.flatMap(yazdigi))];
  const dolayli = [...new Set(veri.flatMap((v) => VERI[v].okuyan))].filter((s) => !dogrudan.includes(s));
  return { dogrudan, veri, dolayli, tum: [...dogrudan, ...dolayli] };
}

console.log(sut("is yetenegi", 24) + sut("sistem", 8) + sut("veri", 6) + sut("okuyan", 8) +
  sut("dokunulan", 11) + sut("sahip", 7) + "koordinasyon turu");
console.log("-".repeat(88));
let kisaSistem = 0, tamSistem = 0, kisaTur = 0, tamTur = 0;
const izlenemeyen = [];
for (const y of YETENEK) {
  const z = zincir(y);
  if (z.dogrudan.length === 0) { izlenemeyen.push(y); continue; }
  const sahipTam = sahipKumesi(z.tum).size, sahipKisa = sahipKumesi(z.dogrudan).size;
  kisaSistem += z.dogrudan.length; tamSistem += z.tum.length;
  kisaTur += Math.max(0, sahipKisa - 1); tamTur += Math.max(0, sahipTam - 1);
  console.log(sut(y, 24) + sut(z.dogrudan.length, 8) + sut(z.veri.length, 6) +
    sut(z.dolayli.length, 8) + sut(z.tum.length, 11) + sut(sahipTam, 7) + (sahipTam - 1));
}

const izlenen = YETENEK.length - izlenemeyen.length;
console.log(`\n${izlenen}/${YETENEK.length} yetenek izlenebiliyor; izlenemeyen: ${izlenemeyen.join(", ")}`);
console.log(sut("zincir bicimi", 26) + sut("dokunulan sistem", 18) + sut("yetenek basina", 16) +
  "koordinasyon turu");
console.log("-".repeat(80));
console.log(sut("kisa (yetenek->sistem)", 26) + sut(kisaSistem, 18) +
  sut((kisaSistem / izlenen).toFixed(2), 16) + kisaTur);
console.log(sut("tam (->veri->okuyan)", 26) + sut(tamSistem, 18) +
  sut((tamSistem / izlenen).toFixed(2), 16) + tamTur);
console.log(`fark: ${tamSistem - kisaSistem} sistem ve ${tamTur - kisaTur} koordinasyon turu ` +
  `kisa zincirde gorunmuyor (${((tamSistem - kisaSistem) / tamSistem * 100).toFixed(0)}%)`);

const enGenis = YETENEK.filter((y) => karsilayan(y).length)
  .map((y) => [y, zincir(y).tum.length]).sort((a, b) => b[1] - a[1])[0];
console.log(`en genis zincir: ${enGenis[0]} -> ${enGenis[1]} sistem`);

// ---- zincirin koptugu yerler ----
const kopma = [
  ["izlenemeyen yetenek", izlenemeyen],
  ["yetim sistem (yetenege baglanamiyor)", SISTEMLER.filter((s) => KARSILAMA[s].length === 0)],
  ["sahipsiz sistem", SISTEMLER.filter((s) => SISTEM[s].sahip === "yok")],
  ["sahipsiz veri (yazani yok)", Object.keys(VERI).filter((v) => VERI[v].yazan.length === 0)],
  ["okunmayan veri", Object.keys(VERI).filter((v) => VERI[v].okuyan.length === 0)],
];
console.log("");
console.log(sut("kopma turu", 38) + sut("sayi", 6) + "kalem");
console.log("-".repeat(78));
for (const [t, l] of kopma) console.log(sut(t, 38) + sut(l.length, 6) + (l.join(", ") || "-"));
const toplam = kopma.reduce((t, [, l]) => t + l.length, 0);
const erisilen = new Set(YETENEK.filter((y) => karsilayan(y).length).flatMap((y) => zincir(y).veri));
console.log(`\ntoplam ${toplam} kopma noktasi; ` +
  `${Object.keys(VERI).length} veri varliginin ${erisilen.size}'ine bir yetenekten erisilebiliyor`);
```

```
is yetenegi             sistem  veri  okuyan  dokunulan  sahip  koordinasyon turu
----------------------------------------------------------------------------------------
materyal-arama          2       3     4       6          4      3
odunc-verme             2       2     2       4          3      2
iade-alma               2       4     4       6          4      3
ayirtma                 1       2     3       4          3      2
uyelik-acma             1       2     4       5          4      3
uye-dogrulama           2       2     4       6          5      4
ucret-hesaplama         1       2     4       5          4      3
subeler-arasi-aktarim   1       3     4       5          4      3
demirbas-sayimi         2       4     3       5          4      3
kullanim-raporlama      1       0     0       1          1      0
gecikme-bildirimi       2       4     3       5          4      3

11/13 yetenek izlenebiliyor; izlenemeyen: ucret-tahsilati, satin-alma-onerisi
zincir bicimi             dokunulan sistem  yetenek basina  koordinasyon turu
--------------------------------------------------------------------------------
kisa (yetenek->sistem)    17                1.55            5
tam (->veri->okuyan)      52                4.73            29
fark: 35 sistem ve 24 koordinasyon turu kisa zincirde gorunmuyor (67%)
en genis zincir: materyal-arama -> 6 sistem

kopma turu                            sayi  kalem
------------------------------------------------------------------------------
izlenemeyen yetenek                   2     ucret-tahsilati, satin-alma-onerisi
yetim sistem (yetenege baglanamiyor)  1     arsiv
sahipsiz sistem                       1     arsiv
sahipsiz veri (yazani yok)            1     eski-kayit
okunmayan veri                        1     sayim-farki

toplam 6 kopma noktasi; 10 veri varliginin 9'ine bir yetenekten erisilebiliyor
```

#### Değişimin Dokunduğu Sistem Sayısı

Kısa zincir yalnız karşılayan sistemleri gösteriyor: on bir izlenebilir yetenek için toplam 17
sistem, yetenek başına 1,55. Tam zincir veriyi ve okuyucuları da katıyor: 52 sistem, yetenek
başına 4,73. Aradaki 35 sistem, kısa zincire bakan birinin haberdar etmeyi hiç düşünmeyeceği
sistemlerdir — dokunulacak sistemlerin **%67'si** ilk halkada görünmüyor.

Koordinasyon turu farkı daha keskin: kısa zincirde toplam 5, tam zincirde 29. Kurum ölçeğinde
maliyeti üreten şey kod değişikliğinin büyüklüğü değil, bu 24 fazla turdur; her tur ayrı bir
bütçenin sahibiyle yapılan bir uzlaşmadır.

Tablonun iki satırı sınırı gösteriyor. Üye doğrulama yeteneği iki sistemle karşılanıyor ama zinciri
altı sisteme ve beş sahibe yayılıyor; bu kurumdaki en pahalı değişiklik odur, çünkü karşılayan iki
sistemin sahibi bile farklı. Karşı uçta kullanım raporlaması var: tek sistem, sıfır veri, sıfır
okuyan, sıfır koordinasyon turu. Raporlama hiçbir veri yazmıyor, yalnız okuyor; bu yüzden onda
yapılan değişiklik hiçbir yere yayılmıyor. Bir sistemin değişim maliyetini belirleyen şey
büyüklüğü değil, **yazdığı verinin kaç okuyucusu olduğudur**.

#### Zincirin Koptuğu Yerler

Zincir her yerde kurulamıyor; altı kopma noktası var ve her birinin farklı bir sonucu var.

**İzlenemeyen yetenek** iki tane: ücret tahsilatı ve satın alma önerisi. İkisi de yapılıyor ama
hiçbir sisteme bağlanamıyor, dolayısıyla değiştiklerinde dokunulacak sistem listesi boş çıkıyor.
Bu, değişikliğin bedava olduğu anlamına gelmez; bedelin sistem dışında, bankoda ve elde tutulan
çizelgelerde ödendiği anlamına gelir.

**Yetim sistem** ve **sahipsiz sistem** aynı kaleme, arşive denk geliyor: hiçbir yeteneğe
bağlanamıyor ve sahibi yazılı değil. Böyle bir sistem izlenebilirlik tablosunda hiç görünmez;
kapatma kararı da, sürdürme kararı da savunmasız kalır.

**Sahipsiz veri** eski kayıttır — okunuyor ama yazanı yok; on veri varlığının dokuzuna bir
yetenekten erişilebiliyor, erişilemeyen tek varlık budur. Önceki derste görüldüğü gibi bu boşluk
süreçte bir insan kararı olarak geri döndü. **Okunmayan veri** ise sayım farkıdır: yazılıyor,
kimse okumuyor. İkisi zincirin iki ucundaki kopmalardır ve ikisi de aynı şeyi söyler — bir veri
varlığının değeri, iki ucunun da bağlı olmasındadır.

#### Özet

- İzlenebilirlik zinciri dört halkadır: yetenek, karşılayan sistemler, o sistemlerin yazdığı veri,
  o veriyi okuyan sistemler; koordinasyon turu etkilenen ayrı sahip sayısının bir eksiğidir.
- Model kurumdaki 13 yeteneğin 11'i izlenebiliyor; kalan ikisi hiçbir sisteme bağlanamıyor.
- Kısa zincir yetenek başına 1,55 sistem gösterirken tam zincir 4,73 gösteriyor; dokunulacak
  sistemlerin %67'si ilk halkada görünmüyor ve koordinasyon turu 5'ten 29'a çıkıyor.
- En çok sahip ve koordinasyon turu isteyen zincir üye doğrulamadır: 6 sistem, 5 sahip, 4 tur. En dar zincir kullanım
  raporlamasıdır: 1 sistem, 0 okuyan, 0 tur — çünkü hiçbir veri yazmıyor.
- Zincir 6 noktada kopuyor: 2 izlenemeyen yetenek, 1 yetim sistem, 1 sahipsiz sistem, 1 sahipsiz
  veri, 1 okunmayan veri; 10 veri varlığının 9'una bir yetenekten erişilebiliyor.

#### Sonraki Adım

Bu konu kurumu dört adımda modelledi: sistemler ile yetenekler eşlendi, aynı model iki çerçeve
biçiminde belgelendi, bir iş süreci adım adım sınıflandırıldı ve yetenekten veriye izlenebilirlik
kuruldu. Artık hangi yeteneğin hangi sistemde durduğu ve bir değişikliğin kaç sistemi ilgilendirdiği
görünür. Görünmeyen tek şey kaldı ve bu kursun ikinci yarısının konusu odur: sistemlerin birbirine
**nasıl** bağlandığı. Zincirde "şu sistem şu veriyi okuyor" diye geçen her halkanın arkasında bir
taşıma biçimi var — verinin hangi yoldan geçtiği, ne sıklıkta yenilendiği, kopmasından kimin
sorumlu olduğu. Çerçeve dersinde iki sorunun hiçbir biçimde yanıtlanamaması boşuna değildi:
model bu alanları hiç taşımıyordu. Sonraki ders bağın kendisini bir seçim nesnesine çevirir ve
aynı bağ kümesini farklı taşıma biçimleriyle kurup maliyetini sayar.

## Tümleştirme

Kurum içindeki sistemlerin birbirine bağlanması: dosya aktarımı, ortak veritabanı, uzak çağrı ve mesajlaşmanın bağ başına maliyeti, merkezî tümleştirme noktasının artıları ile darboğaz riski, kaynak sistem ve altın kayıtla ana veri yönetimi, çözümleme yükünü işletim yükünden ayıran dönüştürme hatları, değiştirilemeyen eski sistemlerin sarmalanarak aşamalı olarak devredilmesi ve toplam sahip olma maliyetiyle bağımlılık riskini karşılaştıran al veya geliştir kararı.

### Tümleştirme Kalıpları

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/tumlestirme-kaliplari

Aynı bağın dört kalıpla kurulup karşılaştırılması: sorgu başına kaynak sisteme giden tur ve istek, tazelik penceresi, tazeleme başına taşınan kayıt, tüketici koduna sızan fiziksel şema adı sayısı ve kaynak tek sütununu yeniden adlandırdığında kırılan bağ ile koordine edilecek sahip sayısı.

Önceki konu kurumun yeteneklerini çıkardı ve her yeteneğin hangi sistemde durduğunu gösterdi. O
eşleme bir soruyu hiç sormadı: sistemler birbirine nasıl bağlanıyor. Bir yetenek bir sistemde
duruyorsa, aynı veriye ihtiyaç duyan ikinci sistem onu hangi yoldan, hangi sıklıkta ve kimin
sorumluluğunda alıyor. Bu ders tek bir bağı alır, onu dört ayrı kalıpla kurar ve dördünü aynı
ölçülerle karşılaştırır.

Kurum ölçeğinde ölçü birimi bağdır. Tek bir sistemin içinde bir çağrının nereye gittiği o sistemin
sahibinin kararıdır; kurum ölçeğinde bağın iki ucunda iki ayrı sahip, iki ayrı bütçe ve iki ayrı
takvim durur. Bu yüzden burada sayılan şey gecikme kadar, bağın kime ne borç yüklediğidir.

**TM1 — kurum kurgudur ve `node` içinde bir veri yapısı olarak yazılır.** Sistemler, sahipleri ve
aralarındaki bağlar bir dizi olarak durur; ölçülen bağ o dizinin bir satırıdır.

**TM2 — tazeleme dönemi zamanlayıcı yerine `tik` ile modellenir.** Gerekçe: dönemin saat karşılığı
(dakika, saat, gece) kalıbın kendisiyle değil işletim kararıyla belirlenir; ölçülen nicelik "kaç
tazeleme dönemi sonra taze" olduğudur ve bu sayı dönemin uzunluğundan bağımsızdır.

**TM3 — mesajlaşma taşıyıcısı bir ekleme kütüğü olarak modellenir.** Kuyruk mekaniği, teslim
garantisi ve tüketici rekabeti Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunda ölçüldü;
burada ölçülen şey taşıyıcının kendisi değil, bağın kaynağa ve sahibine ödettiğidir.

#### Kurum ve Ölçülen Bağ

Bölgesel kütüphane ağı kurgu bir kurumdur. Katalog sistemi dışarıdan alınmıştır; ödünç,
ücretlendirme ve bildirim servisleri içeride yazılmıştır; üyelik ayrı bir birimin, kimlik
doğrulama belediyenin elindedir. Bu derste ölçülen tek varlık nüsha durumudur: bir kitap
nüshasının rafta olup olmadığı. Bu veriyi katalog yazar, beş sistem okur.

```js
// kurum.mjs — bolgesel kutuphane agi: kurgu bir kurum modeli; dogrudan kosunca kendini yazar
export const SISTEM = [
  { ad: "katalog", sahip: "katalog birimi", disaridan: 1 },
  { ad: "odunc", sahip: "ic gelistirme", disaridan: 0 },
  { ad: "ucretlendirme", sahip: "ic gelistirme", disaridan: 0 },
  { ad: "bildirim", sahip: "ic gelistirme", disaridan: 0 },
  { ad: "raporlama", sahip: "yonetim birimi", disaridan: 0 },
  { ad: "sube-arayuzu", sahip: "sube birimi", disaridan: 0 },
  { ad: "uyelik", sahip: "uyelik birimi", disaridan: 0 },
  { ad: "kimlik", sahip: "belediye bilgi islem", disaridan: 1 },
];
// nusha durumunu katalogdan okuyan baglar; her bag bir kalipla kurulmustur (model)
export const BAG = [
  { hedef: "odunc", kalip: "ortak-db" },
  { hedef: "ucretlendirme", kalip: "ortak-db" },
  { hedef: "raporlama", kalip: "dosya" },
  { hedef: "sube-arayuzu", kalip: "uzak-cagri" },
  { hedef: "bildirim", kalip: "mesaj" },
];
export const sahip = (a) => SISTEM.find((s) => s.ad === a).sahip;

if (process.argv[1].endsWith("kurum.mjs")) {
  console.log(`${SISTEM.length} sistem, ${new Set(SISTEM.map((s) => s.sahip)).size} ayri sahip, ` +
    `${SISTEM.filter((s) => s.disaridan).length} sistem disaridan alinmis`);
  console.log(`katalogdan cikan bag: ${BAG.length}, dokunulan sahip: ` +
    `${new Set(BAG.map((b) => sahip(b.hedef))).size}`);
  for (const k of ["ortak-db", "dosya", "uzak-cagri", "mesaj"]) {
    console.log(`  ${k.padEnd(11)}${BAG.filter((b) => b.kalip === k).length} bag`);
  }
}
```

```
8 sistem, 6 ayri sahip, 2 sistem disaridan alinmis
katalogdan cikan bag: 5, dokunulan sahip: 3
  ortak-db   2 bag
  dosya      1 bag
  uzak-cagri 1 bag
  mesaj      1 bag
```

Kaynak sistem nüsha tablosunun sahibidir ve tabloya dört yoldan erişim verir: tek kaydı yayın
biçiminde döndüren bir uç, aynı biçimde bir anlık görüntü, fiziksel tablonun kopyasını çıkaran bir
döküm ve her değişiklikte yayın biçiminde bir satır eklenen kütük. Fiziksel sütun adları
`SEMA` içinde durur ve yalnız kaynağın kendi kodunda okunur.

```js
// katalog.mjs — nusha tablosunun sahibi olan kaynak sistem; <port>; uzun omurlu surec
import { createServer } from "node:http";
import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
const [port] = process.argv.slice(2);
if (!port) { console.log("kullanim: node katalog.mjs <port>"); process.exit(1); }
const IS = 20;                                   // katalogun bir istegi karsilama suresi (ms)
const SEMA = { durum: "durum", sube: "subeKodu" };   // fiziksel sutun adlari; katalogun malidir
const yaz = (s) => writeFileSync("katalog.db", s.map((r) => JSON.stringify(r)).join("\n") + "\n");
const oku = () => readFileSync("katalog.db", "utf8").split("\n").filter(Boolean).map(JSON.parse);
const yayin = (r) => ({ nushaId: r.nushaId, sube: r[SEMA.sube],
  uygun: r[SEMA.durum] === "rafta" });           // disari verilen bicim; katalogun sozudur
if (!existsSync("katalog.db")) {
  yaz([...Array(200).keys()].map((i) => ({ nushaId: 401 + i, subeKodu: 1 + (i % 4),
    durum: i % 5 === 0 ? "oduncte" : "rafta", basimYili: 1990 + (i % 30) })));
}
let yuk = 0;                                     // kaynak sistemin gordugu istek sayisi

createServer(async (istek, yanit) => {
  const u = new URL(istek.url, "http://y");
  if (u.pathname === "/yuk") { yanit.end(String(yuk)); return; }
  yuk += 1;
  await new Promise((c) => setTimeout(c, IS));
  const id = Number(u.searchParams.get("id"));
  if (u.pathname === "/nusha") {                 // uzak cagri: tek kayit, yayin bicimi
    yanit.end(JSON.stringify(yayin(oku().find((r) => r.nushaId === id))));
  } else if (u.pathname === "/anlik") {          // mesaj tuketicisinin ilk dolumu, yayin bicimi
    yanit.end(JSON.stringify(oku().map(yayin)));
  } else if (u.pathname === "/doku") {           // dosya aktarimi: fiziksel tablonun kopyasi
    const s = oku();
    writeFileSync("katalog.doku", s.map((r) => JSON.stringify(r)).join("\n") + "\n");
    yanit.end(String(s.length));
  } else if (u.pathname === "/degistir") {       // katalogun kendi yazma yolu
    const s = oku(), r = s.find((x) => x.nushaId === id);
    r[SEMA.durum] = u.searchParams.get("durum");
    yaz(s);
    appendFileSync("katalog.olay", JSON.stringify(yayin(r)) + "\n");
    yanit.end("tamam");
  } else if (u.pathname === "/goc") {            // katalog kendi sutununu yeniden adlandirir
    yaz(oku().map((r) => { const { [SEMA.durum]: d, ...k } = r; return { ...k, nushaDurumu: d }; }));
    SEMA.durum = "nushaDurumu";
    yanit.end("tamam");
  } else yanit.end("yok");
}).listen(Number(port));
```

#### Aynı Bağın Dört Kurulumu

Tüketici tek bir kaynak dosyadan koşar ve kalıbı komut satırından alır. Dört bölümün her biri iki
işlev tanımlar: sorguyu yanıtlayan `SOR` ve tazeleme dönemini temsil eden `TIK`. Bölümler
işaretli olduğu için hangi kalıbın hangi adı okuduğu koddan sayılabilir.

```js
// odunc.mjs — tuketici; <kalip: ortak-db|dosya|uzak-cagri|mesaj> <port> <katalog-port>
import { createServer } from "node:http";
import { existsSync, readFileSync } from "node:fs";
const [kalip, port, kp] = process.argv.slice(2);
if (!port) { console.log("kullanim: node odunc.mjs <kalip> <port> <katalog-port>"); process.exit(1); }
const K = `http://127.0.0.1:${kp}`;
const satir = (d) => readFileSync(d, "utf8").split("\n").filter(Boolean).map(JSON.parse);
const yerel = new Map();                         // tuketicinin kendi kopyasi
let okunan = 0;
const SOR = {}, TIK = {};                        // TIK: tazeleme donemini modelleyen tetik

// --- ortak-db --- tuketici kaynagin fiziksel tablosunu dogrudan okur
SOR["ortak-db"] = (id) => satir("katalog.db").find((r) => r.nushaId === id).durum === "rafta";
TIK["ortak-db"] = () => 0;

// --- dosya --- kaynak fiziksel tabloyu doker, tuketici doku dosyasini bastan okur
SOR["dosya"] = (id) => yerel.get(id);
TIK["dosya"] = async () => {
  await fetch(`${K}/doku`);
  const s = satir("katalog.doku");
  for (const r of s) yerel.set(r.nushaId, r.durum === "rafta");
  return s.length;
};

// --- uzak-cagri --- her sorgu kaynagin yayin bicimini cagirir
SOR["uzak-cagri"] = async (id) => (await (await fetch(`${K}/nusha?id=${id}`)).json()).uygun;
TIK["uzak-cagri"] = () => 0;

// --- mesaj --- ilk dolum yayin bicimindedir, sonra yalniz degisiklik satirlari okunur
SOR["mesaj"] = (id) => yerel.get(id);
TIK["mesaj"] = () => {
  if (!existsSync("katalog.olay")) return 0;
  const s = satir("katalog.olay");
  let n = 0;
  while (okunan < s.length) { yerel.set(s[okunan].nushaId, s[okunan].uygun); okunan += 1; n += 1; }
  return n;
};
if (kalip === "mesaj") for (const r of await (await fetch(`${K}/anlik`)).json()) yerel.set(r.nushaId, r.uygun);

// --- ortak --- kalipten bagimsiz servis yuzeyi
createServer(async (istek, yanit) => {
  const u = new URL(istek.url, "http://y");
  if (u.pathname === "/tik") { yanit.end(String(await TIK[kalip]())); return; }
  yanit.end(String(await SOR[kalip](Number(u.searchParams.get("id")))));
}).listen(Number(port));
```

#### Ölçüm

Araç üç aşamada koşar. Önce her tüketiciye yüz sorgu gönderip sorgu başına turu ve bu sırada
kaynak sisteme ulaşan istek sayısını sayar. Sonra kaynakta tek bir nüshanın durumunu değiştirir ve
tüketiciye iki kez sorar: tikten önce ve tikten sonra. Son aşamada kaynak kendi sütununu yeniden
adlandırır ve dört tüketicinin de aynı soruya doğru yanıt verip vermediğine bakılır. Tüketici
kodundaki ad sayımı çalışan süreçlerden değil, kaynak metinden okunur.

```js
// olc.mjs — ayni bagi dort kalipla olcer; <katalog-port> <dort tuketici portu>
import { readFileSync } from "node:fs";
import { BAG, sahip } from "./kurum.mjs";
const arg = process.argv.slice(2);
if (arg.length < 5) { console.log("kullanim: node olc.mjs <katalog-port> <p1> <p2> <p3> <p4>"); process.exit(1); }
const [kp, ...port] = arg;
const KALIP = ["ortak-db", "dosya", "uzak-cagri", "mesaj"];
const UC = Object.fromEntries(KALIP.map((k, i) => [k, `http://127.0.0.1:${port[i]}`]));
const K = `http://127.0.0.1:${kp}`, IS = 20, SORGU = 100;
const metin = (u) => fetch(u).then((y) => y.text());
const sor = (k, id) => metin(`${UC[k]}/sor?id=${id}`);
const tik = (k) => metin(`${UC[k]}/tik`).then(Number);
const o = {};
for (const k of KALIP) { o[k] = {}; await tik(k); }          // ilk dolum, olcumden once

for (const k of KALIP) {                                     // gecikme ve kaynagin gordugu yuk
  const y0 = Number(await metin(`${K}/yuk`));
  const t = performance.now();
  for (let i = 0; i < SORGU; i += 1) await sor(k, 401 + (i % 200));
  o[k].tur = Math.round((performance.now() - t) / SORGU / IS);
  o[k].yuk = Number(await metin(`${K}/yuk`)) - y0;
}
await metin(`${K}/degistir?id=402&durum=oduncte`);           // kaynakta tek kayit degisir
for (const k of KALIP) {
  const once = await sor(k, 402);
  o[k].kayit = await tik(k);
  o[k].pencere = once === "false" ? 0 : (await sor(k, 402)) === "false" ? 1 : -1;
}
const bolum = {};                                            // kalip basina tuketici kodu
for (const p of readFileSync("odunc.mjs", "utf8").split(/^\/\/ --- /m).slice(1)) {
  bolum[p.slice(0, p.indexOf(" "))] = p;
}
const FIZIKSEL = ["katalog.db", "katalog.doku", "durum", "rafta"];   // kaynagin ic semasi
const YAYIN = ["/nusha", "/anlik", "katalog.olay", "uygun"];         // kaynagin verdigi soz
const say = (m, l) => l.filter((a) => m.includes(a)).length;
await metin(`${K}/goc`);                                     // kaynak kendi sutununu adlandirir
for (const k of KALIP) { await tik(k); o[k].dogru = (await sor(k, 403)) === "true"; }

console.log(`${"kalip".padEnd(12)}${"tur".padStart(5)}${"kaynak istegi".padStart(15)}` +
  `${"tazelik tik".padStart(13)}${"tik kaydi".padStart(11)}${"fiziksel ad".padStart(13)}` +
  `${"yayin adi".padStart(11)}${"goc sonrasi".padStart(13)}`);
for (const k of KALIP) {
  console.log(`${k.padEnd(12)}${String(o[k].tur).padStart(5)}${String(o[k].yuk).padStart(15)}` +
    `${String(o[k].pencere).padStart(13)}${String(o[k].kayit).padStart(11)}` +
    `${String(say(bolum[k], FIZIKSEL)).padStart(13)}${String(say(bolum[k], YAYIN)).padStart(11)}` +
    `${(o[k].dogru ? "dogru" : "yanlis").padStart(13)}`);
}
const kirik = BAG.filter((b) => !o[b.kalip].dogru);
console.log(`tek sutun adi degisti: ${kirik.length}/${BAG.length} bag kirildi ` +
  `(${kirik.map((b) => b.hedef).join(", ")}); koordine edilecek sahip ` +
  `${new Set(kirik.map((b) => sahip(b.hedef))).size}/${new Set(BAG.map((b) => sahip(b.hedef))).size}`);
```

```bash
rm -f katalog.db katalog.doku katalog.olay
node katalog.mjs 8981 & K=$!
sleep 0.6
node odunc.mjs ortak-db   8982 8981 & A=$!
node odunc.mjs dosya      8983 8981 & B=$!
node odunc.mjs uzak-cagri 8984 8981 & C=$!
node odunc.mjs mesaj      8985 8981 & D=$!
sleep 0.8
node olc.mjs 8981 8982 8983 8984 8985
kill $K $A $B $C $D
```

```
kalip         tur  kaynak istegi  tazelik tik  tik kaydi  fiziksel ad  yayin adi  goc sonrasi
ortak-db        0              0            0          0            3          0       yanlis
dosya           0              0            1        200            3          0       yanlis
uzak-cagri      1            100            0          0            0          2        dogru
mesaj           0              0            1          1            0          3        dogru
tek sutun adi degisti: 3/5 bag kirildi (odunc, ucretlendirme, raporlama); koordine edilecek sahip 2/3
```

#### Gecikme, Yük ve Tazelik

İlk üç kolon kalıpların yüzeyde neye benzediğini veriyor. Uzak çağrı her sorguda kaynağa gidiyor:
sorgu başına bir tur ve yüz sorguda yüz istek. Diğer üç kalıpta sorgu turu sıfır, çünkü yanıt
tüketicinin kendi tarafından geliyor; kaynak sistem yüz sorgunun hiçbirini görmüyor.

Tazelik kolonu bu kazancın karşılığını gösteriyor. Ortak veritabanı ile uzak çağrıda kaynakta
yapılan değişiklik tüketiciye aynı anda yansıyor; iki kalıpta da tazelik penceresi sıfır tiktir.
Dosya aktarımı ve mesajlaşmada değişiklik ancak bir tazeleme döneminden sonra görünüyor. Aradaki
fark dördüncü kolonda: dosya aktarımı tek bir nüshanın durumu değiştiği hâlde her tazelemede iki
yüz kaydın tamamını taşıyor, mesajlaşma bir kayıt taşıyor. Aynı tazelik penceresi, iki yüz kat
farklı taşıma hacmiyle satın alınıyor. Kaynak sisteme düşen iş de buradan çıkıyor: dosya aktarımı
sorgu başına sıfır istek üretir ama her dönemde tabloyu bir baştan sona okur.

Buradan tek başına bir sıralama çıkmıyor. Uzak çağrı tazelik penceresini sıfırlar ve kaynağın
yükünü sorgu sayısına bağlar; dosya aktarımı yükü dönem sayısına bağlar ve tazeliği feda eder;
mesajlaşma dönem sayısına bağlı kalıp taşıma hacmini değişiklik sayısına indirir. Ortak
veritabanı hepsinden ucuz görünüyor: sıfır tur, sıfır istek, sıfır pencere. Bedeli sonraki iki
kolonda duruyor.

#### Sahiplik Sızıntısı

Beşinci ve altıncı kolon aynı bağı sahiplik açısından ölçüyor. Ortak veritabanı ve dosya aktarımı
kalıplarında tüketici kodu kaynağın fiziksel şemasından üç ad taşıyor: tablonun adı, sütunun adı
ve o sütunun anlamlı olduğu değer. Üçüncü ad en pahalısıdır, çünkü bir ad değil bir kuraldır.
"Rafta" değerinin uygunluk demek olduğu bilgisi katalog biriminin işletme kuralıdır ve o kural
tüketicinin kodunda ikinci bir kopya olarak durur. Katalog yarın üçüncü bir durum değeri eklerse,
kaynak kod hiç değişmediği hâlde tüketicinin yanıtı yanlışlaşır.

Uzak çağrı ve mesajlaşma kalıplarında fiziksel ad sayısı sıfırdır. Tüketici kaynağın tablosunu
değil, kaynağın dışarıya verdiği biçimi okur; uygunluk kararı kaynağın kodunda tek bir yerde
hesaplanır. Altıncı kolondaki adlar bir kayıp değil, bir sözleşmedir: kaynak sistem o adları
değiştirmemeyi taahhüt etmiştir ve karşılığında tablosunda dilediğini yapabilir.

Ortak veritabanının asıl sorunu bu satırlarda görünüyor. Tablo tek bir sistemin adını taşıyor ama
iki sistemin kodu ona bağlı. Şemanın tek sahibi yok; katalog birimi tabloyu tek başına
değiştiremeyeceğini ancak bağı kuran taraf değişikliği fark ettiğinde öğrenir.

#### Değişikliğin Yayılması

Son kolon bunu ölçüyor. Kaynak sistem tek bir sütunun adını değiştiriyor; kendi yayın biçimini
korumak dışında hiçbir şey yapmıyor. Uzak çağrı ve mesajlaşma bağları bu değişiklikten hiç
etkilenmiyor, çünkü ikisi de yayın biçiminden okuyor. Ortak veritabanı ve dosya aktarımı bağları
yanlış yanıt vermeye başlıyor; üstelik gürültüsüzce, çünkü eksik alanın karşılığı hata değil,
tanımsız bir değerdir.

Son satır bu sonucu kurumun tamamına taşıyor. Katalogdan çıkan beş bağın üçü kırılıyor ve
kırılanların ardında iki ayrı sahip duruyor. Kaynak sistemin sahibi için bu, tek satırlık bir
göçün önce iki birimle takvim uzlaştırmasını, sonra üç sistemin uyarlanmasını beklemesi demektir.
Kalıp seçimi burada bir gecikme tercihi olmaktan çıkıp bir koordinasyon borcuna dönüşüyor: hangi
kalıp seçilirse seçilsin veri karşıya geçer, ama kaç sahibin izni olmadan değişemeyeceği kalıba
göre değişir.

#### Özet

- Aynı bağ dört kalıpla kuruldu: uzak çağrıda sorgu başına 1 tur ve yüz sorguda 100 kaynak isteği,
  diğer üç kalıpta 0 tur ve 0 istek ölçüldü.
- Tazelik penceresi ortak veritabanı ve uzak çağrıda 0 tik, dosya aktarımı ve mesajlaşmada 1 tik;
  aynı pencere dosya aktarımında 200, mesajlaşmada 1 kayıt taşıyarak alınıyor.
- Ortak veritabanı ve dosya aktarımı tüketici koduna kaynağın fiziksel şemasından 3 ad taşıyor;
  bunların biri sütun adı değil, uygunluk kuralının ikinci kopyasıdır.
- Uzak çağrı ve mesajlaşma fiziksel ad taşımıyor, yerine kaynağın taahhüt ettiği 2 ve 3 yayın adına
  bağlanıyor.
- Kaynak tek bir sütun adını değiştirdiğinde 5 bağın 3'ü sessizce yanlış yanıt vermeye başlıyor ve
  3 sahipten 2'siyle koordinasyon gerekiyor.

#### Sonraki Adım

Ölçüm tek bir kaynak ve tek bir tüketiciyle yapıldı; kurum modelinde ise katalogdan çıkan beş bağ
var ve katalog kurumun tek sistemi değil. Her sistem her sisteme kendi seçtiği kalıpla bağlandığında
bağ sayısının sistem sayısıyla nasıl arttığı, yeni bir sistem eklemenin kaç tarafa iş çıkardığı ve
bu bağların ortak bir noktadan geçirilmesinin neyi ucuzlatıp neyi tek bir yerde topladığı hiç
sorulmadı. Sonraki ders aynı kurum modelinde ikili bağları ve merkezî noktayı yan yana kurar; bağ
sayısını, yeni sistemin maliyetini, merkezin düştüğü anda kopan bağ sayısını ve merkezde biriken
iş mantığının kime ait olduğunu sayar.

### Kurumsal Servis Veri Yolu

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/kurumsal-servis-veri-yolu

Aynı akış kümesinin ikili bağlarla ve merkezî bir noktayla kurulup karşılaştırılması: yazılan çevirici ve uyarlayıcı sayısı, bir kuralın kaç yerde geçtiği, merkezin işlediği ileti sayısı, merkez düştüğünde kopan akış oranı, yeni bir sistem eklemenin dokunduğu sahip sayısı ve merkezde biriken iş mantığının sahipliği.

Önceki ders tek bir bağı dört kalıpla kurdu ve bir kalıbın neye mal olduğunu gösterdi. Kurumda ise
her sistem her sistemle kendi seçtiği yoldan konuşuyor. Bu ders aynı veri akışı kümesini iki
düzende kurar — her akış için doğrudan bir bağ, ya da bütün akışların geçtiği tek bir merkezî
nokta — ve ikisini aynı ölçülerle karşılaştırır.

**TM4 — kurum kurgudur, akış kümesi `node` içinde bir dizi olarak yazılır.** Ölçülen her nicelik
ya bu diziden ya çalışan süreçlerden ya da tümleştirme kodunun kendi metninden okunur.

**TM5 — alıcı sistemler tek bir süreçte, her biri kendi portunda modellenir.** Gerekçe: ölçülen
nicelikler (yazılan birim, geçilen atlama, işlenen ileti, kopan akış) sistemlerin ayrı makinelerde
durup durmamasından bağımsızdır; ayrı portlar sistem sınırını korumaya yeter.

**TM6 — merkezî nokta bir ürün değil, bir konumdur.** Ölçülen şey merkezin hangi yetenekleri
taşıdığı değil, bütün akışların tek bir noktadan geçmesinin bağ sayısına, arıza yüzeyine ve
sahipliğe ne yaptığıdır.

#### Akış Kümesi

Bölgesel kütüphane ağında altı sistem, dokuz veri akışı ve beş ayrı sahip vardır. Ödünç servisi
her ödüncü dört sisteme bildirir, üyelik sistemi üye değişikliğini üç sisteme, katalog nüsha
durumunu iki sisteme. Dokuz akış, altı sistemin kurabileceği otuz yönlü çiftin küçük bir alt
kümesidir; graf seyrektir ve bu seyreklik ilerideki sayıların çoğunu belirler.

```js
// kurum.mjs — kurgu kurum modeli: sistemler, sahipleri ve aralarindaki veri akislari
export const SAHIP = { katalog: "katalog birimi", odunc: "ic gelistirme",
  ucretlendirme: "ic gelistirme", uyelik: "uyelik birimi", raporlama: "yonetim birimi",
  "sube-arayuzu": "sube birimi", ayirtma: "sube birimi", merkez: "tumlestirme birimi" };
export const ALICI = ["ucretlendirme", "raporlama", "katalog", "sube-arayuzu", "odunc"];
export const AKIS = [                            // [kaynak, hedef]; her satir bir bag
  ["odunc", "ucretlendirme"], ["odunc", "raporlama"], ["odunc", "katalog"],
  ["odunc", "sube-arayuzu"], ["uyelik", "odunc"], ["uyelik", "ucretlendirme"],
  ["uyelik", "raporlama"], ["katalog", "sube-arayuzu"], ["katalog", "raporlama"],
];
export const YENI = [                            // yedinci sistem eklenince dogan akislar
  ["odunc", "ayirtma"], ["uyelik", "ayirtma"], ["katalog", "ayirtma"],
  ["ayirtma", "odunc"], ["ayirtma", "sube-arayuzu"],
];
export const derece = (a) => AKIS.filter((b) => b.includes(a)).length;

if (process.argv[1].endsWith("kurum.mjs")) {
  const s = [...new Set(AKIS.flat())];
  console.log(`${s.length} sistem, ${AKIS.length} akis, ${new Set(s.map((a) => SAHIP[a])).size} sahip; ` +
    `olasi yonlu cift ${s.length * (s.length - 1)}`);
  console.log(`en cok akisa dokunan sistem: ` +
    `${s.map((a) => `${a} ${derece(a)}`).sort((x, y) => y.split(" ")[1] - x.split(" ")[1])[0]}`);
  console.log(`yedinci sistem eklenince akis ${AKIS.length} -> ${AKIS.length + YENI.length}`);
}
```

```
6 sistem, 9 akis, 5 sahip; olasi yonlu cift 30
en cok akisa dokunan sistem: odunc 5
yedinci sistem eklenince akis 9 -> 14
```

Alıcı sistemler tek bir süreçte, beş ayrı portta durur ve aldıkları kaydı kendi kütüklerine
yazarlar; iki düzenin sonucu bu kütüklerden karşılaştırılır.

```js
// sistemler.mjs — bes alici sistem, her biri kendi portunda; <taban-port>; uzun omurlu surec
import { createServer } from "node:http";
import { appendFileSync } from "node:fs";
import { ALICI } from "./kurum.mjs";
const [taban] = process.argv.slice(2);
if (!taban) { console.log("kullanim: node sistemler.mjs <taban-port>"); process.exit(1); }
ALICI.forEach((ad, i) => createServer(async (istek, yanit) => {
  let s = "";
  for await (const p of istek) s += p;
  appendFileSync(`alinan-${ad}.log`, `${s}\n`);
  yanit.end("tamam");
}).listen(Number(taban) + i));
```

#### İkili Bağlar

İkili düzende her akış için bir çevirici yazılır ve çevirici kaynak sistemin içinde durur. Her
sistemin kendi sözcük dağarcığı vardır: ödünç servisi `uyeId` der, üyelik sistemi `uye_no`,
ücretlendirme `uyeNo`. Çevirici bu farkı kapatır ve hedefin beklediği alanları üretir. Dört kural
(gecikme ücreti, rapor dönemi, şube bölgesi, üye sınıfı) çeviricilerin içinde çağrılır.

```js
// ikili.mjs — ikili tumlestirme: her akis icin bir cevirici; cevirici kaynak sistemde durur
export const ucret = (g) => g * 5;                          // gecikme ucreti kurali
export const donem = (z) => z.slice(0, 7);                  // rapor donemi kurali
export const bolge = (k) => (k <= 2 ? "kuzey" : "guney");   // sube bolgesi kurali
export const sinif = (d) => (d === 1 ? "tam" : "kisitli");  // uye sinifi kurali
export const CEVIRICI = {
  "odunc->ucretlendirme": (o) => ({ uyeNo: o.uyeId, nusha: o.nushaId, borc: ucret(o.gecikmeGunu) }),
  "odunc->raporlama": (o) => ({ olay: "odunc", anahtar: o.nushaId, donem: donem(o.zaman) }),
  "odunc->katalog": (o) => ({ nushaId: o.nushaId, uygun: false }),
  "odunc->sube-arayuzu": (o) => ({ nusha: o.nushaId, bolge: bolge(o.subeKodu) }),
  "uyelik->odunc": (o) => ({ uyeId: o.uye_no, sinif: sinif(o.durum_kodu) }),
  "uyelik->ucretlendirme": (o) => ({ uyeNo: o.uye_no, sinif: sinif(o.durum_kodu) }),
  "uyelik->raporlama": (o) => ({ olay: "uye", anahtar: o.uye_no, donem: donem(o.zaman) }),
  "katalog->sube-arayuzu": (o) => ({ nusha: o.nushaId, bolge: bolge(o.subeKodu) }),
  "katalog->raporlama": (o) => ({ olay: "nusha", anahtar: o.nushaId, donem: donem(o.zaman) }),
};
```

#### Merkezî Nokta

Merkezî düzende üretici sistem kendi biçimini tek bir yere verir. Merkez o biçimi ortak biçime
çevirir, akış tablosuna bakarak hedefleri bulur ve her hedef için o sistemin biçimine çevirip
yollar. Sistem başına iki uyarlayıcı vardır: içeri ve dışarı. Dört kural artık tek bir yerde durur
ve `KURAL` dizisi her kuralın işini kimin sahiplendiğini yazar.

```js
// merkez.mjs — merkezi nokta; <port> <taban-port>; uzun omurlu surec
import { createServer } from "node:http";
import { AKIS, ALICI } from "./kurum.mjs";
const [port, taban] = process.argv.slice(2);
if (!taban) { console.log("kullanim: node merkez.mjs <port> <taban-port>"); process.exit(1); }
const ucret = (g) => g * 5, donem = (z) => z.slice(0, 7);   // kurallar merkezde toplandi
const bolge = (k) => (k <= 2 ? "kuzey" : "guney"), sinif = (d) => (d === 1 ? "tam" : "kisitli");
export const KURAL = [                           // merkezde duran kural ve isin asil sahibi
  { ad: "ucret", sahip: "ic gelistirme" }, { ad: "donem", sahip: "yonetim birimi" },
  { ad: "bolge", sahip: "sube birimi" }, { ad: "sinif", sahip: "uyelik birimi" },
];
const GIRIS = {                                  // sistem bicimi -> ortak bicim
  odunc: (o) => ({ tur: "odunc", uye: o.uyeId, nusha: o.nushaId, sube: o.subeKodu,
    gecikme: o.gecikmeGunu, zaman: o.zaman }),
  uyelik: (o) => ({ tur: "uye", uye: o.uye_no, durum: o.durum_kodu, zaman: o.zaman }),
  katalog: (o) => ({ tur: "nusha", nusha: o.nushaId, sube: o.subeKodu, zaman: o.zaman }),
};
const CIKIS = {                                  // ortak bicim -> sistem bicimi
  ucretlendirme: (c) => (c.tur === "odunc"
    ? { uyeNo: c.uye, nusha: c.nusha, borc: ucret(c.gecikme) }
    : { uyeNo: c.uye, sinif: sinif(c.durum) }),
  raporlama: (c) => ({ olay: c.tur, anahtar: c.nusha ?? c.uye, donem: donem(c.zaman) }),
  katalog: (c) => ({ nushaId: c.nusha, uygun: false }),
  "sube-arayuzu": (c) => ({ nusha: c.nusha, bolge: bolge(c.sube) }),
  odunc: (c) => ({ uyeId: c.uye, sinif: sinif(c.durum) }),
};
let gelen = 0, giden = 0;                        // merkezin isledigi ileti sayisi

createServer(async (istek, yanit) => {
  if (istek.url === "/sayac") { yanit.end(`${gelen} ${giden}`); return; }
  if (istek.url === "/kapat") { yanit.end("kapali"); process.exit(0); }
  let s = "";
  for await (const p of istek) s += p;
  const { kaynak, govde } = JSON.parse(s);
  gelen += 1;
  const ortak = GIRIS[kaynak](govde);
  for (const h of AKIS.filter((b) => b[0] === kaynak).map((b) => b[1])) {
    giden += 1;
    await fetch(`http://127.0.0.1:${Number(taban) + ALICI.indexOf(h)}/al`,
      { method: "POST", body: JSON.stringify(CIKIS[h](ortak)) });
  }
  yanit.end("tamam");
}).listen(Number(port));
```

#### Ölçüm

Araç aynı altı olayı önce ikili düzende, sonra merkezî düzende geçirir ve alıcı kütüklerini
karşılaştırır. Yazılan birim sayısı ve kuralın geçtiği yer sayısı çalışan süreçlerden değil, iki
tümleştirme dosyasının metninden okunur. Son adımda merkez kapatılır ve aynı altı olay yeniden
gönderilir.

```js
// olc.mjs — iki duzeni ayni akis kumesinde olcer; <taban-port> <merkez-port>
import { existsSync, readFileSync, rmSync } from "node:fs";
import { AKIS, ALICI, SAHIP, YENI } from "./kurum.mjs";
import { CEVIRICI } from "./ikili.mjs";
const [taban, mp] = process.argv.slice(2);
if (!mp) { console.log("kullanim: node olc.mjs <taban-port> <merkez-port>"); process.exit(1); }
const OLAY = [                                   // uretici sistemlerin kendi bicimindeki olaylari
  ["odunc", { uyeId: 7, nushaId: 401, subeKodu: 1, gecikmeGunu: 3, zaman: "2026-04-11" }],
  ["odunc", { uyeId: 9, nushaId: 402, subeKodu: 3, gecikmeGunu: 0, zaman: "2026-04-12" }],
  ["uyelik", { uye_no: 7, durum_kodu: 1, zaman: "2026-04-11" }],
  ["uyelik", { uye_no: 9, durum_kodu: 2, zaman: "2026-04-13" }],
  ["katalog", { nushaId: 401, subeKodu: 1, zaman: "2026-04-11" }],
  ["katalog", { nushaId: 403, subeKodu: 4, zaman: "2026-04-14" }],
];
const TESLIM = AKIS.length * 2;                  // her akis iki olay tasir
const sil = () => ALICI.forEach((a) => rmSync(`alinan-${a}.log`, { force: true }));
const topla = () => ALICI.flatMap((a) => existsSync(`alinan-${a}.log`)
  ? readFileSync(`alinan-${a}.log`, "utf8").split("\n").filter(Boolean).map((s) => `${a} ${s}`) : []);
const ikiliKos = async () => {                   // cevirici kaynak sistemde kosar, dogrudan yollar
  for (const [k, g] of OLAY) {
    for (const h of AKIS.filter((b) => b[0] === k).map((b) => b[1])) {
      await fetch(`http://127.0.0.1:${Number(taban) + ALICI.indexOf(h)}/al`,
        { method: "POST", body: JSON.stringify(CEVIRICI[`${k}->${h}`](g)) });
    }
  }
};
const merkezKos = async () => {                  // uretici yalniz kendi bicimini merkeze verir
  let kabul = 0;
  for (const [kaynak, govde] of OLAY) {
    try {
      await fetch(`http://127.0.0.1:${mp}/olay`, { method: "POST",
        body: JSON.stringify({ kaynak, govde }) });
      kabul += 1;
    } catch { kabul += 0; }                      // merkez kapaliysa uretici teslim edemez
  }
  return kabul;
};
sil(); await ikiliKos(); const a = topla().sort();
sil(); await merkezKos(); const b = topla().sort();
const [gelen, giden] = (await (await fetch(`http://127.0.0.1:${mp}/sayac`)).text()).split(" ").map(Number);
const mk = readFileSync("merkez.mjs", "utf8"), ik = readFileSync("ikili.mjs", "utf8");
const kesit = (m, ad) => m.split(`const ${ad} = {`)[1].split("\n};")[0];
const anahtar = (m) => m.match(/^ {2}"?[\w>-]+"?: \(/gm).length;   // kalip basina yazilan birim
const cagri = (m) => ["ucret", "donem", "bolge", "sinif"]          // kuralin gectigi yer sayisi
  .reduce((s, r) => s + (m.match(new RegExp(`\\b${r}\\(`, "g")) || []).length, 0);
const kural = mk.split("KURAL = [")[1].split("];")[0].match(/sahip: "([^"]+)"/g);
const kume = (l) => new Set(l).size;
const MD = ["ayirtma", "merkez"];                // merkezli duzende dokunulan birimler
const satir = (ad, x, y) => console.log(`${ad.padEnd(41)}${String(x).padStart(7)}${String(y).padStart(9)}`);

satir("olcu", "ikili", "merkezi");
satir("akis (bag) sayisi", AKIS.length, AKIS.length);
satir("yazilan cevirici / uyarlayici", anahtar(kesit(ik, "CEVIRICI")),
  anahtar(kesit(mk, "GIRIS")) + anahtar(kesit(mk, "CIKIS")));
satir("kuralin gectigi yer", cagri(ik), cagri(mk));
satir("teslim basina atlama", 1, 2);
satir("en yogun birimin isledigi ileti", 2, gelen + giden);
satir("bir birim dusunce kopan akis", Math.max(...AKIS.flat()
  .map((s) => AKIS.filter((b) => b.includes(s)).length)), AKIS.length);
satir("yedinci sistem: yazilacak birim", YENI.length, MD.length);
satir("yedinci sistem: dokunulan sahip", kume(YENI.map((b) => SAHIP[b[0]])),
  kume(MD.map((s) => SAHIP[s])));
satir("sahibi baska olan, merkezde duran kural", 0,
  kural.filter((s) => !s.includes(SAHIP.merkez)).length);
console.log(`iki duzenin teslimi: ${a.length}/${b.length} kayit, ` +
  `birebir ayni: ${JSON.stringify(a) === JSON.stringify(b) ? "evet" : "hayir"}`);

await fetch(`http://127.0.0.1:${mp}/kapat`).catch(() => 0);        // merkez kapatilir
sil(); const kabul = await merkezKos(); const dusukMerkez = topla().length;
sil(); await ikiliKos();
console.log(`merkez kapali: ${kabul}/${OLAY.length} olay kabul edildi, ` +
  `${dusukMerkez}/${TESLIM} teslim oldu; ikili duzen ayni anda ${topla().length}/${TESLIM} teslim etti`);
```

```bash
node sistemler.mjs 8991 & S=$!
node merkez.mjs 8990 8991 &
sleep 0.8
node olc.mjs 8991 8990
kill $S
```

```
olcu                                       ikili  merkezi
akis (bag) sayisi                              9        9
yazilan cevirici / uyarlayici                  9        8
kuralin gectigi yer                            8        5
teslim basina atlama                           1        2
en yogun birimin isledigi ileti                2       24
bir birim dusunce kopan akis                   5        9
yedinci sistem: yazilacak birim                5        2
yedinci sistem: dokunulan sahip                4        2
sahibi baska olan, merkezde duran kural        0        4
iki duzenin teslimi: 18/18 kayit, birebir ayni: evet
merkez kapali: 0/6 olay kabul edildi, 0/18 teslim oldu; ikili duzen ayni anda 18/18 teslim etti
```

#### Bağ Sayısı Ne Kadar Azalıyor

Son satırdan önceki karşılaştırma ölçümün geçerliliğini kuruyor: iki düzen de on sekiz kaydı
teslim ediyor ve teslim edilen kayıtlar birebir aynı. Aradaki fark işin sonucunda değil, işin
nerede durduğunda.

İkinci satır beklenen kazancı vermiyor. Dokuz akış için dokuz çevirici yerine sekiz uyarlayıcı
yazılıyor; kazanç tek birim. Merkezî tümleştirmenin klasik gerekçesi bağ sayısının sistem sayısının
karesi kadar artmasıdır, ama o gerekçe bütün sistemlerin birbiriyle konuştuğu varsayımına
dayanır. Bu kurumda altı sistemin kurabileceği otuz yönlü çiftten yalnız dokuzu gerçekleşmiştir.
Çevirici sayısı akış sayısıyla, uyarlayıcı sayısı sistem sayısıyla büyür; graf seyrek olduğu
sürece ikisi birbirine yakın kalır ve merkezî düzenin bu kolondaki üstünlüğü küçüktür.

Asıl kazanç üçüncü satırdadır. Aynı dört kural ikili düzende sekiz yerde çağrılıyor, merkezde beş
yerde. Rapor dönemi kuralı üç ayrı çeviricide geçiyor, çünkü raporlamaya veri gönderen üç sistem
de o hesabı kendi kodunda yapmak zorunda. Dönem tanımı değişirse ikili düzende üç ayrı sistemin,
merkezde tek bir birimin değişmesi gerekir. Merkezin sattığı şey bağ sayısı değil, tekrarın
ortadan kalkmasıdır.

#### Merkezin Bedeli

Beşinci satır darboğazı sayıya çeviriyor. Altı olay için merkez yirmi dört ileti işliyor: altı
giriş, on sekiz çıkış. İkili düzende en yoğun tek bağın işlediği ileti sayısı iki. Merkez, en
yoğun ikili bağın on iki katı iş yapıyor ve bu oran akış sayısıyla büyüyor; üstüne teslim başına
bir atlama ekliyor.

Altıncı satır arıza yüzeyini veriyor. İkili düzende en çok akışa dokunan sistem ödünç servisidir
ve o düştüğünde dokuz akıştan beşi kopar. Merkez düştüğünde dokuzunun dokuzu kopar. Çıktının son
satırı bunu ölçümle gösteriyor: merkez kapatıldığında altı olayın hiçbiri kabul edilmiyor ve on
sekiz teslimden sıfırı gerçekleşiyor; aynı anda ikili düzen on sekiz teslimin on sekizini yapıyor.
Ödünç servisi düştüğünde kurum ödünç veremediği için zaten durmuştur; merkez düştüğünde ise
hiçbir iş yapmayan bir bileşen bütün kurumu durdurur. Tek arıza noktasının rahatsız edici yanı
budur: iş değeri sıfır olan bir bileşenin arıza payı en yüksektir.

#### Yeni Sistem ve Merkezde Biriken Mantık

Yedinci ve sekizinci satırlar merkezî düzenin en güçlü savunmasıdır. Ayırtma sistemi eklendiğinde
beş yeni akış doğuyor. İkili düzende bu beş akış için beş çevirici yazılır ve çeviriciler kaynak
sistemlerin içinde durduğu için ödünç, üyelik, katalog ve ayırtma kodlarına dokunulur: dört ayrı
sahiple takvim uzlaştırılır. Merkezî düzende yalnız iki birim yazılır — ayırtmanın giriş ve çıkış
uyarlayıcısı — ve dokunulan sahip sayısı ikiye iner. Yeni sistemin maliyeti sistem sayısından
kopar.

Son satır bunun karşılığını gösteriyor. Merkezde dört kural duruyor ve dördünün de asıl sahibi
başkasıdır: gecikme ücreti ücretlendirmenin, rapor dönemi yönetim biriminin, bölge tanımı şube
biriminin, üye sınıfı üyelik biriminin işidir. Merkezin sahibi olan tümleştirme birimi bu
kuralların hiçbirini yazacak yetkinliğe sahip değildir ama hepsinin kodunu taşır. Bunun iki sonucu
var. Birincisi, üye sınıfı tanımı değiştiğinde değişiklik üyelik biriminin kendi sürümüyle değil,
merkezin sürümüyle çıkar; ikincisi, o sürüm dokuz akışın tamamını birden yeniden dağıtır. Kuralın
tekrarı kalkarken kuralın sahipliği bulanıklaşıyor ve dağıtım birimleri birbirine bağlanıyor.
Seçim akış grafının ne kadar sıkı olduğuna bağlıdır: merkez tekrarı ve yeni sistemin koordinasyon
maliyetini düşürür, karşılığında bir atlama, ortak bir arıza noktası ve sahibi belirsiz bir kural
yığını ekler.

#### Özet

- Aynı dokuz akış iki düzende kuruldu ve ikisi de aynı 18 kaydı birebir aynı içerikle teslim etti;
  karşılaştırma bu doğrulamanın üstüne kuruldu.
- Yazılan birim sayısı 9'a karşı 8; altı sistemin 30 olası yönlü çiftinden yalnız 9'u
  gerçekleştiği için merkezin bağ sayısı kazancı tek birimde kaldı.
- Aynı dört kural ikili düzende 8, merkezde 5 yerde geçiyor; rapor dönemi kuralı üç ayrı sistemde
  tekrarlanıyor.
- Merkez altı olay için 24 ileti işliyor, en yoğun ikili bağ 2; merkez kapatıldığında 18 teslimden
  0'ı gerçekleşirken ikili düzen aynı anda 18'ini tamamlıyor.
- Yedinci sistem ikili düzende 5 birim ve 4 sahibe, merkezî düzende 2 birim ve 2 sahibe mal
  oluyor; karşılığında merkezde sahibi başkası olan 4 kural birikiyor.

#### Sonraki Adım

İki ders boyunca veri hep tek yönde aktı: bir sistem yazdı, ötekiler okudu. Kaynak belliydi, bağın
yönü belliydi ve çakışma diye bir şey yoktu. Kurumda bu varsayım çoğu varlık için tutmaz. Üye
kaydı üyelik sisteminde de, ödünç servisinde de, belediyedeki kimlik servisinde de durur; üçü de
kendi kullanıcı arayüzünden yazılır ve üçünün adres alanı aynı üye için farklı değerler taşır.
Sonraki ders aynı varlığı üç sistemde tutar ve sayar: kaç sistem yazıyor, kaç alan çakışıyor, bir
uzlaştırma turunda kaç kayıt düzeliyor ve geriye kaç tutarsızlık kalıyor; bir sistem kaynak
seçildiğinde bu sayılar nasıl değişiyor ve o seçim yazma yolunda neyi uzatıyor.

### Ana Veri Yönetimi

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/ana-veri-yonetimi

Aynı üye kaydının üç sistemde tutulmasının ölçülmesi: kaç sistemin yazdığı, çakışan alan çifti sayısı, uzlaştırma turunda düzeltilen alan ve kalan tutarsızlık, altın kayıt seçildiğinde bu sayıların nasıl değiştiği ve seçimin yazma yolunda ödettiği adım ile erişilebilirlik kaybı.

İki ders boyunca veri hep tek yönde aktı: bir sistem yazdı, ötekiler okudu. Kaynağı belliydi,
bağın yönü belliydi ve iki kopyanın farklı gerçek taşıması diye bir sorun yoktu. Kurumda bu
varsayım çoğu varlık için tutmaz. Üye kaydı üyelik sisteminde de, ödünç servisinde de,
belediyedeki kimlik servisinde de durur; üçü de kendi ekranından yazılır ve aynı üyenin adresi üç
yerde üç farklı değer taşıyabilir.

Bu ders o durumu kurar ve sayar: kaç sistem yazıyor, kaç alan çakışıyor, bir uzlaştırma turunda
kaç değer düzeliyor ve geriye ne kalıyor. Sonra sistemlerden biri kaynak sistem seçilir, aynı olay
dizisi yeniden koşturulur ve aynı sayılar yeniden okunur.

**TM7 — kurum kurgudur; sistemler, alanları, sahipleri ve yazma olayları `node` içinde bir veri
yapısıdır.** Rastgelelik tek bir görünür tohumdan üretilir, üreteç kodun içindedir.

**TM8 — çoğaltma mekaniği modellenmez.** Gerekçe: kopya tutma, çoğaltma gecikmesi ve sonunda
tutarlılık ayrı bir kursta ölçüldü. Burada ölçülen şey verinin nasıl kopyalandığı değil, kimin
yazdığı ve iki kopyanın farklı gerçek taşımasıdır; yazma anında görünür kabul edilir.

**TM9 — uzlaştırma kuralı "en son yazan kazanır" olarak modellenir.** Gerekçe: ölçülen nicelik
kuralın kendisi değil, kuralın uygulanabildiği yüzeydir. Dışarıdan yazılamayan bir sistemde hangi
kural seçilirse seçilsin düzeltme yazılamaz; kuralı değiştirmek kalan tutarsızlığın yerini değil,
yalnız kazananı değiştirir.

#### Aynı Varlık, Üç Sistem

Üç sistem aynı üyeyi tutar ve üçünün alan kümesi farklıdır. Üyelik sistemi dört alan taşır, ödünç
servisi üç, belediyedeki kimlik servisi iki. Üçünün de sahibi ayrıdır ve üçünde de kendi
kullanıcıları vardır. Belirleyici fark alan sayısında değil, son kolonda: kimlik servisine
dışarıdan yazılamaz. Kurum o sistemi okuyabilir, düzeltme gönderemez.

```js
// kurum.mjs — uye kaydini tutan uc sistem: kurgu kurum modeli ve olay ureteci
export const SISTEM = [
  { ad: "uyelik", sahip: "uyelik birimi", disaridanYazilir: 1,
    alan: ["ad", "adres", "telefon", "eposta"] },
  { ad: "odunc", sahip: "ic gelistirme", disaridanYazilir: 1,
    alan: ["ad", "adres", "telefon"] },
  { ad: "kimlik", sahip: "belediye bilgi islem", disaridanYazilir: 0,
    alan: ["ad", "adres"] },
];
export const ALAN = ["ad", "adres", "telefon", "eposta"];
export const UYE = 120, TUR = 6, TOHUM = 20260411;   // uye sayisi, uye basina yazma, gorunur tohum
const uretec = (t) => () => ((t = (t * 1103515245 + 12345) % 2147483648) / 2147483648);

// her sistemin kendi kullanicisi kendi ekranindan yazar; olaylar tek tohumdan uretilir
export const olaylar = () => {
  const r = uretec(TOHUM), o = [];
  for (let u = 1; u <= UYE; u += 1) {
    for (let t = 1; t <= TUR; t += 1) {
      const s = SISTEM[Math.floor(r() * SISTEM.length)];
      const a = s.alan[Math.floor(r() * s.alan.length)];
      o.push({ uye: u, sistem: s.ad, alan: a, deger: `d${Math.floor(r() * 4)}`, zaman: t });
    }
  }
  return o;
};

if (process.argv[1].endsWith("kurum.mjs")) {
  const O = olaylar();
  console.log(`${SISTEM.length} sistem ayni varligi tutuyor, ` +
    `${new Set(SISTEM.map((s) => s.sahip)).size} ayri sahip; ` +
    `disaridan yazilabilen ${SISTEM.filter((s) => s.disaridanYazilir).length}`);
  for (const s of SISTEM) {
    console.log(`  ${s.ad.padEnd(8)}${String(s.alan.length).padStart(2)} alan  ` +
      `${String(O.filter((o) => o.sistem === s.ad).length).padStart(3)} yazma  ${s.sahip}`);
  }
  console.log(`toplam ${O.length} yazma, ${UYE} uye, ${ALAN.length} alan`);
}
```

```
3 sistem ayni varligi tutuyor, 3 ayri sahip; disaridan yazilabilen 2
  uyelik   4 alan  224 yazma  uyelik birimi
  odunc    3 alan  258 yazma  ic gelistirme
  kimlik   2 alan  238 yazma  belediye bilgi islem
toplam 720 yazma, 120 uye, 4 alan
```

#### İki Yazma Düzeni

Dağıtık düzende yazma hangi ekrandan geldiyse oraya düşer ve orada kalır. Altın kayıt düzeninde
dışarıdan yazılabilen sistemlerin ekranlarından gelen her yazma önce kaynak sisteme gider, oradan
öteki yazılabilir sistemlere yayılır; belediyenin kendi ekranından gelen yazma bu düzenin dışında
kalır. Uzlaştırma turu her iki düzende de aynı işlevle koşar: çakışan her alan için en son
yazılmış değer bulunur ve yazılabilen sistemlere işlenir.

```js
// duzen.mjs — iki yazma duzeni ve uzlastirma turu; depo bicimi: depo[sistem][uye][alan]
import { SISTEM } from "./kurum.mjs";
const bul = (s) => SISTEM.find((x) => x.ad === s);
export const bos = () => Object.fromEntries(SISTEM.map((s) => [s.ad, {}]));
export const koy = (k, s, u, a, d, z) => {       // tasimiyorsa yazma adimi harcanmaz
  if (!bul(s).alan.includes(a)) return 0;
  (k[s][u] ??= {})[a] = { d, z };
  return 1;
};
// dagitik duzen: yazma hangi sistemin ekranindan geldiyse oraya duser
export const dagitik = (k, o, kapali) => (kapali.includes(o.sistem)
  ? { adim: 0, ilk: null }
  : { adim: koy(k, o.sistem, o.uye, o.alan, o.deger, o.zaman), ilk: o.sistem });
// altin kayit duzeni: disaridan yazilabilen her yazma once kaynak sisteme gider, oradan yayilir
export const altin = (k, o, kapali, kaynak = "uyelik") => {
  if (!bul(o.sistem).disaridanYazilir) return dagitik(k, o, kapali);
  if (kapali.includes(kaynak)) return { adim: 0, ilk: null };
  let adim = koy(k, kaynak, o.uye, o.alan, o.deger, o.zaman);
  for (const s of SISTEM.filter((x) => x.disaridanYazilir && x.ad !== kaynak)) {
    adim += koy(k, s.ad, o.uye, o.alan, o.deger, o.zaman);
  }
  return { adim, ilk: kaynak };
};
// cakisma: ayni (uye, alan) icin sistemlerde birden cok farkli deger duruyorsa
export const cakisma = (k, uyeler, alanlar) => uyeler.flatMap((u) => alanlar.flatMap((a) => {
  const v = SISTEM.map((s) => k[s.ad][u]?.[a]).filter(Boolean);
  return new Set(v.map((x) => x.d)).size > 1 ? [{ u, a }] : [];
}));
// uzlastirma turu: en son yazan kazanir, kazanan yazilabilir sistemlere islenir
export const uzlastir = (k, c) => {
  let duzeltilen = 0;
  for (const { u, a } of c) {
    const kazanan = SISTEM.map((s) => ({ ...k[s.ad][u]?.[a] })).filter((x) => x.d)
      .sort((x, y) => y.z - x.z)[0];
    for (const s of SISTEM.filter((x) => x.disaridanYazilir)) {
      const simdi = k[s.ad][u]?.[a];
      if (simdi && simdi.d !== kazanan.d) { koy(k, s.ad, u, a, kazanan.d, kazanan.z); duzeltilen += 1; }
    }
  }
  return duzeltilen;
};
```

#### Ölçüm

Araç yedi yüz yirmi yazma olayını önce dağıtık düzende, sonra altın kayıt düzeninde koşturur. Her
koşumdan sonra çakışan alan çiftleri sayılır, bir uzlaştırma turu koşar ve tur sonrası çakışma
yeniden sayılır. Son ölçü aynı olay dizisini üyelik sistemi kapalıyken yineler ve kaç yazmanın
kabul edildiğini sayar.

```js
// olc.mjs — ayni olay dizisini iki duzende kosar ve tutarsizligi sayar
import { ALAN, SISTEM, UYE, olaylar } from "./kurum.mjs";
import { altin, bos, cakisma, dagitik, uzlastir } from "./duzen.mjs";
const O = olaylar(), UYELER = [...Array(UYE).keys()].map((i) => i + 1);
const kos = (yaz, kapali = []) => {
  const k = bos(), ilkler = new Set();
  let adim = 0, kabul = 0;
  for (const o of O) {
    const { adim: n, ilk } = yaz(k, o, kapali);
    adim += n;
    if (ilk) { kabul += 1; ilkler.add(ilk); }
  }
  return { k, adim, kabul, yazan: ilkler.size };
};
const olc = (yaz) => {
  const t = kos(yaz);
  const once = cakisma(t.k, UYELER, ALAN);
  const duzeltilen = uzlastir(t.k, once);
  const sonra = cakisma(t.k, UYELER, ALAN);
  return { ...t, once, duzeltilen, sonra, kapali: kos(yaz, ["uyelik"]).kabul };
};
const D = olc(dagitik), A = olc(altin);
const satir = (ad, x, y) => console.log(`${ad.padEnd(38)}${String(x).padStart(10)}${String(y).padStart(13)}`);

satir("olcu", "dagitik", "altin kayit");
satir("kullanici yazmasini alan sistem", D.yazan, A.yazan);
satir("olay basina yazma adimi", (D.adim / O.length).toFixed(2), (A.adim / O.length).toFixed(2));
satir("cakisan (uye, alan) cifti", D.once.length, A.once.length);
satir("uzlastirma turunda duzeltilen alan", D.duzeltilen, A.duzeltilen);
satir("uzlastirma sonrasi kalan tutarsizlik", D.sonra.length, A.sonra.length);
satir("uyelik kapaliyken kabul edilen yazma", `${D.kapali}/${O.length}`, `${A.kapali}/${O.length}`);
console.log();
console.log(`${"alan".padEnd(9)}${"tasiyan".padStart(8)}${"dagitik cakisan".padStart(17)}` +
  `${"dagitik kalan".padStart(15)}${"altin cakisan".padStart(15)}${"altin kalan".padStart(13)}`);
for (const a of ALAN) {
  const n = (l) => l.filter((x) => x.a === a).length;
  console.log(`${a.padEnd(9)}${String(SISTEM.filter((s) => s.alan.includes(a)).length).padStart(8)}` +
    `${String(n(D.once)).padStart(17)}${String(n(D.sonra)).padStart(15)}` +
    `${String(n(A.once)).padStart(15)}${String(n(A.sonra)).padStart(13)}`);
}
```

```
olcu                                     dagitik  altin kayit
kullanici yazmasini alan sistem                3            2
olay basina yazma adimi                     1.00         1.61
cakisan (uye, alan) cifti                    131           95
uzlastirma turunda duzeltilen alan            95           94
uzlastirma sonrasi kalan tutarsizlik          48           48
uyelik kapaliyken kabul edilen yazma     496/720      238/720

alan      tasiyan  dagitik cakisan  dagitik kalan  altin cakisan  altin kalan
ad              3               62             32             53           32
adres           3               54             16             42           16
telefon         2               15              0              0            0
eposta          1                0              0              0            0
```

#### Çakışma Nereden Doğuyor

İkinci tablonun ilk kolonu tek başına açıklayıcıdır. Elektronik posta alanı yalnız üyelik
sisteminde durur ve hiçbir düzende hiç çakışmaz. Telefon iki sistemde durur, adres ve ad üçünde;
çakışma sayıları da bu sıraya uyar. Çakışma alanın önemiyle, doldurulma sıklığıyla ya da veri
kalitesiyle değil, o alanı kaç sistemin yazdığıyla doğar. Yüz yirmi üyenin dört alanı için dağıtık
düzende yüz otuz bir çakışan çift ölçülüyor; bunların tamamı birden fazla sistemin yazdığı üç
alandadır.

Uzlaştırma turu yüz otuz bir çakışmadan doksan beş alan değerini düzeltiyor ve kırk sekiz çakışma
geriye kalıyor. Kalanların dağılımı ikinci tablonun dördüncü kolonundadır: otuz ikisi ad, on
altısı adres alanında. Bu iki alan, kimlik servisinin taşıdığı iki alandır. Telefon alanındaki on
beş çakışmanın tamamı düzeliyor, çünkü telefonu taşıyan iki sistemin ikisi de yazılabilir.

Kalan tutarsızlığın kaynağı uzlaştırma kuralının zayıflığı değildir. En son yazan kazanır kuralı
her çakışmada bir kazanan belirler; sorun kazananın öteki sistemlere yazılamamasıdır. Kazanan
değer belediyenin sistemindeki değerden farklı çıktığında, kurum o sistemi düzeltemez. Kırk sekiz
sayısı bir veri kalitesi ölçüsü değil, bir yetki sınırı ölçüsüdür.

#### Altın Kayıt Neyi Değiştiriyor

Üyelik sistemi kaynak sistem seçildiğinde tablo dört yerde değişiyor. Kullanıcı yazması alan
sistem sayısı üçten ikiye iniyor; üçe değil ikiye, çünkü üçüncü yazıcı kurumun yetki sınırının
dışındadır. Çakışan çift sayısı yüz otuz birden doksan beşe düşüyor. Telefon alanındaki çakışma
tamamen kayboluyor: iki yazılabilir sistem artık aynı yazma yolundan beslendiği için o alanda iki
farklı gerçek üretilemiyor.

Ad ve adres alanlarında çakışma azalıyor ama sıfırlanmıyor — altmış ikiden elli üçe, elli dörtten
kırk ikiye. Kalan çakışmaların tamamı kurum içi kopyalarla belediyenin kopyası arasındadır.

Beşinci satır dersin en sert sayısıdır: kalan tutarsızlık iki düzende de tam olarak kırk sekiz.
Bu bir rastlantı değil, düzeneğin yapısal sonucudur. Uzlaştırmanın kazananı, o alanın en son
yazılmış değeridir; hangi ekrandan geldiği ve hangi sisteme düştüğü kazananı değiştirmez. Kazanan
kimlik servisinden gelmediği her durumda o servisin kopyası yanlış kalır ve dışarıdan yazılamadığı
için düzeltilemez. Altın kayıt seçimi bu kırk sekiz çakışmanın bir tanesini bile azaltmıyor.

Buradan ana veri yönetiminin gerçek sınırı çıkıyor. Altın kayıt, yazma yetkisinin ulaştığı yüzeyde
tutarlılık üretir. O yüzeyin dışında kalan her kopya için üretebileceği tek şey, tutarsızlığın
nerede olduğunu bilmektir. Kırk sekiz kayıt için yapılabilecek şey onları düzeltmek değil,
raporlanabilir hâle getirmek ve kurum içi kararların hangi kopyaya güveneceğini yazılı hâle
getirmektir.

#### Seçimin Ödettiği

İkinci ve altıncı satırlar bedeli veriyor. Olay başına yazma adımı 1,00'dan 1,61'e çıkıyor. Artış
iki kat değil, çünkü yalnız birden fazla yazılabilir sistemin taşıdığı alanlar yayılıyor;
elektronik posta yazmaları tek adımda kalıyor. Yazma yolunun uzaması ölçülebilir bir gecikme
olarak da geri döner: kullanıcı artık kendi sisteminin veritabanına değil, başka bir birimin
sistemine yazar ve o yazma başarılı olana kadar bekler.

Altıncı satır bunun daha sert biçimidir. Üyelik sistemi kapalıyken dağıtık düzende yedi yüz yirmi
yazmanın dört yüz doksan altısı kabul edilirken, altın kayıt düzeninde yalnız iki yüz otuz sekizi
kabul ediliyor — o da belediyenin kendi ekranından gelenlerdir. Kurumun bütün üye yazmaları tek
bir birimin sistemine bağlanmıştır. Dağıtık düzende üyelik sisteminin kapalı olması ödünç
servisinin üye adresini güncellemesini engellemiyordu; altın kayıt düzeninde engelliyor.

Ödenen bedel yalnız teknik de değil. Kaynak sistem seçmek, bir birimin sistemini öteki birimlerin
çalışma önkoşulu hâline getirir: erişilebilirlik hedefi, bakım penceresi ve sürüm takvimi artık o
birimin tek başına vereceği kararlar olmaktan çıkar. Kurum ölçeğinde altın kayıt kararı bir veri
kararı gibi görünür, ama ödediği şey bir bağımlılık ve bir koordinasyon yükümlülüğüdür.

#### Özet

- Aynı üye kaydı üç sistemde tutulduğunda 720 yazma olayı dağıtık düzende 131 çakışan (üye, alan)
  çifti üretiyor; çakışma yalnız birden fazla sistemin yazdığı alanlarda doğuyor.
- Tek sistemde duran elektronik posta alanı hiçbir düzende çakışmıyor; iki sistemde duran telefon
  alanı altın kayıt düzeninde 15 çakışmadan 0'a iniyor.
- Uzlaştırma turu dağıtık düzende 95, altın kayıt düzeninde 94 alan değerini düzeltiyor; kalan
  tutarsızlık iki düzende de 48 ve tamamı dışarıdan yazılamayan sistemin taşıdığı iki alandadır.
- Altın kayıt seçimi çakışmayı 131'den 95'e düşürüyor ama kalan tutarsızlığı bir tane bile
  azaltmıyor: düzeltme ancak yazma yetkisinin ulaştığı yüzeyde çalışır.
- Seçimin bedeli olay başına yazma adımının 1,00'dan 1,61'e çıkması ve kaynak sistem kapalıyken
  kabul edilen yazmanın 496/720'den 238/720'ye düşmesidir.

#### Sonraki Adım

Üç ders boyunca bütün ölçümler işletim yolunda kaldı: bir kayıt yazıldı, bir bağdan geçti, bir
sistemde okundu. Yönetim birimi ise bunların hiçbirini tek tek sormuyor; dönemlik ödünç sayısını,
şube başına gecikme oranını ve üyelik hareketlerini birlikte istiyor ve bu soruların yanıtı üç
ayrı sistemin verisini yan yana koymayı gerektiriyor. Bu soruların işletim sistemleri üzerinde
koşturulması hiç ölçülmedi: raporlama sorgusunun kaynak sisteme bindirdiği yük, üç sistemin farklı
alan adlarının tek bir çözümleme biçimine getirilmesi ve bu dönüştürmenin sonucun tazeliğine
eklediği gecikme. Sonraki ders çözümleme yükünü işletim yolundan ayırır ve bu üç niceliği sayar.

### Veri Ambarı ve Dönüştürme Hatları

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/veri-ambari-ve-donusturme-hatlari

Çözümleme yükünün işletim yükünden ayrılması: beş raporun işletim sistemine günde 163 sorgu ve 5.354.308 okunan kayıt bindirmesi, ambarın bu yükü tazelik gecikmesi karşılığında devralması, sekiz adımlık dönüştürme hattının bir çevrimde 523.341 kayıt taşıması ve kaynak şemasındaki tek bir alan değişiminin bir adımı kırıp dört adımı durdurarak beş raporun beşini birden düşürmesi.

Önceki ders aynı varlığı birden çok sistemin yazdığı durumu ele aldı: bir kaynak sistem seçildi
ve kayıtlar arasındaki tutarsızlık sayıldı. Orada bütün taraflar veriyi **yazıyordu**. Bu derste
hiç yazmayan bir taraf var. Bölgesel kütüphane ağının yönetim birimi yalnız soru sorar: hangi
şube doluyor, hangi eser gecikmede, üyelik nasıl akıyor. Soru veriyi değiştirmez ama bedelsiz de
değildir; her soru bir sorguya, her sorgu okunan kayda dönüşür ve o kayıtlar ödünç işlemlerini
yürüten sistemin diskinde durur.

Bu ders çözümleme yükünün işletim yükünden ayrılmasını ölçer. Ağ, sahipleri ve bütçeleri ayrı
olan bir **kurgudur**.

#### Soru Soran Taraf Sayılabilir Bir Yük Getirir

Modelde dört kaynak vardır ve dördünün sahibi ayrıdır: ödünç servisi, üyelik sistemi, dışarıdan
alınmış katalog ve şube sistemleri. Yönetim biriminin beş sorusu bunları okur.

**TM10: kayıt sayıları, koşum sıklıkları ve tazelik gereksinimleri kurgudur** ve hiçbir gerçek
kurumdan alınmamıştır. **TM11: bir raporun bir varlığa dokunması bir sorgudur; olay varlığı
pencereye göre, boyut varlığı tam taranır.** **TM14: okuduğu alanı bulamayan adım kırılır;
girdisi sağlam olmayan adım durur.**

```js
// ambar/model.mjs — bolgesel kutuphane aginin kurgu modeli ve donusturme hatti. Kayitlar
// gercekten uretilir; sonraki bloklarin sayilari bu dizileri tarayarak olculur.
export const TOHUM = 7391, GUN = 180, SON = GUN * 24 - 1;
export const SAHIP = { odunc: "odunc servisi (iceride)", uye: "uyelik sistemi",
  eser: "katalog (disaridan alinmis)", sube: "sube sistemleri" };

export function uret(t = TOHUM) {
  let s = t;
  const r = () => (s = (s * 48271) % 2147483647) / 2147483647, n = (k) => Math.floor(r() * k);
  const dizi = (k, f) => Array.from({ length: k }, (_, i) => f(i));
  return {
    sube: dizi(12, (i) => ({ id: i, bolge: `b${i % 4}` })),
    eser: dizi(128_000, (i) => ({ id: i, tur: ["kitap", "sureli", "isitsel"][n(3)], degisim: n(SON) })),
    uye: dizi(46_000, (i) => ({ id: i, kayit_gun: n(GUN), sube_id: n(12), degisim: n(SON) })),
    odunc: dizi(240_000, (i) => ({ id: i, uye_id: n(46_000), eser_id: n(128_000),
      sube_id: r() < 0.008 ? null : n(12), gun: n(GUN), saat: n(24) })),
  };
}

// Raporlar: varlik -> pencere (gun) ya da tam tarama; gunluk kosum; kabul edilen en buyuk
// gecikme (saat); ambardaki dayanak; kirilmayi belirleyen alan.
export const RAPORLAR = {
  doluluk: { okur: { odunc: 1, sube: "tam" }, kosum: 48, tazelik: 1, dayanak: "ozet-sube", alan: "odunc.sube_id" },
  "gecikmis-eser": { okur: { odunc: 30, eser: "tam" }, kosum: 24, tazelik: 4, dayanak: "zengin", alan: "eser.tur" },
  "yeni-uye": { okur: { uye: "tam" }, kosum: 12, tazelik: 14, dayanak: "ozet-uye", alan: "uye.kayit_gun" },
  etkinlik: { okur: { odunc: 90, uye: "tam" }, kosum: 2, tazelik: 36, dayanak: "ozet-uye", alan: "uye.kayit_gun" },
  devir: { okur: { odunc: 180, eser: "tam", sube: "tam" }, kosum: 1, tazelik: 72, dayanak: "zengin", alan: "eser.tur" },
};

// Tek kosumda okunan kayit ve acilan sorgu.
export function raporOku(veri, r) {
  let okunan = 0, sorgu = 0;
  for (const [varlik, pencere] of Object.entries(r.okur)) {
    sorgu += 1;
    if (pencere === "tam") { okunan += veri[varlik].length; continue; }
    for (const k of veri[varlik]) if (k.gun >= GUN - pencere) okunan += 1;
  }
  return { okunan, sorgu };
}

// Bir cevrimde cekilen dilim: olaydan donem icindeki kayit, boyuttan ya tamami ya da
// degisim damgasi doneme dusen kayit (TM13).
export function cek(veri, donem, boyut) {
  const esik = SON - donem;
  const degisen = (d) => boyut === "tam" ? d : d.filter((k) => k.degisim > esik);
  const dilim = { odunc: veri.odunc.filter((k) => k.gun * 24 + k.saat > esik),
    uye: degisen(veri.uye), eser: degisen(veri.eser), sube: veri.sube };
  return { dilim, okunan: Object.values(dilim).reduce((t, d) => t + d.length, 0), sorgu: 4 };
}

// Hattin sekiz adimi; her adim okudugu alani bildirir.
export const ADIMLAR = [
  { ad: "cek-odunc", kaynak: "odunc", girdi: [], okur: ["uye_id", "eser_id", "sube_id", "gun"] },
  { ad: "cek-uye", kaynak: "uye", girdi: [], okur: ["kayit_gun", "sube_id"] },
  { ad: "cek-eser", kaynak: "eser", girdi: [], okur: ["tur"] },
  { ad: "cek-sube", kaynak: "sube", girdi: [], okur: ["bolge"] },
  { ad: "temiz", girdi: ["cek-odunc"], okur: ["sube_id", "gun"] },
  { ad: "zengin", girdi: ["temiz", "cek-eser", "cek-sube"], okur: ["eser_id", "tur", "bolge"] },
  { ad: "ozet-sube", girdi: ["zengin"], okur: ["bolge", "gun"] },
  { ad: "ozet-uye", girdi: ["temiz", "cek-uye"], okur: ["uye_id", "kayit_gun"] },
];

const grupla = (d, f) => [...new Set(d.map(f))].map((a) => ({ a }));
const ISLEM = {
  temiz: ([o]) => o.filter((k) => k.sube_id !== null),
  zengin: ([o, e, s]) => {
    const t = new Map(e.map((k) => [k.id, k.tur])), b = new Map(s.map((k) => [k.id, k.bolge]));
    return o.map((k) => ({ ...k, tur: t.get(k.eser_id) ?? "yok", bolge: b.get(k.sube_id) ?? "yok" }));
  },
  "ozet-sube": ([o]) => grupla(o, (k) => `${k.bolge}|${k.gun}`),
  "ozet-uye": ([o]) => grupla(o, (k) => `${k.uye_id}|${Math.floor(k.gun / 30)}`),
};

// Hatti kostur: hata firlatan adim "kirik", girdisi saglam olmayan adim "durdu" olur.
export function kostur(dilim) {
  const cikti = new Map(), durum = new Map(), sayim = new Map();
  let tasinan = 0;
  for (const a of ADIMLAR) {
    if (a.girdi.some((g) => durum.get(g) !== "tamam")) { durum.set(a.ad, "durdu"); continue; }
    const girdiler = a.kaynak ? [dilim[a.kaynak]] : a.girdi.map((g) => cikti.get(g));
    const ornek = girdiler.filter((d) => d.length > 0).map((d) => d[0]);
    try {
      for (const alan of a.okur)
        if (ornek.every((k) => (alan in k) === false)) throw new Error(`eksik alan ${alan}`);
      const sonuc = a.kaynak ? girdiler[0] : ISLEM[a.ad](girdiler);
      const giren = girdiler.reduce((t, d) => t + d.length, 0);
      cikti.set(a.ad, sonuc); durum.set(a.ad, "tamam");
      sayim.set(a.ad, { giren, cikan: sonuc.length });
      tasinan += giren + sonuc.length;
    } catch (e) { durum.set(a.ad, `kirik: ${e.message}`); }
  }
  return { durum, sayim, tasinan };
}
```

#### Ambar Yükü Alır, Karşılığında Gecikme Verir

Ambar bir çevrimde kaynakları okur, dönüştürür ve raporların okuyacağı özetleri bırakır. Bir
rapor ancak kabul ettiği gecikme ambarınkinden büyükse ambardan cevap alır. **TM12: hat saniyede
4.000 kayıt taşır; tazelik gecikmesi dönem ile koşum süresinin toplamıdır.** **TM13: artımlı
boyut yüklemesi değişim damgası üzerinde bir dizin varsayar.**

```js
// ambar/yuk.mjs — isletim sistemine dusen sorgu ve okunan kayit: ambarsiz ve ambarli
import { uret, RAPORLAR, raporOku, cek, kostur, GUN } from "./model.mjs";

const veri = uret();
const HIZ = 4000; // TM12: hat saniyede 4.000 kayit tasir
const olcum = Object.fromEntries(Object.entries(RAPORLAR).map(([a, r]) => [a, raporOku(veri, r)]));

console.log(`model: ${Object.entries(veri).map(([a, d]) => `${a} ${d.length}`).join(", ")}; ${GUN} gun`);
console.log("\nrapor          kosum/gun  sorgu/kosum  okunan/kosum  okunan/gun  tazelik (saat)");
console.log("-------------- ---------- ------------ ------------- ----------- ---------------");
let hamOkunan = 0, hamSorgu = 0;
for (const [ad, r] of Object.entries(RAPORLAR)) {
  const o = olcum[ad];
  hamOkunan += o.okunan * r.kosum; hamSorgu += o.sorgu * r.kosum;
  console.log(`${ad.padEnd(14)} ${String(r.kosum).padStart(10)} ${String(o.sorgu).padStart(12)} ` +
    `${String(o.okunan).padStart(13)} ${String(o.okunan * r.kosum).padStart(11)} ${String(r.tazelik).padStart(15)}`);
}
console.log(`ambarsiz toplam: ${hamSorgu} sorgu/gun, ${hamOkunan} okunan kayit/gun`);

console.log("\ndonem  boyut     kosum (sn)  gecikme  ambarda  isletimde  sorgu/gun  okunan/gun  ambarsiza gore");
console.log("------ --------- ---------- -------- -------- ---------- ---------- ----------- --------------");
const kalanlar = {};
for (const boyut of ["tam", "artimli"]) for (const donem of [24, 12, 3, 1]) {
  const c = cek(veri, donem, boyut);
  const kosum = kostur(c.dilim).tasinan / HIZ;
  const gecikme = donem + kosum / 3600, cevrim = 24 / donem;
  let sorgu = c.sorgu * cevrim, okunan = c.okunan * cevrim;
  const kalan = [];
  for (const [ad, r] of Object.entries(RAPORLAR)) {
    if (r.tazelik >= gecikme) continue;
    kalan.push(ad);
    sorgu += olcum[ad].sorgu * r.kosum; okunan += olcum[ad].okunan * r.kosum;
  }
  kalanlar[donem] = kalan;
  console.log(`${String(donem).padStart(6)} ${boyut.padEnd(9)} ${kosum.toFixed(1).padStart(10)} ` +
    `${gecikme.toFixed(2).padStart(8)} ${String(5 - kalan.length).padStart(8)} ${String(kalan.length).padStart(10)} ` +
    `${String(Math.round(sorgu)).padStart(10)} ${String(Math.round(okunan)).padStart(11)} ` +
    `${`${(okunan / hamOkunan * 100).toFixed(1)}%`.padStart(14)}`);
}
console.log(`\n24 saatlik donemde isletimde kalan rapor: ${kalanlar[24].join(", ")}`);
console.log(`3 saatlik donemde isletimde kalan rapor: ${kalanlar[3].join(", ")}`);
```

```
model: sube 12, eser 128000, uye 46000, odunc 240000; 180 gun

rapor          kosum/gun  sorgu/kosum  okunan/kosum  okunan/gun  tazelik (saat)
-------------- ---------- ------------ ------------- ----------- ---------------
doluluk                48            2          1326       63648               1
gecikmis-eser          24            2        168293     4039032               4
yeni-uye               12            1         46000      552000              14
etkinlik                2            2        165808      331616              36
devir                   1            3        368012      368012              72
ambarsiz toplam: 163 sorgu/gun, 5354308 okunan kayit/gun

donem  boyut     kosum (sn)  gecikme  ambarda  isletimde  sorgu/gun  okunan/gun  ambarsiza gore
------ --------- ---------- -------- -------- ---------- ---------- ----------- --------------
    24 tam            133.4    24.04        2          3        160     4830006          90.2%
    12 tam            131.9    12.04        3          2        152     4451992          83.1%
     3 tam            130.8     3.04        4          1        128     1456912          27.2%
     1 tam            130.6     1.04        4          1        192     4241160          79.2%
    24 artimli          3.6    24.00        2          3        160     4656902          87.0%
    12 artimli          1.8    12.00        3          2        152     4104854          76.7%
     3 artimli          0.4     3.00        4          1        128       65392           1.2%
     1 artimli          0.1     1.00        4          1        192       65160           1.2%

24 saatlik donemde isletimde kalan rapor: doluluk, gecikmis-eser, yeni-uye
3 saatlik donemde isletimde kalan rapor: doluluk
```

İlk tablo yükün nerede olduğunu gösteriyor. Günde 163 sorgu ve 5.354.308 okunan kayıt var; bunun
4.039.032'si, yani yüzde yetmiş beşi **tek bir rapordan** geliyor. Sebebi koşum sayısı değil,
koşum başına okunan kayıt: gecikmiş eser listesi her koşumda katalogun 128.000 satırını tarıyor.
Günde 48 kez koşan doluluk raporu toplamın yüzde birini bile bulmuyor.

İkinci tablo ambarın devraldığı payı dönem dönem sayıyor ve iki yönlü bir eğri çıkarıyor. Dönem
kısaldıkça gecikme düşüyor, gecikme düştükçe daha çok rapor ambardan cevap alabiliyor: ikiden
dörde. Ama çevrim sayısı da artıyor ve her çevrim kaynakları yeniden okuyor. Tam boyut
yüklemesinde okunan kayıt 24 saatlik dönemde yüzde 90,2, 3 saatlikte yüzde 27,2, 1 saatlikte
yeniden yüzde 79,2. En ucuz nokta uçlarda değil, ortada.

Asıl belirleyici sütun **boyut**. Aynı dönemde artımlı yükleme yüzde 27,2'yi yüzde 1,2'ye
indiriyor, çünkü katalogun 128.000 satırı her çevrimde değil yalnız değişen kısmıyla okunuyor.
İşletim yükünün düşüp düşmeyeceğini ambarın varlığı değil, kaynakları nasıl okuduğu belirliyor.

Bir rapor hiçbir dönemde ambara geçmiyor: doluluk raporunun kabul ettiği gecikme bir saat, en
kısa dönemin gecikmesi 1,04 saat. Tazelik gereksinimi, ambarın kapsayamadığı yolu tanımlar.

#### Hattın Adımları ve Kaynak Şemasındaki Değişim

Hat sekiz adımdır ve her adım okuduğu alanı bildirir. Kaynak şemasındaki bir alan değişimi
gerçekten uygulanır: alan yeniden adlandırılır ya da kaldırılır, hat koşturulur ve kırılan
adım sayılır.

```js
// ambar/kirilma.mjs — adim adim tasinan kayit ve kaynak sema degisiminin kirdigi adim
import { uret, RAPORLAR, cek, kostur, ADIMLAR, SAHIP } from "./model.mjs";

const veri = uret(), DONEM = 3;
const { dilim } = cek(veri, DONEM, "tam");
const temiz = kostur(dilim);
const gecikme = DONEM + temiz.tasinan / 4000 / 3600;

console.log("adim         girdi                       giren    cikan");
console.log("------------ ------------------------ -------- --------");
for (const a of ADIMLAR) {
  const s = temiz.sayim.get(a.ad);
  console.log(`${a.ad.padEnd(12)} ${(a.kaynak ?? a.girdi.join(",")).padEnd(24)} ` +
    `${String(s.giren).padStart(8)} ${String(s.cikan).padStart(8)}`);
}
console.log(`bir cevrimde ${ADIMLAR.length} adim ${temiz.tasinan} kayit tasidi; gecikme ${gecikme.toFixed(2)} saat`);

// Uc sema degisimi uygulanir: alan yeniden adlandirilir ya da kaldirilir.
const DEGISIM = {
  "eser.tur -> eser.tur_kodu": { varlik: "eser", alan: "tur", yeni: "tur_kodu" },
  "odunc.sube_id -> odunc.sube": { varlik: "odunc", alan: "sube_id", yeni: "sube" },
  "uye.kayit_gun kaldirildi": { varlik: "uye", alan: "kayit_gun", yeni: null },
};
const uygula = (d, g) => ({ ...d, [g.varlik]: d[g.varlik].map((k) => {
  const y = { ...k }; delete y[g.alan]; if (g.yeni) y[g.yeni] = k[g.alan]; return y; }) });

console.log("\ndegisim                       sahip                        kirik  duran  saglam  ambarda dusen  ambarsiz kirilan");
console.log("----------------------------- --------------------------- ------ ------ ------- -------------- -----------------");
for (const [ad, g] of Object.entries(DEGISIM)) {
  const d = [...kostur(uygula(dilim, g)).durum];
  const say = (f) => d.filter(([, v]) => f(v)).length;
  const bozuk = new Set(d.filter(([, v]) => v !== "tamam").map(([k]) => k));
  const dusen = Object.values(RAPORLAR).filter((r) => bozuk.has(r.dayanak)).length;
  const ambarsiz = Object.values(RAPORLAR).filter((r) => r.alan === `${g.varlik}.${g.alan}`).length;
  console.log(`${ad.padEnd(29)} ${SAHIP[g.varlik].padEnd(27)} ${String(say((v) => v.startsWith("kirik"))).padStart(6)} ` +
    `${String(say((v) => v === "durdu")).padStart(6)} ${String(say((v) => v === "tamam")).padStart(7)} ` +
    `${String(dusen).padStart(14)} ${String(ambarsiz).padStart(17)}`);
}

// Bag: ambarsiz rapor okudugu her kaynaga baglanir; ambarli kaynak yalniz hatta baglanir.
const bagsiz = Object.values(RAPORLAR).flatMap((r) => Object.keys(r.okur));
const kalan = Object.values(RAPORLAR).filter((r) => r.tazelik < gecikme);
const kalanBag = kalan.flatMap((r) => Object.keys(r.okur));
console.log(`\nbag: ambarsiz ${bagsiz.length} (rapor -> kaynak); ambarli ${4 + (5 - kalan.length) + kalanBag.length} ` +
  `(4 cekim + ${5 - kalan.length} ambar okumasi + ${kalanBag.length} kalan dogrudan okuma)`);
console.log(`yonetim biriminin konustugu sahip: ambarsiz ${new Set(bagsiz).size}, ` +
  `ambarli ${new Set(["ambar", ...kalanBag]).size}`);
```

```
adim         girdi                       giren    cikan
------------ ------------------------ -------- --------
cek-odunc    odunc                         146      146
cek-uye      uye                         46000    46000
cek-eser     eser                       128000   128000
cek-sube     sube                           12       12
temiz        cek-odunc                     146      144
zengin       temiz,cek-eser,cek-sube    128156      144
ozet-sube    zengin                        144        4
ozet-uye     temiz,cek-uye               46144      143
bir cevrimde 8 adim 523341 kayit tasidi; gecikme 3.04 saat

degisim                       sahip                        kirik  duran  saglam  ambarda dusen  ambarsiz kirilan
----------------------------- --------------------------- ------ ------ ------- -------------- -----------------
eser.tur -> eser.tur_kodu     katalog (disaridan alinmis)      1      2       5              3                 2
odunc.sube_id -> odunc.sube   odunc servisi (iceride)          1      4       3              5                 1
uye.kayit_gun kaldirildi      uyelik sistemi                   1      1       6              2                 2

bag: ambarsiz 10 (rapor -> kaynak); ambarli 10 (4 cekim + 4 ambar okumasi + 2 kalan dogrudan okuma)
yonetim biriminin konustugu sahip: ambarsiz 4, ambarli 3
```

Adım tablosu maliyetin nereden geldiğini gösteriyor. Üç saatlik çevrimde ödünç tarafından yalnız
146 kayıt geliyor, ama taşınan toplam 523.341. Farkın tamamı boyut okumasıdır: `zengin` adımına
128.156 kayıt giriyor, çünkü 144 ödünç kaydını zenginleştirmek için katalogun tamamı okunuyor.
`temiz` adımı 146 kayıttan 144'ünü geçiriyor; şubesi boş kalan iki kayıt düşüyor.

Kırılma tablosu bu kursun sorusunu veriyor. Üç değişimin üçü de tek bir alanı ilgilendiriyor ve
üçü de hattın **tek** adımını kırıyor. Fark, kırığın nerede durduğudur. Katalogun alanı
kırıldığında iki adım daha duruyor ve üç rapor cevapsız kalıyor; ambarsız durumda o alanı iki
rapor kullanıyordu. Ödünç servisinin alanı kırıldığında dört adım duruyor ve **beş raporun beşi**
düşüyor — oysa o alanı doğrudan okuyan tek rapor vardı. Üyelik alanında iki sayı eşitleniyor.

Ambar, aynı kaynağı okuyan raporları birbirine bağlar. Doluluk raporu katalogun tür alanını hiç
kullanmaz; ambarsız durumda o değişimden etkilenmezdi, ambarlı durumda `ozet-sube` adımı `zengin`
adımının ardında durduğu için etkilenir. Karşılığı düzeltmenin yerindedir: kırık tek bir adımdır
ve tek bir ekibin sorumluluğundadır. Ambarsız durumda aynı düzeltme, ayrı yazılmış rapor
sorgularının her birinde ayrı ayrı yapılır.

Son satırlar bağı sayıyor. Bağ sayısı değişmiyor: ambarsız 10, ambarlı 10. Değişen yönü ve
sahibi. Yönetim birimi ambarsız durumda dört sahiple, ambarlı durumda üçüyle konuşur; kalan iki
sahip ambarın karşılayamadığı doluluk raporu yüzündendir. Tümleştirme noktası bağ sayısını
azaltmaz, koordinasyonun kiminle yapılacağını değiştirir.

#### Özet

- Beş rapor işletim sistemine günde 163 sorgu ve 5.354.308 okunan kayıt bindiriyor; bunun yüzde
  yetmiş beşi tek bir rapordan geliyor, çünkü o rapor her koşumda katalogun 128.000 satırını
  tarıyor (TM10, TM11).
- Dönem kısaldıkça ambardan cevaplanan rapor ikiden dörde çıkıyor, ama çevrim sayısı arttığı için
  okunan kayıt yüzde 27,2'den yüzde 79,2'ye geri tırmanıyor; en ucuz dönem uçlarda değil ortadadır.
- Artımlı boyut yüklemesi aynı dönemde işletim yükünü yüzde 27,2'den yüzde 1,2'ye indiriyor;
  belirleyici olan ambarın varlığı değil kaynakları nasıl okuduğudur (TM13).
- Tazelik gereksinimi bir saat olan rapor hiçbir dönemde ambara geçmiyor, çünkü en kısa dönemin
  gecikmesi 1,04 saat. Ambar kapsayamadığı yolu böyle bildirir (TM12).
- Sekiz adımlık hat bir çevrimde 523.341 kayıt taşıyor; kaynaktaki tek bir alan değişimi tek bir
  adımı kırıyor, ama ödünç alanında kırığın ardında dört adım durduğu için beş raporun beşi
  düşüyor — o alanı doğrudan okuyan tek rapor vardı (TM14).

#### Sonraki Adım

Bu dersin ölçümleri bir varsayıma yaslanıyordu: kaynak sistemlerin alanları biliniyor ve şema
değişimi bir hata iletisiyle görünüyor. Ağdaki her sistem böyle değil. Ödünç geçmişini yıllardır
tutan, kaynak koduna kimsenin erişemediği bir kayıt sistemi duruyor. Sıradaki ders bunu ele alır:
değiştirilemeyen bir sistemin çağrı yüzeyi sarmalanınca kaç yol kapanır, kaç yol sarmalayıcının
dışında kalır, veri sahipliği devredilirken iki sistemin birlikte yazdığı pencere ne kadar sürer.

### Eski Sistemlerle Çalışma

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/eski-sistemlerle-calisma

Kaynak koduna erişilemeyen bir kayıt sisteminin sarmalanması ve sahipliğinin aşamalı devri: sistemin yüzeyinin koddan değil 60.000 çağrılık bir izden okunması, arayüzü tam kapatan bir sarmalayıcının çağrıların yüzde 71,8'ini kapatıp yedi çağrı çiftini ve dört sahibi dışarıda bırakması, sahiplik devrinde koordinasyon adımının 24'ten 13'e inmesi ve birlikte yazılan pencerenin en yavaş sahibin sürüm turundan kısalmaması.

Önceki dersin bütün ölçümleri kaynak sistemlerin okunabildiğini varsayıyordu: alanları
biliniyordu, şemaları değiştiğinde bu bir hata iletisiyle görünüyordu. Bölgesel kütüphane ağının
kurgu modelinde bu varsayımı karşılamayan bir sistem var. Ödünç geçmişini yıllardır tutan kayıt
sistemi çalışıyor, ağın en eski kayıtları onda duruyor, ama kaynak koduna kimse erişemiyor: ne
bir alan eklenebiliyor, ne bir davranış değiştirilebiliyor, ne de içeride ne olduğu sorulabiliyor.

Bu ders geçişin yol yol nasıl taşındığını ölçmez. Sorusu daha önce gelir: değiştirilemeyen bir
sistemin çevresine ne kurulabilir, o şeyin kapatamadığı ne kalır ve sistemin tuttuğu veri başka
bir sahibe geçerken iki taraf ne kadar süre birlikte yazar. Ağ, sahipleri ve bütçeleri ayrı olan
bir **kurgudur**.

#### Erişilemeyen Sistemin Yüzeyi Trafikten Okunur

Bir sistemin çağrı yüzeyi genelde kodundan çıkarılır. Burada kod yok, dolayısıyla ölçü de başka
yerden gelmek zorunda: sisteme **gelen çağrılar** izlenir ve yüzey bu izden sayılır. Yüzeyin
birimi tek bir işlem adı değil, **(çağıran, işlem) çiftidir**; aynı işlemi çağıran iki sistem iki
ayrı bağdır, çünkü ikisinin sahibi ayrıdır.

**TM15: çağıran sistemler, sahipleri, yolları ve çağrı payları kurgudur.** **TM16: eski sistemin
yüzeyi koddan okunamaz; ölçü, doksan günde gözlenmiş 60.000 çağrılık izdir.** **TM17:
sarmalayıcı yalnız çağrı arayüzündeki işlemi kapatabilir; veritabanına doğrudan giren iş ile
dosya diziniyle gelen aktarım sarmalanamaz.**

```js
// eski/model.mjs — kaynak koduna erisilemeyen kayit sisteminin kurgu modeli. Sistemin yuzeyi
// koddan degil trafikten olculur: cagri izi gercekten uretilir ve sonraki bloklar onu tarar.
export const TOHUM = 4127, GUN = 90, OLAY = 60_000, BASLA = 30;
// Her sahibin kendi surum turu vardir (gun) ve bir turda tek bir yazani devreder (TM18).
export const TUR = { sarmal: 7, odunc: 7, sube: 14, ucret: 14, uyelik: 21, veri: 30, yonetim: 30 };

// Cagiran sistemler: sahibi, eski sisteme ulastigi yol ve kullandigi islemler. "arayuz" yolu
// sarmalanabilir; "veritabani" ve "dosya" yollari sarmalayicinin disinda kalir.
export const CAGIRANLAR = {
  "sube-ucu": { sahip: "sube", yol: "arayuz", pay: 34, islem: ["odunc-ac", "iade-al", "gecmis-oku"] },
  "odunc-servisi": { sahip: "odunc", yol: "arayuz", pay: 30, islem: ["odunc-ac", "iade-al", "uzat", "ceza-yaz"] },
  "uyelik": { sahip: "uyelik", yol: "arayuz", pay: 8, islem: ["uye-esle", "gecmis-oku"] },
  "gece-isi": { sahip: "veri", yol: "veritabani", pay: 12, islem: ["toplu-kapat", "arsivle"] },
  "ucret-hesabi": { sahip: "ucret", yol: "veritabani", pay: 9, islem: ["ceza-yaz", "gecmis-oku"] },
  "rapor-araci": { sahip: "yonetim", yol: "veritabani", pay: 5, islem: ["gecmis-oku"] },
  "sube-aktarim": { sahip: "sube", yol: "dosya", pay: 2, islem: ["toplu-kapat", "arsivle"] },
};

// Her islem bir veri varligina dokunur ve ya okur ya yazar.
export const ISLEM = {
  "odunc-ac": ["odunc", "yaz"], "iade-al": ["odunc", "yaz"], uzat: ["odunc", "yaz"],
  "toplu-kapat": ["odunc", "yaz"], "ceza-yaz": ["ceza", "yaz"], "uye-esle": ["uye-bag", "yaz"],
  arsivle: ["gecmis", "yaz"], "gecmis-oku": ["gecmis", "oku"],
};
export const VARLIKLAR = ["odunc", "ceza", "uye-bag", "gecmis"];

// Cagri izi: her olay bir cagiran, bir islem ve bir gun tasir.
export function izUret(t = TOHUM) {
  let s = t;
  const r = () => (s = (s * 48271) % 2147483647) / 2147483647;
  const adlar = Object.keys(CAGIRANLAR);
  const toplam = adlar.reduce((a, k) => a + CAGIRANLAR[k].pay, 0);
  const iz = [];
  for (let i = 0; i < OLAY; i += 1) {
    let p = r() * toplam, cagiran = adlar[0];
    for (const k of adlar) { p -= CAGIRANLAR[k].pay; if (p <= 0) { cagiran = k; break; } }
    const islem = CAGIRANLAR[cagiran].islem[Math.floor(r() * CAGIRANLAR[cagiran].islem.length)];
    const [varlik, yon] = ISLEM[islem];
    iz.push({ cagiran, islem, varlik, yon, yol: CAGIRANLAR[cagiran].yol, gun: Math.floor(r() * GUN) });
  }
  return iz;
}

// Sarmalayici yalnizca arayuz yolundaki islemleri kapatabilir.
export const kapali = (e, kapsam) => e.yol === "arayuz" && kapsam.includes(e.islem);
export const KAPSAM = {
  yok: [],
  dar: ["odunc-ac", "iade-al"],
  "arayuz-tam": ["odunc-ac", "iade-al", "uzat", "ceza-yaz", "uye-esle", "gecmis-oku"],
};
```

#### Sarmalayıcının Kapattığı ve Kapatamadığı

Sarmalayıcı, eski sistemin önüne konan ve bütün çağrıları kendi üzerinden geçiren bir katmandır.
Kapatabileceği şey, çağıranın hangi yoldan geldiğine bağlıdır ve bu yol seçimi çağıranın
sahibinin yıllar önce verdiği bir karardır.

```js
// eski/yuzey.mjs — cagri yuzeyi ve sarmalayicinin kapattigi pay, izden sayilir
import { izUret, CAGIRANLAR, KAPSAM, kapali, OLAY } from "./model.mjs";

const iz = izUret();
const yuzey = (d) => new Set(d.map((e) => `${e.cagiran}|${e.islem}`)).size;

console.log(`iz: ${iz.length} cagri, ${Object.keys(CAGIRANLAR).length} cagiran sistem, ` +
  `${yuzey(iz)} ayri (cagiran, islem) cifti\n`);
console.log("yol           cagiran  yuzey  cagri     pay  sahip");
console.log("------------- ------- ------ ------- ------- ------");
for (const yol of ["arayuz", "veritabani", "dosya"]) {
  const d = iz.filter((e) => e.yol === yol);
  const c = Object.entries(CAGIRANLAR).filter(([, v]) => v.yol === yol);
  console.log(`${yol.padEnd(13)} ${String(c.length).padStart(7)} ${String(yuzey(d)).padStart(6)} ` +
    `${String(d.length).padStart(7)} ${`${(d.length / OLAY * 100).toFixed(1)}%`.padStart(7)} ` +
    `${String(new Set(c.map(([, v]) => v.sahip)).size).padStart(6)}`);
}

console.log("\nsarmal kapsami  kapanan yuzey  kapanan cagri      pay  disarida yuzey  disarida cagri  disarida sahip");
console.log("--------------- ------------- --------------- -------- --------------- --------------- ---------------");
for (const [ad, kapsam] of Object.entries(KAPSAM)) {
  const ic = iz.filter((e) => kapali(e, kapsam)), dis = iz.filter((e) => kapali(e, kapsam) === false);
  const disSahip = new Set(dis.map((e) => CAGIRANLAR[e.cagiran].sahip)).size;
  console.log(`${ad.padEnd(15)} ${String(yuzey(ic)).padStart(13)} ${String(ic.length).padStart(15)} ` +
    `${`${(ic.length / OLAY * 100).toFixed(1)}%`.padStart(8)} ${String(yuzey(dis)).padStart(15)} ` +
    `${String(dis.length).padStart(15)} ${String(disSahip).padStart(15)}`);
}
```

```
iz: 60000 cagri, 7 cagiran sistem, 16 ayri (cagiran, islem) cifti

yol           cagiran  yuzey  cagri     pay  sahip
------------- ------- ------ ------- ------- ------
arayuz              3      9   43073   71.8%      3
veritabani          3      5   15697   26.2%      3
dosya               1      2    1230    2.1%      1

sarmal kapsami  kapanan yuzey  kapanan cagri      pay  disarida yuzey  disarida cagri  disarida sahip
--------------- ------------- --------------- -------- --------------- --------------- ---------------
yok                         0               0     0.0%              16           60000               6
dar                         4           22516    37.5%              12           37484               6
arayuz-tam                  9           43073    71.8%               7           16927               4
```

İlk tablo, kaynak koduna erişilemeyen bir sistemin yine de ölçülebildiğini gösteriyor. Yedi
çağıran sistem, on altı ayrı (çağıran, işlem) çifti ve üç ayrı yol var. Çağrıların yüzde 71,8'i
çağrı arayüzünden geliyor; geri kalanı ya doğrudan veritabanına giriyor ya da bir dosya diziniyle
ulaşıyor. Sayı olarak küçük görünen dosya yolu — yüzde 2,1 — iki ayrı yüzey çifti taşıyor ve
bunlardan biri veri **yazıyor**.

İkinci tablo sarmalayıcının sınırını veriyor. Kapsam arayüzdeki bütün işlemleri içerdiğinde bile
kapanan pay yüzde 71,8'de duruyor: yedi yüzey çifti ve 16.927 çağrı dışarıda kalıyor, çünkü o
çağrılar arayüzü hiç kullanmıyor. Sarmalayıcı bir sistemin **kapısını** kapatır; duvarındaki
delikleri kapatmaz. Kaynak koda erişim olmadığı için o delikleri kapatmanın tek yolu, deliği
açanla — yani çağıranın sahibiyle — konuşmaktır.

Dışarıda kalan **sahip** sütunu ikinci bir şey söylüyor. Dar kapsamlı sarmalayıcı çağrıların
yüzde 37,5'ini kapatıyor ama dışarıda kalan sahip sayısını altıdan hiç indirmiyor. Kapatılan
çağrı oranı, koordinasyonun azaldığı anlamına gelmez; koordinasyonu azaltan şey bir sahibin
**bütün** yollarının kapanmasıdır. Arayüzü tam kapatan sarmalayıcı altı sahibi dörde indiriyor.

#### Sahiplik Devri ve Birlikte Yazılan Pencere

Sarmalayıcı bir hazırlıktır; asıl iş, eski sistemin tuttuğu veri varlıklarının sahipliğinin yeni
bir sisteme geçmesidir. Bir varlığın sahipliği tek bir anda geçmez: o varlığa yazan her yol ayrı
ayrı çevrilir ve hepsi çevrilene kadar iki sistem birden yazar. Bu **pencere** ölçülebilir.

**TM18: her sahibin kendi sürüm turu vardır ve bir turda tek bir yazanı devreder.** **TM19:
dışarıda kalan her yazan için bir bildirim ve bir doğrulama turu gerekir (iki adım); sarmalayıcı
ardındaki bütün yazanlar tek bir yönlendirmeyle devredilir (bir adım).**

```js
// eski/devir.mjs — veri sahipliginin devri: iki sistemin birlikte yazdigi pencere ve
// sahipler arasi koordinasyon adimi. Her sayi ayni cagri izinden okunur.
import { izUret, CAGIRANLAR, KAPSAM, kapali, VARLIKLAR, BASLA, TUR } from "./model.mjs";

const iz = izUret();

function devir(varlik, kapsam) {
  const yazar = (e) => e.varlik === varlik && e.yon === "yaz";
  const yazanlar = [...new Set(iz.filter(yazar).map((e) => `${e.cagiran}|${e.islem}`))];
  const gecis = new Map(), sayac = {}, dis = [];
  for (const y of yazanlar) {
    const [c, i] = y.split("|");
    if (kapali({ yol: CAGIRANLAR[c].yol, islem: i }, kapsam)) { gecis.set(y, TUR.sarmal); continue; }
    const s = CAGIRANLAR[c].sahip;
    sayac[s] = (sayac[s] ?? 0) + 1;
    gecis.set(y, sayac[s] * TUR[s]);
    dis.push(s);
  }
  const birlikte = iz.filter((e) => yazar(e) && e.gun >= BASLA
    && e.gun < BASLA + gecis.get(`${e.cagiran}|${e.islem}`)).length;
  return { yazan: yazanlar.length, ic: yazanlar.length - dis.length, dis: dis.length,
    sahip: new Set(dis).size, adim: (yazanlar.length > dis.length ? 1 : 0) + 2 * dis.length,
    pencere: Math.max(...gecis.values()), birlikte };
}

console.log("varlik   kapsam       yazan  sarmalda  disarida  sahip  koordinasyon  pencere (gun)  birlikte yazilan");
console.log("-------- ----------- ------ --------- --------- ------ ------------- -------------- -----------------");
const toplam = {};
for (const varlik of VARLIKLAR) for (const ad of ["yok", "arayuz-tam"]) {
  const d = devir(varlik, KAPSAM[ad]);
  toplam[ad] = { adim: (toplam[ad]?.adim ?? 0) + d.adim, birlikte: (toplam[ad]?.birlikte ?? 0) + d.birlikte,
    pencere: Math.max(toplam[ad]?.pencere ?? 0, d.pencere) };
  console.log(`${varlik.padEnd(8)} ${ad.padEnd(11)} ${String(d.yazan).padStart(6)} ${String(d.ic).padStart(9)} ` +
    `${String(d.dis).padStart(9)} ${String(d.sahip).padStart(6)} ${String(d.adim).padStart(13)} ` +
    `${String(d.pencere).padStart(14)} ${String(d.birlikte).padStart(17)}`);
}
for (const [ad, t] of Object.entries(toplam))
  console.log(`toplam (${ad}): ${t.adim} koordinasyon adimi, en uzun pencere ${t.pencere} gun, ` +
    `${t.birlikte} cagri iki sisteme birden yazildi`);
```

```
varlik   kapsam       yazan  sarmalda  disarida  sahip  koordinasyon  pencere (gun)  birlikte yazilan
-------- ----------- ------ --------- --------- ------ ------------- -------------- -----------------
odunc    yok              7         0         7      3            14             42              6862
odunc    arayuz-tam       7         5         2      2             5             30              3386
ceza     yok              2         0         2      2             4             14               781
ceza     arayuz-tam       2         1         1      1             3             14               781
uye-bag  yok              1         0         1      1             2             21               556
uye-bag  arayuz-tam       1         1         0      0             1              7               173
gecmis   yok              2         0         2      2             4             30              1307
gecmis   arayuz-tam       2         0         2      2             4             30              1307
toplam (yok): 24 koordinasyon adimi, en uzun pencere 42 gun, 9506 cagri iki sisteme birden yazildi
toplam (arayuz-tam): 13 koordinasyon adimi, en uzun pencere 30 gun, 5647 cagri iki sisteme birden yazildi
```

Sarmalayıcının kazandırdığı şey tabloda tek bir sütunda toplanmıyor. Koordinasyon adımı 24'ten
13'e, birlikte yazılan çağrı 9.506'dan 5.647'ye iniyor. En uzun pencere 42 günden 30 güne
düşüyor — ama otuzun altına inmiyor.

Dört satır dört ayrı sonuç veriyor ve farkı yaratan, varlığa kimin yazdığıdır. Ödünç kayıtlarına
yedi yol yazıyor; beşi arayüzden geçtiği için sarmalayıcının ardında tek bir yönlendirmeyle
devrediliyor, kalan ikisi kendi sahiplerinin turunu bekliyor: koordinasyon 14 adımdan 5'e, pencere
42 günden 30 güne iniyor. Üye bağında tek yazan var ve o arayüzden geçiyor; sarmalayıcıyla
pencere 21 günden 7 güne, birlikte yazılan çağrı 556'dan 173'e düşüyor. Ceza kayıtlarında
sarmalayıcı bir adım kazandırıyor ama pencereyi hiç kısaltmıyor, çünkü pencereyi belirleyen
dışarıdaki yazan. Geçmiş kayıtlarında iki satır birebir aynı: o varlığa yazan iki yolun ikisi de
arayüzün dışında olduğu için sarmalayıcı bu devirde hiçbir şey değiştirmiyor.

Buradan çıkan sınır, bu dersin asıl ölçüsüdür. Pencerenin alt sınırını sarmalayıcı belirlemez;
**en yavaş sahibin sürüm turu** belirler. Gece işini yürüten sahibin turu otuz gündür ve o sahip
geçmiş kayıtlarına doğrudan veritabanından yazar. Sarmalayıcı ne kadar geniş olursa olsun bu yolu
kapatamaz, dolayısıyla otuz gün ödenecektir. Geçişi hızlandırmak isteyen bir kararın önce
bakması gereken yer, sarmalayıcının kapsamı değil, dışarıda kalan yolların sahipleri ve onların
turlarıdır.

Bir uyarı da birlikte yazılan çağrı sütununda. Pencere boyunca 5.647 çağrı iki sisteme birden
yazılıyor; bu çağrılar iki tarafta da doğru olmak zorunda ve her biri iki yazma işlemi demek.
Pencerenin uzunluğu bir takvim sorunu değil, o takvim boyunca çift yazılan kayıt sayısıdır.

#### Özet

- Kaynak koduna erişilemeyen sistemin çağrı yüzeyi koddan değil izden ölçülür: 60.000 çağrılık
  izde 7 çağıran, 16 ayrı (çağıran, işlem) çifti ve üç ayrı yol görünüyor (TM15, TM16).
- Arayüzü tam kapatan sarmalayıcı çağrıların yüzde 71,8'ini kapatıyor; 7 yüzey çifti ve 16.927
  çağrı dışarıda kalıyor, çünkü veritabanına ve dosya dizinine giren yol sarmalanamaz (TM17).
- Kapatılan çağrı oranı koordinasyonun azaldığını göstermez: dar kapsamlı sarmalayıcı çağrıların
  yüzde 37,5'ini kapattığı halde dışarıdaki sahip sayısını altıdan indirmiyor. Sahip ancak bütün
  yolları kapandığında listeden çıkar.
- Sahipliğin devrinde sarmalayıcı koordinasyon adımını 24'ten 13'e, birlikte yazılan çağrıyı
  9.506'dan 5.647'ye indiriyor; üye bağında pencere 21 günden 7 güne iniyor, geçmiş kayıtlarında
  ise iki durum birebir aynı kalıyor (TM18, TM19).
- Pencerenin alt sınırını sarmalayıcının kapsamı değil en yavaş sahibin sürüm turu belirler: otuz
  günlük turu olan sahip veritabanına doğrudan yazdığı için en uzun pencere 42 günden yalnız 30
  güne inebiliyor.

#### Sonraki Adım

Bu ders elde olanla çalıştı: sistem duruyor, değiştirilemiyor, çevresine bir katman kuruluyor ve
sahipliği adım adım devrediliyor. Kararın kendisi çoktan verilmişti — o sistem bir zamanlar ya
satın alınmıştı ya da içeride yazılmıştı ve bugünkü bütün maliyetler o kararın devamıdır. Kursun
son dersi bu kararı ölçmeye çalışır. Bir yetenek için iki seçenek modellenir: satın almak ve
geliştirmek. Toplam sahip olma maliyeti kalem kalem toplanır — uyarlama, tümleştirme bağları,
sürüm yükseltme, eğitim ve çıkış — ve kazananın zaman ufkuna göre değiştiği gösterilir. Yanına
ikinci bir sayı konur: sahibi başkası olan bir yolun kesilmesi, yani bağımlılık riski.

### Al veya Geliştir Kararı

Source: https://academia.sh/tr/kurslar/kurumsal-baglam/al-veya-gelistir-karari

Bir yeteneğin iki seçeneğinin toplam sahip olma maliyetiyle karşılaştırılması: uyarlama, tümleştirme bağı, eğitim, sürüm yükseltme ve çıkış kalemlerinin ayrı ayrı toplanması, satın alma 402 saat artı yılda 114 saatken geliştirmenin 606 saat artı yılda 54 saat olması, kazananın 3,40 yıllık ufukta değişmesi, sahibi dışarıda olan sekiz noktanın kesilme riski eklendiğinde başabaş ufkun 1,79 yıla inmesi ve ürünün yerleşik kapsamı büyüdükçe aynı sınırın 12,00 yıla çıkması.

Önceki ders elde olanla çalıştı: değiştirilemeyen bir sistem duruyordu, çevresine bir katman
kuruldu ve sahipliği adım adım devredildi. O sistem bir zamanlar ya satın alınmıştı ya içeride
yazılmıştı; bugün ödenen sarmalayıcı, koordinasyon ve pencere maliyetlerinin hepsi o eski kararın
devamıdır. Bu ders, kararın kendisini ölçmeye çalışır.

Bölgesel kütüphane ağının kurgu modelinde yönetim birimi bir raporlama yüzeyi istiyor. İki
seçenek var: dışarıdan bir ürün almak ya da içeride yazmak. Karar "hangisi daha ucuz" diye
sorulursa yanıtsız kalır, çünkü ucuzluk bir zaman aralığı belirtilmeden tanımlı değildir.

#### Toplam Sahip Olma Maliyeti Kalem Kalemdir

Satın alma kararı çoğu zaman tek bir sayıyla — kurulum bedeliyle — savunulur. Oysa bir yeteneğin
ömrü boyunca ödediği beş ayrı kalem vardır ve ikisi yalnız bir kez, ikisi her yıl, biri de
ayrılırken ödenir.

**TM20: yetenek sayısı, kullanıcı sayısı ve saat katsayıları kurgudur.** **TM21: çıkış maliyeti
bu derste ölçülmez; bir kaynak ağacı taranarak başka bir derste ölçülmüştü ve buraya hazır bir
kalem olarak girer — satın alınan yol için 96, geliştirilen yol için 24 saat.** **TM22: toplam
sahip olma maliyeti bir kez ödenen kalemlerin toplamı artı ufuk çarpı yıllık kalemlerdir; çıkış
ufkun sonunda ödenir.**

```js
// karar.mjs — bir yetenegin iki secenegi: satin almak ve gelistirmek. Butun kalemler model
// buyuklukleriyle hesaplanir; cikis kalemi disaridan girdi olarak alinir (TM21).
const IHTIYAC = 18;        // yonetim biriminin istedigi rapor yetenegi
const KULLANICI = 9;       // yuzeyi kullanan kisi
const KAYNAK_BAG = 5;      // baglanacak kaynak sistem

// TM20: saat katsayilari ve buyuklukler kurgudur.
const K = { kurulum: 40, uyarlamaSaat: 14, yazmaSaat: 26, alBag: 22, gelBag: 12,
  egitimAl: 4, egitimGel: 6, surumSayisi: 2, surumNokta: 3, bakimYetenek: 2.5,
  cikisAl: 96, cikisGel: 24 };

// Bir secenegin kalemleri. "yerlesik": urunun hazir sagladigi yetenek sayisi.
function kalemler(yerlesik) {
  const uyarlanan = IHTIYAC - yerlesik;
  const alBag = KAYNAK_BAG + 1;                     // urun kendi veri kopyasini da ister
  const al = {
    uyarlama: [K.kurulum + uyarlanan * K.uyarlamaSaat, 0],
    "tumlestirme bagi": [alBag * K.alBag, 0],
    egitim: [KULLANICI * K.egitimAl, KULLANICI * 2 * K.surumSayisi],
    "surum yukseltme": [0, K.surumSayisi * (uyarlanan + alBag) * K.surumNokta],
    cikis: [K.cikisAl, 0],
  };
  const gel = {
    uyarlama: [IHTIYAC * K.yazmaSaat, 0],
    "tumlestirme bagi": [KAYNAK_BAG * K.gelBag, 0],
    egitim: [KULLANICI * K.egitimGel, KULLANICI],
    "surum yukseltme": [0, IHTIYAC * K.bakimYetenek],
    cikis: [K.cikisGel, 0],
  };
  const topla = (o, i) => Object.values(o).reduce((t, v) => t + v[i], 0);
  return { al, gel, alBir: topla(al, 0), alYil: topla(al, 1),
    gelBir: topla(gel, 0), gelYil: topla(gel, 1), uyarlanan, alBag };
}

// TM22: toplam sahip olma maliyeti = bir kez odenen + ufuk x yillik.
const tso = (bir, yil, ufuk) => bir + ufuk * yil;
// Iki dogrunun kesistigi ufuk; negatifse kesisim yok.
const basabas = (b1, y1, b2, y2) => (b1 - b2) / (y2 - y1);

const m = kalemler(11);
console.log(`ihtiyac ${IHTIYAC} yetenek, urun ${IHTIYAC - m.uyarlanan} tanesini yerlesik sagliyor, ` +
  `${m.uyarlanan} tanesi uyarlanacak; bag: al ${m.alBag}, gelistir ${KAYNAK_BAG}\n`);
console.log("kalem              al (bir kez)  al (yillik)  gelistir (bir kez)  gelistir (yillik)");
console.log("------------------ ------------ ------------ ------------------- ------------------");
for (const ad of Object.keys(m.al))
  console.log(`${ad.padEnd(18)} ${m.al[ad][0].toFixed(0).padStart(12)} ${m.al[ad][1].toFixed(0).padStart(12)} ` +
    `${m.gel[ad][0].toFixed(0).padStart(19)} ${m.gel[ad][1].toFixed(0).padStart(18)}`);
console.log(`${"toplam".padEnd(18)} ${m.alBir.toFixed(0).padStart(12)} ${m.alYil.toFixed(0).padStart(12)} ` +
  `${m.gelBir.toFixed(0).padStart(19)} ${m.gelYil.toFixed(0).padStart(18)}`);

// TM23: sahibi disarida olan yol yilda 0,12, sahibi iceride olan yol 0,20 olasilikla kesilir.
// Dis yol yalniz "al" seceneginde vardir; ic yol (kaynak sistemler) iki secenekte de.
const DIS = 0.12, IC = 0.20;
const disBedel = K.cikisAl + (K.kurulum + m.uyarlanan * K.uyarlamaSaat) + m.alBag * K.alBag;
const icBedelAl = KAYNAK_BAG * K.alBag, icBedelGel = KAYNAK_BAG * K.gelBag;
const alYilR = m.alYil + DIS * disBedel + IC * icBedelAl;
const gelYilR = m.gelYil + IC * icBedelGel;

console.log("\nufuk (yil)      al  gelistir  kazanan   fark    al (riskli)  gelistir (riskli)  kazanan");
console.log("---------- ------- --------- -------- ------ -------------- ------------------ --------");
for (const ufuk of [1, 2, 3, 4, 5, 8]) {
  const a = tso(m.alBir, m.alYil, ufuk), g = tso(m.gelBir, m.gelYil, ufuk);
  const ar = tso(m.alBir, alYilR, ufuk), gr = tso(m.gelBir, gelYilR, ufuk);
  console.log(`${String(ufuk).padStart(10)} ${a.toFixed(0).padStart(7)} ${g.toFixed(0).padStart(9)} ` +
    `${(a < g ? "al" : "gelistir").padStart(8)} ${Math.abs(a - g).toFixed(0).padStart(6)} ` +
    `${ar.toFixed(0).padStart(14)} ${gr.toFixed(0).padStart(18)} ${(ar < gr ? "al" : "gelistir").padStart(8)}`);
}
console.log(`\nsahibi disarida olan nokta: al ${m.uyarlanan + 1}, gelistir 0; ` +
  `sahibi iceride olan bag: iki secenekte de ${KAYNAK_BAG}`);
console.log(`kesilme bedeli: dis ${disBedel} saat (al), ic ${icBedelAl} / ${icBedelGel} saat; ` +
  `yillik beklenen al ${(DIS * disBedel + IC * icBedelAl).toFixed(1)}, gelistir ${(IC * icBedelGel).toFixed(1)} saat`);
console.log(`basabas ufuk: risksiz ${basabas(m.alBir, m.alYil, m.gelBir, m.gelYil).toFixed(2)} yil, ` +
  `riskli ${basabas(m.alBir, alYilR, m.gelBir, gelYilR).toFixed(2)} yil`);

console.log("\nyerlesik  uyarlanan  al (bir kez)  al (yillik)  basabas ufuk (yil)  5 yilda kazanan");
console.log("--------- ---------- ------------- ------------ ------------------- ----------------");
for (const yerlesik of [6, 9, 11, 14, 17]) {
  const s = kalemler(yerlesik);
  const b = basabas(s.alBir, s.alYil, s.gelBir, s.gelYil);
  const kazanan = tso(s.alBir, s.alYil, 5) < tso(s.gelBir, s.gelYil, 5) ? "al" : "gelistir";
  console.log(`${String(yerlesik).padStart(9)} ${String(s.uyarlanan).padStart(10)} ` +
    `${s.alBir.toFixed(0).padStart(13)} ${s.alYil.toFixed(0).padStart(12)} ${b.toFixed(2).padStart(19)} ` +
    `${kazanan.padStart(16)}`);
}
```

```
ihtiyac 18 yetenek, urun 11 tanesini yerlesik sagliyor, 7 tanesi uyarlanacak; bag: al 6, gelistir 5

kalem              al (bir kez)  al (yillik)  gelistir (bir kez)  gelistir (yillik)
------------------ ------------ ------------ ------------------- ------------------
uyarlama                    138            0                 468                  0
tumlestirme bagi            132            0                  60                  0
egitim                       36           36                  54                  9
surum yukseltme               0           78                   0                 45
cikis                        96            0                  24                  0
toplam                      402          114                 606                 54

ufuk (yil)      al  gelistir  kazanan   fark    al (riskli)  gelistir (riskli)  kazanan
---------- ------- --------- -------- ------ -------------- ------------------ --------
         1     516       660       al    144            582                672       al
         2     630       714       al     84            762                738 gelistir
         3     744       768       al     24            942                804 gelistir
         4     858       822 gelistir     36           1122                870 gelistir
         5     972       876 gelistir     96           1302                936 gelistir
         8    1314      1038 gelistir    276           1841               1134 gelistir

sahibi disarida olan nokta: al 8, gelistir 0; sahibi iceride olan bag: iki secenekte de 5
kesilme bedeli: dis 366 saat (al), ic 110 / 60 saat; yillik beklenen al 65.9, gelistir 12.0 saat
basabas ufuk: risksiz 3.40 yil, riskli 1.79 yil

yerlesik  uyarlanan  al (bir kez)  al (yillik)  basabas ufuk (yil)  5 yilda kazanan
--------- ---------- ------------- ------------ ------------------- ----------------
        6         12           472          144                1.49         gelistir
        9          9           430          126                2.44         gelistir
       11          7           402          114                3.40         gelistir
       14          4           360           96                5.86               al
       17          1           318           78               12.00               al
```

#### Kazanan Zaman Ufkuna Bağlıdır

İlk tablo iki seçeneği beş kaleme ayırıyor ve kalemlerin farklı yönlere baktığını gösteriyor.
Satın alma bir kez ödenende üçte bir kadar ucuz (402'ye karşı 606 saat) ama yıllıkta iki kattan
fazla pahalı (114'e karşı 54 saat). İki kalem bu farkı üretiyor. Sürüm yükseltme kalemi satın
almada 78 saat, geliştirmede 45 saattir; satın almadaki sayı ürünün kendi takvimine değil, o
takvimin **kaç noktaya dokunduğuna** bağlıdır — yedi uyarlama noktası ve altı bağ. Uyarlama
azalırsa yükseltme de ucuzlar; uyarlama arttıkça her sürüm daha pahalıya gelir.

Bağ kalemi ikinci farkı taşıyor. Satın alınan yol beş kaynağa değil altısına bağlanıyor, çünkü
ürün veriyi kendi kopyasında ister; ve her bağ kendi uyarlayıcısını gerektirdiği için bağ başına
maliyet 22 saat, içeride yazılanda 12 saattir. Aynı beş kaynak, iki seçenekte 132'ye karşı 60
saat ediyor.

İkinci tablo bu iki doğruyu ufuk boyunca izliyor. Bir yıllık ufukta satın alma 144 saat önde, üç
yılda fark 24 saate iniyor, dördüncü yılda geliştirme öne geçiyor. Kesişim tam olarak **3,40
yıldadır**. Üç yıllık satırdaki 24 saatlik fark, katsayıların birini biraz farklı seçmenin
kazananı değiştireceği kadar küçüktür; kararı savunan belge tek bir kazanan adı değil, ufku ve
farkı da yazmalıdır.

#### Bağımlılık Riski de Bir Kalemdir

Buraya kadarki hesap iki yolun da sorunsuz sürdüğünü varsayıyor. Kurum ölçeğinde bu varsayım
tutmaz: bir yolun sahibi başkasıysa o yol kesilebilir ve kesilme bedeli ölçülebilir.

**TM23: sahibi dışarıda olan bir yol yılda 0,12, sahibi içeride olan bir yol 0,20 olasılıkla
kesilir.** Satın alınan yolda sahibi dışarıda olan sekiz nokta var: yedi uyarlama noktası ve
ürünün kendi veri kopyası bağı. Bunların kesilmesinin bedeli çıkış artı yeniden uyarlama artı
bağlar, yani 366 saat. Geliştirilen yolda dışarıda sahip yoktur; iki seçenekte de beş kaynak
bağının sahibi başka ekiplerdir ve onların kesilme bedeli satın almada 110, geliştirmede 60
saattir.

Yıllık beklenen bedel satın almada 65,9, geliştirmede 12,0 saat çıkıyor. Bu iki sayı yıllık
kalemin üstüne eklendiğinde başabaş ufku **3,40 yıldan 1,79 yıla** iniyor: risk hesaba katılmadan
üç yıl boyunca kazanan görünen seçenek, katıldığında ikinci yıldan itibaren kaybediyor. Bağımlılık
riski bir uyarı cümlesi değil, yıllık bir kalemdir; kaleme çevrilmediği sürece karara giremez.

Son tablo kararın aslında hangi değişkene bağlı olduğunu gösteriyor. Ürünün yerleşik sağladığı
yetenek 6'dan 17'ye çıktığında başabaş ufku 1,49 yıldan 12,00 yıla uzuyor ve beş yıllık ufkun
kazananı değişiyor. İki seçenek arasındaki fark, seçeneklerin adında değil, ürünün ihtiyacın ne
kadarını hazır karşıladığındadır. Kapsam yükseldikçe uyarlama noktası azalıyor, uyarlama azaldıkça
hem bir kez ödenen hem yıllık sürüm kalemi düşüyor; aynı hesap aynı katsayılarla ters yöne dönüyor.

#### Özet

- Toplam sahip olma maliyeti beş kalemdir: satın alma 402 saat artı yılda 114, geliştirme 606 saat
  artı yılda 54; bir kez ödenende ucuz olan seçenek yıllıkta pahalıdır (TM20, TM22).
- Sürüm yükseltme kalemi ürünün takvimine değil uyarlanan nokta sayısına bağlıdır: yedi uyarlama
  ve altı bağ yılda 78 saat ederken içeride yazılanın bakımı 45 saattir.
- Satın alınan yol beş kaynağa değil altısına bağlanır ve bağ başına 22 saat öder; aynı kaynaklar
  içeride yazılanda 60 saat eder. Bir ürünün kendi veri kopyası bir bağ kalemidir.
- Kazanan ufka bağlıdır: başabaş 3,40 yıl, üç yıllık ufuktaki fark yalnız 24 saat. Kararı savunan
  belge kazanan adıyla birlikte ufku ve farkı yazmalıdır.
- Bağımlılık riski yıllık bir kalemdir. Sahibi dışarıda olan sekiz nokta ve 366 saatlik kesilme
  bedeli yılda 65,9 saate karşılık geliyor; bu kalem eklendiğinde başabaş ufku 1,79 yıla iniyor
  (TM21, TM23).

#### Kurs Kapanışı

Kurs boyunca aynı kurgu ağ on kez modellendi ve her ders aynı ağdan farklı bir niceliği okudu.

| Ders | Modellenen kurum nesnesi | Ölçülen nicelik | Kararın bedeli |
|---|---|---|---|
| Kurumsal Mimari Kavramı | 9 sistem, 6 sahip, 13 yetenek, 10 veri varlığı | Hizalama 11/13; 2 boşluk, 6 örtüşme, 1 yetim sistem; 23 yönlü bağın 20'si sahiplik sınırını geçiyor | 6 örtüşmenin 5'i iki ayrı sahibe yayılıyor ve 5 uzlaşma gerektiriyor |
| Çerçeveler | Katman, görünüm, yönetişim döngüsü, olgunluk basamağı | Ayrıntılı biçim 12 sorunun 10'unu 106 kalemle, hafif biçim 5'ini 22 kalemle yanıtlıyor | Ek yanıt başına 16,8 kalem; değişiklik başına bakım 18'e karşı 2 kalem |
| İş Süreç Modelleme | 16 adımlı süreç; aktör, girdi kümesi, çıktı | 10 adım otomatik, 4'ü insan kararı; 8 aktör, 5 sahip, 10 el değiştirmenin 9'unda sahip değişiyor | Sınır zorlanınca 62 dokunuş kazanılıyor ama 10 yanlış karar ve 30 geri dönüş çıkıyor; başabaş 6,20 dokunuş |
| Yetenek Haritalama | Yetenek, karşılayan sistem, yazılan veri, okuyan sistem zinciri | 13 yeteneğin 11'i izlenebiliyor; kısa zincir 1,55, tam zincir 4,73 sistem gösteriyor | Koordinasyon turu 5'ten 29'a çıkıyor; dokunulacak sistemlerin yüzde 67'si ilk halkada görünmüyor |
| Tümleştirme Kalıpları | Tek bir bağın dört kalıpla kurulmuş hali | Uzak çağrıda yüz sorguya 100 kaynak isteği, ötekilerde 0; tazelik penceresi 0 ve 1 tik | Kaynak tek bir sütun adını değiştirince 5 bağın 3'ü sessizce yanlış yanıt veriyor, 3 sahibin 2'siyle koordinasyon gerekiyor |
| Kurumsal Servis Veri Yolu | Dokuz akışın ikili ve merkezî düzeni | 9'a karşı 8 yazılan birim; merkez 6 olay için 24 ileti işliyor; merkez kapalıyken 18 teslimden 0'ı gerçekleşiyor | Yedinci sistem 5 birim ve 4 sahipten 2 birim ve 2 sahibe iniyor; karşılığında merkezde sahibi başkası olan 4 kural birikiyor |
| Ana Veri Yönetimi | Üç sistemde tutulan üye kaydı ve altın kayıt | 720 yazma olayı dağıtık düzende 131, altın kayıtla 95 çakışan (üye, alan) çifti üretiyor | Kalan tutarsızlık iki düzende de 48; yazma adımı 1,00'dan 1,61'e çıkıyor, kaynak kapalıyken kabul edilen yazma 496/720'den 238/720'ye iniyor |
| Veri Ambarı ve Dönüştürme Hatları | Beş rapor, dört kaynak, sekiz adımlı dönüştürme hattı | Günde 163 sorgu ve 5.354.308 okunan kayıt; dönem taramasında işletim yükü yüzde 90,2, 27,2 ve 79,2 | Tek bir alan değişimi tek adımı kırıyor ama beş raporun beşi düşüyor; tazeliği bir saat olan rapor hiçbir dönemde ambara geçemiyor |
| Eski Sistemlerle Çalışma | Kaynak koduna erişilemeyen kayıt sistemi ve sarmalayıcı | 16 (çağıran, işlem) çiftinin 9'u kapanıyor, yüzde 71,8 çağrı; 7 çift ve 16.927 çağrı dışarıda kalıyor | Koordinasyon 24 adımdan 13'e iniyor ama birlikte yazılan pencere en yavaş sahibin turu yüzünden 30 günün altına inmiyor |
| Al veya Geliştir Kararı | Bir yeteneğin iki seçeneği ve beş maliyet kalemi | Satın alma 402 saat artı yılda 114, geliştirme 606 artı yılda 54; başabaş 3,40 yıl | Sahibi dışarıda olan 8 nokta yılda 65,9 saatlik beklenen bedel getiriyor ve başabaş ufku 1,79 yıla iniyor |

On dersin ortak kuralı tek cümledir: **kurum ölçeğinde ölçü bağdır.** Bir sistemin içinde ölçüm
birimi çağrı, kayıt ya da saniyeydi. Kurum ölçeğinde bunların hiçbiri tek başına karar taşımıyor;
her tabloda belirleyici olan bağ sayısı ve yönü, o bağın hangi sahiplik sınırını geçtiği ve bir
değişimin kaç sahibi koordinasyona çağırdığı oldu. Sarmalayıcının kapsamı da, altın kaydın seçimi
de, ambarın dönemi de aynı yerde sınırlandı: kendi kararının ulaşamadığı sahipte.

Kursun bıraktığı boşluk şudur. Bağlar kuruldu ve sayıldı, sahiplik ayrıldı, alınacak ile
geliştirilecek ayrıldı — ama bu kararların hiçbiri **hangi niteliği** koruduğunu söylemedi. Bir
merkezî düzen neyin uğruna seçildi: erişilebilirlik mi, değiştirilebilirlik mi, tutarlılık mı?
Üstelik kararların kâğıtta kalıp kalmadığını, verildikleri gibi sürüp sürmediğini denetleyen bir
mekanizma da kurulmadı. Sıradaki kurs, **M20/K04 Kalite Nitelikleri ve Yönetişim**, bu iki
soruyla açılır.

