---
title: 'Sistem Tasarımına Giriş'
source: 'https://academia.sh/tr/kurslar/sistem-tasarimina-giris'
language: tr
updated: '2026-08-17T04:43:05+00:00'
license: 'CC BY-SA 4.0'
lessons: 13
outcomes:
    - 'Bir tasarım problemini gereksinim ve kısıtlarına ayırır'
    - 'Kabaca büyüklük hesabıyla kaynak ihtiyacını tahmin eder'
    - 'Tutarlılık ve hizmet erişilebilirliği ödünleşimini doğru terimlerle ifade eder'
---

# Sistem Tasarımına Giriş

Bir tasarım probleminin gereksinim ve kısıtlarına ayrılması: işlevsel ile işlevsel olmayan gereksinimlerin ayrı belirleyiciler olarak ele alınması, kabaca büyüklük hesabıyla istek, veri ve bant genişliği ihtiyacının tahmin edilmesi, tasarımın diyagram ve karar gerekçesiyle anlatılması ve gecikme, verim, ölçeklenebilirlik, hizmet erişilebilirliği ile tutarlılık arasındaki gerilimlerin doğru terimlerle ifade edilmesi.

## Yaklaşım

Bir sistem tasarımı probleminin nasıl ele alındığı: bileşen, sözleşme ve nitelik kararlarının ayrılması, gereksinim toplama ile kapsamın daraltılması, işlevsel gereksinimlerin işlevsel olmayanlardan ayrı belirleyiciler olması, istek, veri ve bant genişliği ihtiyacının kabaca büyüklük hesabıyla tahmin edilmesi ve tasarımın diyagram, ödünleşim ve karar gerekçesiyle anlatılması.

### Sistem Tasarımı Nedir

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/sistem-tasarimi-nedir

Bir sistem tasarımının üç karar türüne ayrılması: bileşen sınırları, sınırdan geçen sözleşmeler ve niteliklere konan eşikler; eşiğin nereden geldiği sorusunun yanıtı olarak sayının üç sınıfının ayrılması ve sınıfsız sayının karar taşımadığının gösterilmesi.

Mimari Biçemler kursu aynı gönderi kitaplığının düzenlenişlerini karşılaştırdı ve her
karşılaştırmayı üç parçaya indirdi: nitelik senaryosu, eşik ve ölçülen değer. Eşikler o
kursta verilmişti; "sınırdan geçen bayt en çok 100" gibi bir sayı alıştırmanın girdisiydi.
Kursun son cümlesi bunu işaretledi: biçem seçimi burada da aynı üç parçayla savunulur,
değişen yalnız eşiklerin nereden geldiğidir.

Bu kurs o soruyla açılır. Bir sistemde eşik keyfi değildir, bir yerden gelir ve nereden
geldiği yazılabilir. Bu ders eşiğin bağlı olduğu karar türlerini ayırır ve kursun bütün
derslerinde geçerli olacak kuralı kurar: bir tasarım metnindeki her sayının sınıfı söylenir.

#### Üç Karar Türü

**Sistem tasarımı** (system design), birden çok bileşene bölünmüş bir yazılımın bu bölünmeyi
ve bölünmenin getirdiği kısıtları belirleme işidir. Bir programın parçaları birlikte
çalışır ve birlikte durur; bir sistemin **bileşenleri** (component) ayrı ölçeklenebilir ve
ayrı arızalanabilir. Bu iki cümle arasındaki fark, sistem tasarımının bütün sorularını
üretir.

Bir tasarım üç tür karardan oluşur ve üçü ayrı ayrı gerekçelendirilir.

**Bileşen kararı** hangi işin hangi birimde durduğunu söyler. Ölçüsü basittir: bir bileşenin
tek başına ölçeklenebilmesi ve durduğunda geri kalanın ne kadarının ayakta kalması.

**Sözleşme kararı** (contract) bileşen sınırından neyin geçtiğini söyler: hangi alanlar,
hangi yönde, hangi biçimde. Sınırdan geçen her alan iki bileşen arasında bir bağdır ve
sonradan değiştirilmesi ikisini birlikte değiştirmeyi gerektirir.

**Nitelik kararı** bir kalite niteliğine eşik koyar: takip sorgusunun yanıt süresi, kabul
edilen olay kaybı oranı, gün sonu işinin bitmesi gereken saat. Kalite niteliği ve nitelik
senaryosu Kalite ve Test Temelleri kursunun Kalite Nitelikleri dersinde kuruldu; burada
yeniden tanımlanmazlar, eşiğin taşıyıcısı olarak kullanılırlar.

İlk iki karar türü tek makinede de verilir ve Mimari Biçemler kursu onları orada ölçtü.
Üçüncüsü sistemi sistem yapan karardır, çünkü eşik yazılımın içinden değil dışından gelir:
yükten, beklentiden ve arıza tolerans kararından.

#### Sistem Olarak Gönderi Takibi

Kurs boyunca tek bir sistem üzerinde çalışılır: **gönderi takip ve ücretlendirme servisi**.
Kullanıcı bir takip numarasıyla gönderisinin durumunu sorar, taşıyıcı gönderi hareket
ettikçe durum olayı gönderir, satıcı gün sonunda ücretlendirme ister. Üç akış birbirinden
ayrılır çünkü üçü ayrı eşik ister: okuma akışı çok ve küçük, yazma akışı sürekli ve küçük,
toplu akış seyrek ve büyüktür.

Tasarımın ilk hâli bir veri yapısı olarak yazılabilir. Bileşenler, sözleşmeler ve akışlar
listelendiğinde tasarım hakkında sayılabilir şeyler ortaya çıkar.

```js
// tasarim/sistem.mjs — gonderi takip ve ucretlendirme servisi: bilesenler, sozlesmeler ve uc akis
export const BILESEN = {
  "takip-ucu": "takip sorgusunu yanitlar",
  "olay-alici": "tasiyicidan gelen durum olayini kabul eder",
  "gonderi-deposu": "gonderi ve teslimat durumunu tutar",
  "tarife-kurali": "bir gonderinin ucretini hesaplar",
  "toplu-isci": "saticinin gun sonu ucretlendirmesini uretir",
};

export const SOZLESME = {
  "takip-istegi": { yon: "istemci -> takip-ucu", alan: ["takipNo"] },
  "takip-yaniti": { yon: "takip-ucu -> istemci", alan: ["takipNo", "durum", "bolge", "guncellenme"] },
  "durum-olayi": { yon: "tasiyici -> olay-alici", alan: ["takipNo", "durum", "rota", "zaman"] },
  "durum-okuma": { yon: "takip-ucu -> gonderi-deposu", alan: ["takipNo"] },
  "durum-yazma": { yon: "olay-alici -> gonderi-deposu", alan: ["takipNo", "durum", "rota", "zaman"] },
  "gun-taramasi": { yon: "toplu-isci -> gonderi-deposu", alan: ["sozlesmeNo", "gun"] },
  "ucret-istegi": { yon: "toplu-isci -> tarife-kurali", alan: ["agirlik", "bolge", "oran"] },
};

export const AKIS = {
  okuma: { ad: "takip sorgusu", bilesen: ["takip-ucu", "gonderi-deposu"],
    sozlesme: ["takip-istegi", "durum-okuma", "takip-yaniti"] },
  yazma: { ad: "durum olayi", bilesen: ["olay-alici", "gonderi-deposu"],
    sozlesme: ["durum-olayi", "durum-yazma"] },
  toplu: { ad: "gun sonu ucretlendirme", bilesen: ["toplu-isci", "gonderi-deposu", "tarife-kurali"],
    sozlesme: ["gun-taramasi", "ucret-istegi"] },
};
```

Bu listeden çıkan ilk ölçü **tasarım yüzeyi**dir: kaç bileşen, kaç sözleşme, sözleşmelerin
taşıdığı kaç alan.

```js
// tasarim/yuzey.mjs — her akisin dokundugu bilesen, gectigi sozlesme ve tasidigi alan sayisi
import { BILESEN, SOZLESME, AKIS } from "./sistem.mjs";

console.log(`bilesen = ${Object.keys(BILESEN).length}, sozlesme = ${Object.keys(SOZLESME).length}`);
console.log(`${"akis".padEnd(23)}${"bilesen".padStart(8)}${"sozlesme".padStart(9)}${"alan".padStart(6)}`);
for (const a of Object.values(AKIS)) {
  const alan = a.sozlesme.reduce((t, s) => t + SOZLESME[s].alan.length, 0);
  console.log(`${a.ad.padEnd(23)}${String(a.bilesen.length).padStart(8)}${String(a.sozlesme.length).padStart(9)}${String(alan).padStart(6)}`);
}

for (const b of Object.keys(BILESEN)) {
  const akislar = Object.values(AKIS).filter((a) => a.bilesen.includes(b)).map((a) => a.ad);
  console.log(`${b.padEnd(16)} dokunan akis = ${akislar.length}${akislar.length > 1 ? ` (${akislar.join(", ")})` : ""}`);
}
```

```
bilesen = 5, sozlesme = 7
akis                    bilesen sozlesme  alan
takip sorgusu                 2        3     6
durum olayi                   2        2     8
gun sonu ucretlendirme        3        2     5
takip-ucu        dokunan akis = 1
olay-alici       dokunan akis = 1
gonderi-deposu   dokunan akis = 3 (takip sorgusu, durum olayi, gun sonu ucretlendirme)
tarife-kurali    dokunan akis = 1
toplu-isci       dokunan akis = 1
```

Son satırlar tasarımın en önemli olgusunu veriyor: beş bileşenin dördü tek akışa hizmet
ediyor, `gonderi-deposu` ise üçüne birden. Bu bileşen üç ayrı eşiğin kesiştiği yerdir ve
kursun ilerleyen konularında her yeni kısıt önce burada görünür. Bir tasarımın en kırılgan
noktası, en çok akışın dokunduğu bileşendir.

#### Eşiğin Nereden Geldiği

Nitelik kararı bir sayı taşır ve o sayının bir kaynağı vardır. Kaynak üç sınıftan birine
girer; hangisi olduğu metinde yazılmadıkça karar denetlenemez.

**Varsayım**, tasarımın girdisi olarak seçilen sayıdır: günlük etkin kullanıcı, kullanıcı
başına takip sorgusu, kayıt boyutu. Doğruluğu tasarımın içinden gösterilemez, bu yüzden
gerekçesi ve iki katına çıktığında ne olacağı yazılır.

**Hesap**, varsayımlardan aritmetikle çıkan sayıdır: saniyedeki istek, günlük veri artışı,
gereken bant genişliği. Bir hesap ancak dayandığı varsayımlar kadar geçerlidir.

**Ölçüm**, bir düzenekten çıkan sayıdır: bu makinede koşturulan bir işlevin süresi, bir
tamponun zirvesi. Ölçüm ortama bağlıdır ve bu bağlılık metinde işaretlenir.

Aşağıdaki betik dört kararı bu üç sınıfa göre denetler. Dördüncü karar bilinçli olarak
sınıfsız bırakılmıştır.

```js
// tasarim/karar.mjs — bir kararin yanindaki sayinin sinifi: varsayim, hesap ya da olcum
const SINIF = ["varsayim", "hesap", "olcum"];
const BUTCE_US = 50;                          // tarife cagrisi icin secilen butce (mikrosaniye)

// Iki varsayim; tam varsayim tablosu Kabaca Buyukluk Hesabi dersinde kurulur.
const V = { gunlukKullanici: 2_000_000, kullaniciBasinaSorgu: 6, gunlukGonderi: 400_000, gonderiBasinaOlay: 7 };
const sorgu = V.gunlukKullanici * V.kullaniciBasinaSorgu;
const olay = V.gunlukGonderi * V.gonderiBasinaOlay;

const KADEME = [[1, 3000], [5, 4800], [20, 9600]];
const BOLGE = { "34": 100, "06": 115, "35": 125 };
function tarife(g) {
  const kademe = KADEME.find(([k]) => g.agirlik <= k) ?? [0, 9600];
  const taban = Math.max(2500, Math.round((kademe[1] * BOLGE[g.bolge]) / 100));
  return taban - Math.round(taban * Math.min(g.oran, 0.4));
}

function ortancaMikrosaniye(kosu = 9) {
  const sureler = [];
  for (let i = 0; i < kosu; i += 1) {
    const bas = process.hrtime.bigint();
    tarife({ agirlik: 4, bolge: "35", oran: 0.15 });
    sureler.push(Number(process.hrtime.bigint() - bas) / 1000);
  }
  sureler.sort((a, b) => a - b);
  return sureler[Math.floor(kosu / 2)];
}

const KARAR = [
  { ad: "okuma yolu yazmadan ayri olceklenir", olcu: "okuma/yazma istek orani",
    sayi: (sorgu / olay).toFixed(2), sinif: "hesap" },
  { ad: "takip yaniti onbellekten karsilanir", olcu: "onbellek isabet orani",
    sayi: "0.90", sinif: "varsayim" },
  { ad: "tarife kurali surec icinde cagrilir", olcu: `${BUTCE_US} us butcesi`,
    sayi: ortancaMikrosaniye() < BUTCE_US ? "gecti" : "kaldi", sinif: "olcum" },
  { ad: "toplu is gece penceresinde kosar", olcu: "pencere saati",
    sayi: "4", sinif: null },
];

console.log(`${"karar".padEnd(37)}${"olcu".padEnd(25)}${"sayi".padStart(7)}  sinif`);
for (const k of KARAR) {
  console.log(`${k.ad.padEnd(37)}${k.olcu.padEnd(25)}${String(k.sayi).padStart(7)}  ${k.sinif ?? "-"}`);
}
const sinifsiz = KARAR.filter((k) => SINIF.includes(k.sinif) === false);
console.log(`\nsinifsiz sayi tasiyan karar = ${sinifsiz.length}: ${sinifsiz.map((k) => k.ad).join("; ")}`);
console.log(`gunluk takip sorgusu = ${sorgu}, gunluk durum olayi = ${olay}`);
console.log(`varsayim ikiye katlanirsa: kullanici basina sorgu 12 -> oran ${((sorgu * 2) / olay).toFixed(2)}`);
```

```
karar                                olcu                        sayi  sinif
okuma yolu yazmadan ayri olceklenir  okuma/yazma istek orani     4.29  hesap
takip yaniti onbellekten karsilanir  onbellek isabet orani       0.90  varsayim
tarife kurali surec icinde cagrilir  50 us butcesi              gecti  olcum
toplu is gece penceresinde kosar     pencere saati                  4  -

sinifsiz sayi tasiyan karar = 1: toplu is gece penceresinde kosar
gunluk takip sorgusu = 12000000, gunluk durum olayi = 2800000
varsayim ikiye katlanirsa: kullanici basina sorgu 12 -> oran 8.57
```

Dört satır dört ayrı okuma gerektiriyor. Okuma/yazma oranı 4,29 bir **hesap**tır: iki
varsayımın bölümüdür ve son satır duyarlılığını gösteriyor — kullanıcı başına sorgu 6 yerine
12 olsaydı oran 8,57 olurdu. Önbellek isabet oranı 0,90 bir **varsayım**dır; gerekçesi aynı
takip numarasının teslime kadar birkaç kez sorulmasıdır, doğruluğu ancak sistem çalıştığında
sınanır. Tarife çağrısının bütçeyi geçmesi bir **ölçüm**dür ve çıktıya ham süre değil yargı
yazılmıştır, çünkü ham süre bu makineye ve çalışma zamanı sürümüne bağlıdır.

Dördüncü satırın sınıfı yoktur. "Toplu iş dört saatlik gece penceresinde koşar" cümlesi
tasarım metninde makul görünür ama denetlenemez: dört saat bir varsayım mı, satıcının
beklentisinden çıkan bir hesap mı, yoksa bir koşumda ölçülmüş bir süre mi belirsizdir.
Sınıfsız sayı karar taşımaz — ölçülmemiş eksenin tartışmada ağırlığı olmadığı gibi.

#### Bileşen Kararı Nitelik Kararına Bağlıdır

Üç karar türü sırayla verilmez, birbirini belirler. Bileşen listesinin ilk hâli işlevsel
beklentiden çıkar: takip sorgusunu yanıtlayan bir uç, olayı kabul eden bir alıcı, durumu
tutan bir depo. Bu liste bir düzen değil, yalnız işin bölünüşüdür.

Bileşen sayısının bu listenin ötesine geçmesi nitelik kararlarından olur. Okuma akışının
eşiği yazma akışının eşiğinden bağımsız tutulmak isteniyorsa iki akış ayrı ölçeklenebilir
bileşenlere konur ve bileşen sayısı artar. Toplu işin gün sonu penceresi okuma akışının
yanıt süresini bozmamalıysa toplu iş kendi birimine taşınır. Her ayırma sözleşme sayısını ve
sınırdan geçen alan sayısını büyütür; Mimari Biçemler kursunda ölçülen bedel budur.

Sıralamanın yönü bu yüzden tersinden okunur: eşikler bilinmeden bileşen sayısı savunulamaz.
Bir tasarımı "beş bileşen" diye anlatmak, hangi eşiğin hangi ayırmayı zorunlu kıldığını
söylemedikçe bir karar değildir. Sonraki iki ders eşiğin kaynağını sırayla açar: önce
gereksinimlerin nasıl toplandığı, sonra işlevsel olanla işlevsel olmayanın ayrı belirleyici
olması.

#### Özet

- Sistem tasarımı üç tür karardan oluşur: bileşen sınırları, sınırdan geçen sözleşmeler ve
  niteliklere konan eşikler; ilk ikisi tek makinede de verilir, üçüncüsü yükten ve
  beklentiden gelir.
- Tasarım yüzeyi sayılabilir: örnek sistemde 5 bileşen, 7 sözleşme; takip sorgusu 3
  sözleşme ve 6 alan, durum olayı 2 sözleşme ve 8 alan, gün sonu ücretlendirmesi 2 sözleşme
  ve 5 alan taşıyor.
- En çok akışın dokunduğu bileşen en kırılgan noktadır: `gonderi-deposu` üç akışın da içinde,
  öteki dört bileşen birer akışta.
- Bir kararın yanındaki sayı üç sınıftan birine girer: varsayım seçilir ve duyarlılığı
  yazılır, hesap varsayımlardan çıkar, ölçüm bir düzenekten çıkar ve ortama bağlılığı
  işaretlenir.
- Sınıfsız sayı karar taşımaz; örnekte dört karardan biri sınıfsız kaldığı için denetlenemez
  sayıldı.
- Bileşen sayısı işlevsel bölünüşten değil nitelik eşiklerinden büyür; eşik bilinmeden
  bileşen sayısı savunulamaz.

#### Sonraki Adım

Bu ders eşiğin bir kaynağı olduğunu söyledi ama kaynağı aramadı. Örnekteki beş bileşen ve
yedi sözleşme hazır verildi; oysa gerçek bir tasarım işi tek satırlık bir istekle başlar:
"satıcıların gönderilerini takip edebileceği ve gün sonunda ücretlendirilebileceği bir servis."
O satır bileşen adı içermez, sayı içermez, sınır içermez. Sonraki ders o satırdan bir tasarıma
nasıl geçildiğini ele alır: hangi soruların
sorulduğunu, yanıtsız kalan her sorunun neden bir varsayıma dönüştüğünü ve kapsamın
daraltılmasının tasarım yüzeyinde ne kadar yer açtığını.

### Tasarım Problemine Yaklaşım

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/tasarim-problemine-yaklasim

Tek satırlık bir isteğin tasarıma çevrilmesi: soruların dört aileye ayrılması, her ailenin hangi tasarım adımını engellediğinin gösterilmesi, yanıtsız kalan sorunun varsayıma dönüşmesi ve kapsam daraltmasının tasarım yüzeyinde açtığı yerin ölçülmesi.

Önceki ders beş bileşenli bir tasarımı hazır verdi ve o tasarımın yüzeyini ölçtü. Gerçek bir
tasarım işi böyle başlamaz. Başlangıç noktası çoğunlukla tek bir cümledir: "satıcıların
gönderilerini takip edebileceği ve gün sonunda ücretlendirilebileceği bir servis." Bu cümlede
bileşen adı yok, sayı yok, sınır yok.

Bu ders o cümleden tasarıma geçişi ele alır. Geçiş iki işten oluşur: sorularak eksiklerin
bulunması ve kapsam daraltılarak tasarımın küçültülmesi. İkisi de ölçülebilir sonuç üretir —
birincisi yazılması gereken varsayım sayısını, ikincisi tasarım yüzeyindeki küçülmeyi.

#### İstek Eksiktir, Eksikliği Sayılabilir

Tek satırlık istek üç şeyi söylüyor: bir aktör (satıcı), iki yetenek (takip, ücretlendirme)
ve bir zamanlama (gün sonu). Söylemedikleri daha fazladır ve bunlar rastgele dağılmaz, dört
aileye toplanır.

**Aktör ve akış** soruları sistemin dışını tanımlar: kim istek gönderir, kim veri gönderir,
kim sonucu bekler. Yanıtları bileşen listesini belirler.

**Hacim** soruları yükü tanımlar: günde kaç istek, kaç kayıt, kayıt başına kaç bayt.
Yanıtları olmadan hiçbir hesap yapılamaz.

**Eşik** soruları kabul ölçütünü tanımlar: yanıt ne kadar sürebilir, ne kadar kayıp kabul
edilir, sonuç ne zaman hazır olmalı. Yanıtları nitelik kararlarının girdisidir.

**Kısıt** soruları tasarımın dışından gelen zorunlulukları tanımlar: veri ne kadar saklanır,
hangi kural nerede değişir, hangi bileşen dokunulamaz.

Ayrımın işe yaramasının nedeni, her ailenin belirli bir tasarım adımını engellemesidir. Soru
listesi bu bağla birlikte yazıldığında hangi adımın başlayabileceği hesaplanabilir hâle
gelir.

```js
// tasarim/soru.mjs — problem satirinin acmadigi sorular ve her sorunun engelledigi adim
export const ADIM = {
  "aktor ve akis": "bilesen listesi yazilamaz",
  hacim: "kabaca buyukluk hesabi baslamaz",
  esik: "nitelik karari verilemez",
  kisit: "veri saklama karari verilemez",
};

export const SORU = [
  { aile: "aktor ve akis", soru: "takip sorgusunu kim yapar", yanit: "alici ve satici, ayri yetkiyle" },
  { aile: "aktor ve akis", soru: "durum olayini kim gonderir", yanit: "tasiyici" },
  { aile: "aktor ve akis", soru: "ucretlendirmeyi kim baslatir", yanit: "satici, gun sonunda" },
  { aile: "hacim", soru: "gunde kac takip sorgusu gelir", yanit: null },
  { aile: "hacim", soru: "gunde kac gonderi olusur", yanit: null },
  { aile: "hacim", soru: "gonderi basina kac durum olayi gelir", yanit: null },
  { aile: "esik", soru: "takip yaniti en cok ne kadar surer", yanit: null },
  { aile: "esik", soru: "durum olayi kaybi kabul edilir mi", yanit: "edilmez, olay yeniden gonderilir" },
  { aile: "esik", soru: "ucret raporu ne zaman hazir olmali", yanit: null },
  { aile: "kisit", soru: "durum kaydi ne kadar saklanir", yanit: null },
  { aile: "kisit", soru: "tarife kurali kac yerde degisir", yanit: "tek yer" },
];
```

```js
// tasarim/gereksinim.mjs — yanitlanan soru, yanitsiz kalan soru ve yazilmasi gereken varsayim sayisi
import { ADIM, SORU } from "./soru.mjs";

console.log(`${"soru ailesi".padEnd(15)}${"yanit".padStart(6)}  engellenen adim`);
for (const [aile, adim] of Object.entries(ADIM)) {
  const grup = SORU.filter((s) => s.aile === aile);
  const yanitli = grup.filter((s) => s.yanit !== null).length;
  const engel = yanitli === grup.length ? "-" : adim;
  console.log(`${aile.padEnd(15)}${`${yanitli}/${grup.length}`.padStart(6)}  ${engel}`);
}

const yanitsiz = SORU.filter((s) => s.yanit === null);
console.log(`\ntoplam soru = ${SORU.length}, yanitli = ${SORU.length - yanitsiz.length}, yanitsiz = ${yanitsiz.length}`);
console.log(`yazilmasi gereken varsayim = ${yanitsiz.length}`);
for (const s of yanitsiz) console.log(`  varsayim gerekiyor: ${s.soru}`);
```

```
soru ailesi     yanit  engellenen adim
aktor ve akis     3/3  -
hacim             0/3  kabaca buyukluk hesabi baslamaz
esik              1/3  nitelik karari verilemez
kisit             1/2  veri saklama karari verilemez

toplam soru = 11, yanitli = 5, yanitsiz = 6
yazilmasi gereken varsayim = 6
  varsayim gerekiyor: gunde kac takip sorgusu gelir
  varsayim gerekiyor: gunde kac gonderi olusur
  varsayim gerekiyor: gonderi basina kac durum olayi gelir
  varsayim gerekiyor: takip yaniti en cok ne kadar surer
  varsayim gerekiyor: ucret raporu ne zaman hazir olmali
  varsayim gerekiyor: durum kaydi ne kadar saklanir
```

Çıktının en çok işe yarayan satırı ilk tablodur. Aktör ve akış ailesi tamamlandığı için
bileşen listesi yazılabilir; önceki dersin beş bileşeni bu yüzden yazılabilmişti. Hacim
ailesinde yanıt oranı 0/3 olduğu için kabaca büyüklük hesabı başlamaz. Eşik ailesinde 1/3
yanıt var, yani nitelik kararlarının üçte ikisi askıda.

#### Yanıtsız Soru Varsayıma Dönüşür

Yanıtsız altı sorunun karşılığı altı varsayımdır. Bu, tasarım işinin durmaması için gereken
adımdır: bir soru yanıtlanamıyorsa yerine bir sayı seçilir, o sayının **varsayım** olduğu
yazılır ve gerekçesi bir cümleyle verilir.

Varsayımın maliyeti sıfır değildir. Yanlış bir varsayım üstüne kurulan bütün hesaplar aynı
oranda yanlıştır ve bunu görünür kılmanın tek yolu duyarlılığı yazmaktır: varsayım iki katına
çıkarsa hangi hesap kaç katına çıkar. Önceki ders bunun bir örneğini verdi — kullanıcı başına
sorgu 6 yerine 12 alındığında okuma/yazma oranı 4,29'dan 8,57'ye çıkıyordu.

Varsayım ile eşik karıştırılmamalıdır. Varsayım sistemin dışındaki dünya hakkında bir
tahmindir ve ölçülerek düzeltilir. Eşik ise bir karardır: kabul edilen sınırdır ve ölçümle
düzeltilmez, tartışmayla değişir. "Günde on iki milyon sorgu gelir" bir varsayım, "takip
yanıtı 200 milisaniyeyi geçmez" bir eşiktir.

#### Kapsamı Daraltmak

İkinci iş, sorular yanıtlanırken ortaya çıkan yeteneklerin bir bölümünü tasarımın dışında
bırakmaktır. Daraltmanın gerekçesi zaman değil, ölçüdür: her yetenek tasarım yüzeyine bileşen,
sözleşme ve alan ekler.

Aşağıdaki liste yedi kapsam maddesini ve her birinin yüzeye katkısını taşıyor. Üçü içeride,
dördü dışarıdadır; dışarıda bırakılan her madde bir gerekçe ve bir geri dönüş koşulu
taşımalıdır. Son madde bilinçli olarak kayıtsız bırakılmıştır.

```js
// tasarim/kapsam.mjs — kapsam maddelerinin tasarim yuzeyine katkisi ve daraltmanin kaydi
const MADDE = [
  { ad: "takip sorgusu", kapsam: "ic",
    bilesen: ["takip-ucu", "gonderi-deposu"], sozlesme: 3, alan: 6 },
  { ad: "durum olayi kabulu", kapsam: "ic",
    bilesen: ["olay-alici", "gonderi-deposu"], sozlesme: 2, alan: 8 },
  { ad: "gun sonu ucretlendirme", kapsam: "ic",
    bilesen: ["toplu-isci", "gonderi-deposu", "tarife-kurali"], sozlesme: 2, alan: 5 },
  { ad: "alici bildirimi", kapsam: "dis",
    bilesen: ["bildirim-ucu", "sablon-deposu"], sozlesme: 3, alan: 9,
    neden: "takip sorgusunun esigini degistirmiyor", geri: "her durum olayi bildirim doguracaksa" },
  { ad: "satici arayuzu", kapsam: "dis",
    bilesen: ["arayuz-sunucusu", "oturum-deposu"], sozlesme: 4, alan: 14,
    neden: "ucret raporu dosya olarak da teslim edilebilir", geri: "rapor gun icinde istenirse" },
  { ad: "tasiyici sozlesme yonetimi", kapsam: "dis",
    bilesen: ["sozlesme-ucu"], sozlesme: 2, alan: 7,
    neden: "tarife kurali ucretlendirme kitapligindan gelir, burada degismez", geri: "tarife bolgeye gore surumlenirse" },
  { ad: "rota planlama", kapsam: "dis",
    bilesen: ["rota-planlayici", "konum-alici"], sozlesme: 3, alan: 11,
    neden: null, geri: null },
];

function yuzey(maddeler) {
  const bilesen = new Set(maddeler.flatMap((m) => m.bilesen));
  return {
    bilesen: bilesen.size,
    sozlesme: maddeler.reduce((t, m) => t + m.sozlesme, 0),
    alan: maddeler.reduce((t, m) => t + m.alan, 0),
  };
}

const genis = yuzey(MADDE);
const dar = yuzey(MADDE.filter((m) => m.kapsam === "ic"));
console.log(`${"olcu".padEnd(10)}${"genis".padStart(7)}${"dar".padStart(6)}${"oran".padStart(7)}`);
for (const a of ["bilesen", "sozlesme", "alan"]) {
  console.log(`${a.padEnd(10)}${String(genis[a]).padStart(7)}${String(dar[a]).padStart(6)}${(dar[a] / genis[a]).toFixed(2).padStart(7)}`);
}

const disi = MADDE.filter((m) => m.kapsam === "dis");
const kayitli = disi.filter((m) => m.neden !== null && m.geri !== null);
console.log(`\nkapsam disi madde = ${disi.length}, gerekcesi ve geri donus kosulu yazili = ${kayitli.length}`);
for (const m of disi.filter((x) => kayitli.includes(x) === false)) {
  console.log(`  kayitsiz daraltma: ${m.ad} (${m.bilesen.length} bilesen, ${m.alan} alan geri gelebilir)`);
}
for (const m of kayitli) console.log(`  ${m.ad.padEnd(26)} geri donus kosulu: ${m.geri}`);
```

```
olcu        genis   dar   oran
bilesen        12     5   0.42
sozlesme       19     7   0.37
alan           60    19   0.32

kapsam disi madde = 4, gerekcesi ve geri donus kosulu yazili = 3
  kayitsiz daraltma: rota planlama (2 bilesen, 11 alan geri gelebilir)
  alici bildirimi            geri donus kosulu: her durum olayi bildirim doguracaksa
  satici arayuzu             geri donus kosulu: rapor gun icinde istenirse
  tasiyici sozlesme yonetimi geri donus kosulu: tarife bolgeye gore surumlenirse
```

Daraltmanın kazancı üç sayıda görünüyor: bileşen 12'den 5'e, sözleşme 19'dan 7'ye, sınırdan
geçen alan 60'tan 19'a iniyor. Üç oran birbirinden farklı ve bu fark bilgi taşıyor. Bileşen
oranı 0,42, alan oranı 0,32; yani dışarıda bırakılan maddeler bileşen sayısından çok
sözleşme yüzeyini büyütüyordu. Kapsamı daraltmanın en büyük kazancı bileşen adedini
azaltmak değil, bileşenler arasındaki bağ sayısını azaltmaktır.

Üçüncü satırın önceki dersteki sayıyla aynı olması rastlantı değil: daraltılmış kapsamın
yüzeyi 5 bileşen ve 7 sözleşmedir, yani önceki dersin tasarımı bu daraltmanın sonucudur.

#### Daraltmanın Kaydı

Dört kapsam dışı maddenin üçü kayıtlı, biri kayıtsız. Kayıt iki alandan oluşur ve ikisi de
zorunludur.

**Gerekçe** maddenin neden çıkarıldığını söyler ve doğru gerekçe hep aynı biçimdedir: bu
madde hangi eşiği değiştirmiyor. Alıcı bildirimi çıkarıldı çünkü takip sorgusunun yanıt
süresi eşiğini değiştirmiyor; satıcı arayüzü çıkarıldı çünkü ücret raporu dosya olarak da
teslim edilebilir.

**Geri dönüş koşulu** maddenin hangi durumda tekrar kapsama gireceğini söyler. Bu alan
tasarımı ileriye dönük olarak korur: koşul yazılıysa, o koşul gerçekleştiğinde tasarımın
yeniden açılacağı bilinir ve aradaki kararlar bu bilgiyle verilir. Alıcı bildiriminin koşulu
her durum olayının bir bildirim doğurması; bu koşul gerçekleşirse yazma akışının hacmi
değişir ve önceki dersin okuma/yazma oranı geçersizleşir.

Kayıtsız bırakılan madde tam bu yüzden risktir. Rota planlama kapsam dışıdır ama neden
çıkarıldığı ve ne zaman döneceği yazılmadığı için tasarım onu hesaba katmıyor: geri geldiğinde
2 bileşen ve 11 alan bir anda yüzeye eklenir. Kapsam dışı bırakmak bir karardır ve her karar
gibi gerekçesiyle yazılır; yazılmayan daraltma, unutulmuş bir yetenekten ayırt edilemez.

#### Özet

- Tek satırlık bir istek dört soru ailesine ayrılır: aktör ve akış, hacim, eşik, kısıt; her
  aile belirli bir tasarım adımını engeller.
- Örnekte 11 sorunun 5'i yanıtlı: aktör ve akış 3/3 olduğu için bileşen listesi yazılabildi,
  hacim 0/3 olduğu için kabaca büyüklük hesabı başlamıyor.
- Yanıtsız kalan 6 soru 6 varsayıma dönüşür; varsayımın gerekçesi ve duyarlılığı yazılmadıkça
  üstüne kurulan hesap denetlenemez.
- Varsayım dünya hakkında bir tahmindir ve ölçümle düzeltilir; eşik bir karardır ve
  tartışmayla değişir.
- Kapsam daraltması ölçülebilir yer açtı: bileşen 12'den 5'e (0,42), sözleşme 19'dan 7'ye
  (0,37), sınırdan geçen alan 60'tan 19'a (0,32) indi.
- Kapsam dışı bırakılan madde gerekçe ve geri dönüş koşulu taşımalıdır; örnekteki dört
  maddeden biri kayıtsız kaldığı için geri geldiğinde 2 bileşen ve 11 alan hesapsız eklenir.

#### Sonraki Adım

Soru listesindeki dört aileden ikisi aynı şeyi soruyor gibi görünüyor: aktör ve akış soruları
sistemin ne yapacağını, eşik soruları bunu nasıl yapacağını. Bu ikisi ayrı yanıtlanabildiği
için ayrı belirleyicidir ve ayrı yazılırlar. Sonraki ders bu ayrımı kurar: işlevsel
gereksinimler bileşen listesini üretir, işlevsel olmayan gereksinimler o listenin kaç parçaya
bölüneceğini üretir. İkisi bağımsız değiştirilebilir ve bunun kanıtı ölçülebilir — aynı
işlevsel liste iki ayrı eşik kümesiyle iki ayrı tasarım verir.

### İşlevsel ve İşlevsel Olmayan Gereksinimler

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/islevsel-ve-islevsel-olmayan-gereksinimler

İki gereksinim türünün ayrı belirleyici olduğunun gösterilmesi: işlevsel listenin hangi tür bileşenin gerektiğini, eşiklerin aynı işin kaç parçaya bölüneceğini belirlemesi, tek tek oynatılan eşiklerin bileşen sayısında ürettiği değişim ve bir eşiğin tasarımı küçültebilmesi.

Önceki ders soruları dört aileye ayırdı ve iki ailenin farklı şeyler sorduğunu işaretledi:
aktör ve akış soruları sistemin ne yapacağını, eşik soruları bunu hangi sınır içinde
yapacağını. İki yanıt kümesi birbirinden bağımsız değişebiliyorsa iki ayrı belirleyicidir.

Bu ders o bağımsızlığı gösterir. İşlevsel gereksinim listesi hangi türden bileşenin bulunması
gerektiğini söyler; eşikler aynı işin kaç parçaya bölüneceğini söyler. İkisi ayrı ayrı
oynatıldığında tasarımda farklı şeyler değişir ve bu fark sayılabilir.

#### İki Belirleyici

**İşlevsel gereksinim** (functional requirement) sistemin ne yaptığını söyler ve doğru ya da
yanlış biçiminde yanıtlanır: takip numarasıyla durum döndürülür, aynı olayın ikinci kez
gelmesi yutulur. Kalite ve Test Temelleri kursunun Kalite Nitelikleri dersi aynı kavramı
"işlevsel beklenti" adıyla kurmuştu; burada katalog biçimi olan işlevsel gereksinim kullanılır,
kastedilen aynı şeydir.

**İşlevsel olmayan gereksinim** (non-functional requirement) sistemin bu işi hangi sınır
içinde yaptığını söyler ve dereceli yanıtlanır. Aynı derste kurulan kalite niteliği ve nitelik
senaryosu kavramları burada yeniden tanımlanmaz; işlevsel olmayan gereksinim, bir kalite
niteliğine eşik koyan nitelik senaryosunun yazılı hâlidir.

Ayrımın sınavı şudur: bir gereksinim tek bir girdi–çıktı çiftiyle sınanabiliyorsa işlevseldir.
Sınanması için bir yük, bir ortam ve bir eşik gerekiyorsa işlevsel değildir.

#### Eşiğin Sınıfı Yoktur, Kaynağı Vardır

İlk ders sayıları üç sınıfa ayırdı: varsayım, hesap, ölçüm. Eşik bu üçünden hiçbiri değildir
ve bu kasıtlıdır. Varsayım dünya hakkında bir tahmindir, hesap varsayımlardan çıkar, ölçüm bir
düzenekten çıkar; üçü de bir olguyu bildirir. Eşik ise bir olguyu değil bir kabulü bildirir:
hangi değerin yeterli sayıldığını.

Bu yüzden eşiğin yanına sınıf değil **kaynak** yazılır: eşik hangi beklentiden geliyor. "Takip
yanıtı 200 milisaniyeyi geçmez" eşiğinin kaynağı alıcının takip sayfasından beklediği yanıttır;
"olay kaybı sıfırdır" eşiğinin kaynağı taşıyıcı sözleşmesindeki teslim yükümlülüğüdür. Kaynağı
yazılmayan eşik tartışılamaz, çünkü kimin adına konduğu bilinmez.

Bir işlevsel olmayan gereksinim tam olarak şu biçimde yazılır — dört parça nitelik
senaryosundan, beşinci satır bu kursun eklediği kaynak alanıdır:

- **Uyaran:** alıcı takip numarasıyla gönderisinin durumunu sorar.
- **Ortam:** sistem tepe yükünde çalışmaktadır.
- **Yanıt:** gönderinin son durumu, bölgesi ve güncellenme zamanı döner.
- **Yanıt ölçütü:** yanıt süresinin ortancası 200 milisaniyeyi geçmez.
- **Eşiğin kaynağı:** alıcının takip sayfasından beklediği yanıt.

İkinci parça şimdilik boştur. "Tepe yükünde" bir sayı değildir ve bu senaryo ölçülemez
durumdadır; ortamın sayıya çevrilmesi sonraki dersin işidir.

#### Aynı İşlev, İki Eşik Kümesi

Bağımsızlığı göstermenin yolu bir tarafı sabit tutup öteki tarafı oynatmaktır. Altı işlevsel
gereksinim sabit tutulur, iki ayrı eşik kümesi denenir.

Eşikten bileşene geçiş bir kural kümesiyle yapılır. Bu kurallar bir **modeldir**, evrensel bir
türetme değil: her kural bir eşik koşulunu bir bileşen değişikliğine bağlar ve gerekçesi
yanında durur. Kuralların dördüncüsü öteki üçünün tersine çalışır ve bileşen çıkarır.

```js
// tasarim/gereksinim.mjs — islevsel liste, esik kumeleri ve ikisinden bilesen listesi ureten model
export const ISLEV = [
  { no: "I1", akis: "okuma", islem: "takipNo ile gonderinin durumunu dondur" },
  { no: "I2", akis: "okuma", islem: "gonderinin rota gecmisini dondur" },
  { no: "I3", akis: "yazma", islem: "tasiyicidan gelen durum olayini kaydet" },
  { no: "I4", akis: "yazma", islem: "ayni olayin ikinci kez gelmesini yut" },
  { no: "I5", akis: "toplu", islem: "saticinin gununu tara ve ucret uret" },
  { no: "I6", akis: "toplu", islem: "ucret raporunu dosya olarak teslim et" },
];

export const ESIK = {
  gevsek: { okumaMs: 900, olayKaybi: 0.01, topluSaat: 12, ucretMs: 40 },
  siki: { okumaMs: 200, olayKaybi: 0, topluSaat: 4, ucretMs: 1 },
};

export const KAYNAK = {
  okumaMs: "alicinin takip sayfasindan bekledigi yanit",
  olayKaybi: "tasiyici sozlesmesindeki teslim yukumlulugu",
  topluSaat: "saticinin raporu sabah istemesi",
  ucretMs: "taramanin gonderi basina harcayabildigi sure",
};

// Islevsel liste hangi turden bilesenin bulunmasi gerektigini belirler.
export function taban(islevler) {
  const b = new Set(["servis", "gonderi-deposu"]);
  if (islevler.some((i) => i.islem.includes("ucret"))) b.add("tarife-servisi");
  return b;
}

// Esikler ayni isin kac parcaya bolunecegini belirler.
export const KURAL = [
  { ad: "okuma esigi 300 ms altinda", kosul: (e) => e.okumaMs <= 300,
    ekle: ["takip-ucu", "olay-alici"], cikar: ["servis"] },
  { ad: "olay kaybi tolere edilmiyor", kosul: (e) => e.olayKaybi === 0,
    ekle: ["olay-kuyrugu"], cikar: [] },
  { ad: "toplu pencere 6 saatin altinda", kosul: (e) => e.topluSaat < 6,
    ekle: ["toplu-isci"], cikar: [] },
  { ad: "ucret cagrisi 1 ms altinda", kosul: (e) => e.ucretMs <= 1,
    ekle: [], cikar: ["tarife-servisi"] },
];

export function tasarim(islevler, esik) {
  const bilesen = taban(islevler);
  const isleyen = [];
  for (const k of KURAL) {
    if (k.kosul(esik) === false) continue;
    for (const b of k.cikar) bilesen.delete(b);
    for (const b of k.ekle) bilesen.add(b);
    isleyen.push(k.ad);
  }
  return { bilesen: [...bilesen].sort(), isleyen };
}
```

```js
// tasarim/turet.mjs — ayni islevsel liste iki esik kumesiyle iki ayri tasarim veriyor
import { ESIK, ISLEV, KAYNAK, KURAL, tasarim } from "./gereksinim.mjs";

const sayim = (a) => ISLEV.filter((i) => i.akis === a).length;
console.log(`islevsel gereksinim = ${ISLEV.length} (okuma ${sayim("okuma")}, yazma ${sayim("yazma")}, toplu ${sayim("toplu")})`);
console.log(`${"esik".padEnd(11)}${"gevsek".padStart(7)}${"siki".padStart(6)}  esigin kaynagi`);
for (const a of Object.keys(KAYNAK)) {
  console.log(`${a.padEnd(11)}${String(ESIK.gevsek[a]).padStart(7)}${String(ESIK.siki[a]).padStart(6)}  ${KAYNAK[a]}`);
}

for (const [ad, esik] of Object.entries(ESIK)) {
  const t = tasarim(ISLEV, esik);
  console.log(`\n${ad}: isleyen kural ${t.isleyen.length}/${KURAL.length}, bilesen ${t.bilesen.length}`);
  console.log(`  ${t.bilesen.join(", ")}`);
}
```

```
islevsel gereksinim = 6 (okuma 2, yazma 2, toplu 2)
esik        gevsek  siki  esigin kaynagi
okumaMs        900   200  alicinin takip sayfasindan bekledigi yanit
olayKaybi     0.01     0  tasiyici sozlesmesindeki teslim yukumlulugu
topluSaat       12     4  saticinin raporu sabah istemesi
ucretMs         40     1  taramanin gonderi basina harcayabildigi sure

gevsek: isleyen kural 0/4, bilesen 3
  gonderi-deposu, servis, tarife-servisi

siki: isleyen kural 4/4, bilesen 5
  gonderi-deposu, olay-alici, olay-kuyrugu, takip-ucu, toplu-isci
```

Altı işlevsel gereksinim iki koşumda da aynı. Gevşek eşiklerle hiçbir kural işlemiyor ve
tasarım üç bileşende kalıyor; sıkı eşiklerle dört kural işliyor ve tasarım beş bileşene
çıkıyor. Bir tasarımın "üç bileşenli" ya da "beş bileşenli" olması bu yüzden işlevsel listeden
okunamaz.

Beş bileşenin bileşimi de dikkat çekiyor: `servis` ve `tarife-servisi` listede yok, yerlerine
`takip-ucu`, `olay-alici`, `olay-kuyrugu` ve `toplu-isci` var. Dördüncü kural bir bileşen
çıkardığı için sıkılaşma bileşen sayısını tek yönde artırmıyor. Olay kuyruğunun bir bileşen
olarak görünmesi, eşzamansız teslim mekaniğinin burada anlatıldığı anlamına gelmez; mesaj
kuyruğu Eşzamansız İşleme kursunda kuruldu ve burada yalnız bir bileşen olarak sayılıyor.

#### Bağımsızlığın İki Yönü

Bağımsızlık iki yönlü olmalıdır: işlevsel listeye ekleme yapıldığında eşikler yerinde
kalmalı, eşik oynatıldığında işlevsel liste yerinde kalmalı. İkinci betik ikisini de sınar.

```js
// tasarim/bagimsizlik.mjs — islevsel listeyi ve esikleri tek tek oynatip bilesen sayisindaki degisimi olcer
import { ESIK, ISLEV, tasarim } from "./gereksinim.mjs";

const temel = tasarim(ISLEV, ESIK.gevsek);
console.log(`baslangic: islev ${ISLEV.length}, esik gevsek, bilesen ${temel.bilesen.length}`);

const I7 = { no: "I7", akis: "okuma", islem: "gonderinin tahmini teslim gununu dondur" };
const genis = tasarim([...ISLEV, I7], ESIK.gevsek);
console.log(`islev eklendi (${I7.no}): islev ${ISLEV.length + 1}, bilesen ${genis.bilesen.length}, ` +
  `degisim ${genis.bilesen.length - temel.bilesen.length}`);

console.log(`\n${"tek esik degisimi".padEnd(26)}${"bilesen".padStart(8)}${"degisim".padStart(8)}  cikan/giren`);
for (const a of Object.keys(ESIK.gevsek)) {
  const t = tasarim(ISLEV, { ...ESIK.gevsek, [a]: ESIK.siki[a] });
  const cikan = temel.bilesen.filter((b) => t.bilesen.includes(b) === false);
  const giren = t.bilesen.filter((b) => temel.bilesen.includes(b) === false);
  const not = [cikan.length ? `-${cikan.join(" -")}` : "", giren.length ? `+${giren.join(" +")}` : ""].filter(Boolean).join(" ");
  console.log(`${`${a} ${ESIK.gevsek[a]} -> ${ESIK.siki[a]}`.padEnd(26)}${String(t.bilesen.length).padStart(8)}` +
    `${String(t.bilesen.length - temel.bilesen.length).padStart(8)}  ${not}`);
}
```

```
baslangic: islev 6, esik gevsek, bilesen 3
islev eklendi (I7): islev 7, bilesen 3, degisim 0

tek esik degisimi          bilesen degisim  cikan/giren
okumaMs 900 -> 200               4       1  -servis +olay-alici +takip-ucu
olayKaybi 0.01 -> 0              4       1  +olay-kuyrugu
topluSaat 12 -> 4                4       1  +toplu-isci
ucretMs 40 -> 1                  2      -1  -tarife-servisi
```

İlk iki satır bir yönü veriyor: yedinci işlevsel gereksinim eklendiğinde bileşen sayısı 3'te
kalıyor, değişim 0. Yeni işlev var olan okuma akışının içine düşüyor ve bileşen listesini
oynatmıyor. İşlevsel liste büyüdükçe tasarımın büyüdüğü sezgisi bu satırla yanlışlanıyor.

Tablo öteki yönü veriyor. Dört eşiğin her biri tek başına oynatıldığında işlevsel liste altı
maddede kalmasına karşın bileşen sayısı değişiyor: üç eşik onu 3'ten 4'e çıkarıyor, biri 3'ten
2'ye indiriyor. Son satır en öğretici olanıdır. Ücret çağrısının bütçesi 40 milisaniyeden 1
milisaniyeye çekildiğinde tarife servisi ayrı bir bileşen olarak kalamıyor, çünkü ayrı bileşen
olmanın bedeli bir ağ adımıdır ve o adım bütçeye sığmıyor. Sıkı eşik her zaman daha çok parça
istemez; bazen tersini ister.

Üçüncü satırdaki çıkan ve giren bileşenler ayrımı da bilgi taşıyor. Okuma eşiği sıkılaştığında
`servis` çıkıp yerine iki bileşen giriyor, yani bu bir ekleme değil bir **bölme**dir. Öteki iki
eşik yalnız ekleme yapıyor. Bir tasarım değişikliğinin bölme mi ekleme mi olduğu, sözleşme
yüzeyine etkisini belirler: bölme var olan bir sınırı ikiye ayırır, ekleme yeni bir sınır
getirir.

#### Özet

- İşlevsel gereksinim sistemin ne yaptığını söyler ve tek bir girdi–çıktı çiftiyle sınanır;
  işlevsel olmayan gereksinim hangi sınır içinde yaptığını söyler ve yük, ortam ve eşik ister.
- Eşiğin varsayım, hesap ya da ölçüm sınıfı yoktur; eşik bir kabuldür ve yanına sınıf değil
  kaynak yazılır — hangi beklentiden geldiği.
- İşlevsel olmayan gereksinim nitelik senaryosunun dört parçasıyla ve eşiğin kaynağıyla
  yazılır; örnek senaryonun ortam parçası hâlâ sayısızdır.
- Aynı altı işlevsel gereksinim gevşek eşiklerle 3, sıkı eşiklerle 5 bileşen verdi; bileşen
  sayısı işlevsel listeden okunamaz.
- Yedinci işlevsel gereksinim bileşen sayısını değiştirmedi (değişim 0); dört eşiğin her biri
  tek başına değiştirdi (üçü +1, biri −1).
- Sıkı eşik her zaman daha çok bileşen istemez: ücret çağrısı bütçesi 1 milisaniyeye
  çekildiğinde tarife servisi ayrı bileşen olmaktan çıktı.

#### Sonraki Adım

Nitelik senaryosunun dört parçasından üçü yazıldı, biri boş kaldı: ortam. "Tepe yükünde
çalışmaktadır" cümlesi eşiği ölçülemez bırakıyor, çünkü tepe yükün kaç istek olduğu
yazılmadı. Aynı boşluk eşiklerin kendisinde de var — 200 milisaniyenin karşılanabilir olup
olmadığı, saniyede kaç isteğin geldiği bilinmeden söylenemez. Sonraki ders bu boşluğu doldurur:
önceki derste altı varsayıma dönüşen altı yanıtsız soru bir varsayım tablosunda toplanır ve
tablodan istek hızı, veri artışı ve bant genişliği ihtiyacı aritmetikle çıkarılır.

### Kabaca Büyüklük Hesabı

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/kabaca-buyukluk-hesabi

On üç varsayımın tek bir tabloda toplanması ve tablodan istek hızı, veri artışı ile bant genişliği ihtiyacının aritmetikle çıkarılması: tepe yükün hesaplanması, önbelleğin arkasındaki yük dengesinin bulunması, seyrek toplu işin bant genişliğine hâkim olması ve her varsayımın hangi sonucu kaç katına çıkardığının ölçülmesi.

Önceki iki ders sayısı olmayan iki boşluk bıraktı. Nitelik senaryosunun ortam parçası "tepe
yükünde" yazıyordu ve tepe yükün kaç istek olduğu belirsizdi; eşiklerin karşılanabilir olup
olmadığı da aynı belirsizliğe bağlıydı. İkinci derste altı yanıtsız soru altı varsayıma
dönüşmüştü ama varsayımlar hiçbir yere yazılmamıştı.

Bu ders o boşluğu doldurur. **Kabaca büyüklük hesabı** (back-of-the-envelope estimate), bir
tasarımın kaynak ihtiyacını az sayıda varsayımdan aritmetikle çıkarma işidir. Amacı doğru sayıyı
bulmak değil, doğru **büyüklük sırasını** bulmak ve tasarım kararlarının hangi varsayıma
dayandığını görünür kılmaktır.

#### Varsayım Tablosu

Bütün hesapların tek bir kaynağı olur. Aşağıdaki on üç varsayım kursun geri kalanında da
kullanılır; hiçbir ders kendi başına yeni bir hacim sayısı seçmez.

| Kod | Varsayım | Değer | Gerekçe |
|---|---|---|---|
| V1 | günlük etkin kullanıcı | 2.000.000 | takip sayfasını günde en az bir kez açan alıcı ve satıcı |
| V2 | kullanıcı başına günlük takip sorgusu | 6 | bir gönderi teslime kadar birkaç kez sorulur |
| V3 | günde oluşan yeni gönderi | 400.000 | satıcı başına günlük gönderi sayısının toplamı |
| V4 | gönderi başına durum olayı | 7 | kabul, aktarma, dağıtıma çıkış, teslim ve ara durumlar |
| V5 | takip yanıtı gövdesi | 480 bayt | durum, bölge, güncellenme zamanı ve son üç rota adımı |
| V6 | bir durum olayının kaydı | 220 bayt | takip numarası, durum, rota adımı, zaman damgası |
| V7 | bir gönderi kaydı | 900 bayt | ağırlık, hacim, bölge, sözleşme ve tarife alanları |
| V8 | tepe çarpanı | 3 | tepe saatteki hızın gün ortalamasına oranı |
| V9 | takip sorgusunun önbellekten karşılanma oranı | 0,90 | aynı takip numarası kısa aralıkla yeniden sorulur |
| V10 | gün sonu işinin penceresi | 4 saat | satıcı raporu sabah ister |
| V11 | ücretlendirmenin taradığı gün | 30 | ücretlendirme aylık dönem üzerinden mutabık kalınır |
| V12 | kaydın saklanma süresi | 730 gün | sözleşme uyuşmazlıkları iki yıl geriye gidebilir |
| V13 | bir fatura satırında toplanan kalem | 100 | bir satıcının bir günü tek fatura satırıdır; dönem kayıtlarının bölümlenmesi bu orana bağlıdır |

Tablonun her satırı bir varsayımdır: doğruluğu tasarımın içinden gösterilemez. Bant genişliği
kavramı Bilgisayar Ağları müfredatında kuruldu ve burada yeniden anlatılmaz; hesapta yalnız
gövde baytları sayılır, başlık ve protokol yükü ayrı bir varsayım olurdu.

```js
// tasarim/varsayim.mjs — kursun tek varsayim tablosu; butun hesaplar bu tablodan cikar
export const V = {
  gunlukKullanici: 2_000_000,   // V1
  kullaniciBasinaSorgu: 6,      // V2
  gunlukGonderi: 400_000,       // V3
  gonderiBasinaOlay: 7,         // V4
  takipYanitiBayt: 480,         // V5
  olayKaydiBayt: 220,           // V6
  gonderiKaydiBayt: 900,        // V7
  tepeCarpani: 3,               // V8
  onbellekIsabeti: 0.9,         // V9
  topluPencereSaat: 4,          // V10
  topluKapsananGun: 30,         // V11
  saklamaGun: 730,              // V12
  faturaSatirinaKalem: 100,     // V13
};

export const GUN_SANIYE = 86_400;

export function hesapla(v) {
  const gunlukSorgu = v.gunlukKullanici * v.kullaniciBasinaSorgu;
  const gunlukOlay = v.gunlukGonderi * v.gonderiBasinaOlay;
  const okumaOrt = gunlukSorgu / GUN_SANIYE;
  const yazmaOrt = gunlukOlay / GUN_SANIYE;
  const okumaTepe = okumaOrt * v.tepeCarpani;
  const yazmaTepe = yazmaOrt * v.tepeCarpani;
  const depoOkuma = okumaTepe * (1 - v.onbellekIsabeti);
  const topluBayt = v.topluKapsananGun * v.gunlukGonderi * v.gonderiKaydiBayt;
  const gunlukBayt = v.gunlukGonderi * v.gonderiKaydiBayt + gunlukOlay * v.olayKaydiBayt;
  return {
    "gunluk takip sorgusu": gunlukSorgu,
    "gunluk durum olayi": gunlukOlay,
    "ortalama okuma istek/s": okumaOrt,
    "tepe okuma istek/s": okumaTepe,
    "tepe yazma istek/s": yazmaTepe,
    "tepe ucta istek/s": okumaTepe + yazmaTepe,
    "onbellek arkasi okuma/s": depoOkuma,
    "depoya ulasan istek/s": depoOkuma + yazmaTepe,
    "depoda yazma/okuma orani": yazmaTepe / depoOkuma,
    "okuma cikis Mbit/s": (okumaTepe * v.takipYanitiBayt * 8) / 1e6,
    "yazma giris Mbit/s": (yazmaTepe * v.olayKaydiBayt * 8) / 1e6,
    "toplu is okunan GB": topluBayt / 1e9,
    "toplu is tarama kayit/s": (v.topluKapsananGun * v.gunlukGonderi) / (v.topluPencereSaat * 3600),
    "toplu is Mbit/s": (topluBayt * 8) / (v.topluPencereSaat * 3600 * 1e6),
    "gunluk veri artisi MB": gunlukBayt / 1e6,
    "saklanan veri GB": (gunlukBayt * v.saklamaGun) / 1e9,
    "gunluk fatura satiri": v.gunlukGonderi / v.faturaSatirinaKalem,
    "donem satici-gun": (v.topluKapsananGun * v.gunlukGonderi) / v.faturaSatirinaKalem,
  };
}
```

Birimler ondalık sayılır: MB $10^6$ bayt, GB $10^9$ bayt, Mbit/s $10^6$ bit/s. Karışıklığı
önlemek için hesabın içinde yalnız bayt ve saniye kullanılır, dönüştürme son adımda yapılır.

#### Hesaplar

```js
// tasarim/olcek.mjs — varsayim tablosundan cikan butun hesaplar
import { V, hesapla } from "./varsayim.mjs";

const r = hesapla(V);
const bicim = (x) => (Number.isInteger(x) ? String(x) : x.toFixed(2));
for (const [ad, deger] of Object.entries(r)) console.log(`${ad.padEnd(26)}${bicim(deger).padStart(12)}`);

const gonderiBasinaMs = 1000 / r["toplu is tarama kayit/s"];
console.log(`\ntoplu iste gonderi basina sure = ${gonderiBasinaMs.toFixed(2)} ms (tek isci varsayimiyla)`);
console.log(`ucret cagrisi esigi 1 ms -> kalan pay = ${(gonderiBasinaMs - 1).toFixed(2)} ms`);
console.log(`toplu is bant genisligi / tepe okuma cikisi = ${(r["toplu is Mbit/s"] / r["okuma cikis Mbit/s"]).toFixed(2)}`);
```

```
gunluk takip sorgusu          12000000
gunluk durum olayi             2800000
ortalama okuma istek/s          138.89
tepe okuma istek/s              416.67
tepe yazma istek/s               97.22
tepe ucta istek/s               513.89
onbellek arkasi okuma/s          41.67
depoya ulasan istek/s           138.89
depoda yazma/okuma orani          2.33
okuma cikis Mbit/s                1.60
yazma giris Mbit/s                0.17
toplu is okunan GB               10.80
toplu is tarama kayit/s         833.33
toplu is Mbit/s                      6
gunluk veri artisi MB              976
saklanan veri GB                712.48
gunluk fatura satiri              4000
donem satici-gun                120000

toplu iste gonderi basina sure = 1.20 ms (tek isci varsayimiyla)
ucret cagrisi esigi 1 ms -> kalan pay = 0.20 ms
toplu is bant genisligi / tepe okuma cikisi = 3.75
```

Bu yirmi bir sayının hepsi **hesap** sınıfındadır: varsayım tablosundan aritmetikle çıkmıştır ve
hiçbiri dışarıdan alınmamıştır. Beşi tasarımı doğrudan etkiliyor.

**Tepe yük sanıldığı yerde değil.** Uçta tepe istek hızı saniyede 513,89. Bunun 416,67'si okuma,
97,22'si yazma. Okuma akışı hâkim görünüyor — ama önbelleğin arkasında tablo tersine dönüyor:
depoya ulaşan okuma 41,67, yazma 97,22 ve depodaki yazma/okuma oranı 2,33. Okuma ağırlıklı diye
tarif edilen sistem, deponun gördüğü yerde yazma ağırlıklıdır. Önbellek burada bir strateji
olarak değil, yalnız hesapta bir çarpan olarak geçiyor; önbellekleme Eşzamansız İşleme kursunda
kuruldu.

**Seyrek akış bant genişliğine hâkim.** Tepe okuma çıkışı 1,60 Mbit/s, gün sonu işinin okuma
hızı 6 Mbit/s: oran 3,75. Günde bir kez koşan iş, günün her saniyesi koşan okuma akışının üç
buçuk katı bant genişliği istiyor, çünkü 10,80 GB'ı dört saatlik bir pencereye sıkıştırıyor. Bir
tasarımın en büyük kaynak kalemi en sık çalışan akış olmak zorunda değildir.

**Bir eşik hesaptan doğrulanabilir.** Önceki dersin ücret çağrısı eşiği 1 milisaniyeydi ve
keyfi görünüyordu. Tarama hızı saniyede 833,33 kayıt olduğuna göre gönderi başına 1,20
milisaniye vardır; 1 milisaniyelik eşik 0,20 milisaniye pay bırakıyor. Eşiğin kaynağı böylece
bir beklenti değil bir hesap oluyor. Sayı tek işçi varsayımıyla geçerlidir: iş paralel işçilere
bölünürse pay büyür, ama bu bir tasarım kararıdır, aritmetiğin sonucu değil.

**Bir rastlantı hesabın tekrarlanmasını gerektiriyor.** Depoya ulaşan tepe istek hızı 138,89 ve
ortalama okuma hızı da 138,89. İki sayı eşit çünkü $12 \cdot 10^6 \cdot 0{,}3 + 2{,}8 \cdot
10^6 \cdot 3 = 12 \cdot 10^6$ olmasıdır; bu bir bağıntı değil, seçilen varsayımların ürettiği
bir çakışmadır. Varsayımlardan biri değiştiğinde eşitlik bozulur, bu yüzden hesap ezberlenmez,
yeniden koşturulur.

**Bir bölme iki ayrı sayı verir.** Günde 400.000 gönderi V13 oranıyla günde 4.000 fatura satırına
düşüyor; her satır bir satıcının bir gününe karşılık geldiğine göre bu sayı aynı zamanda satıcı
sayısıdır. Otuz günü tarayan ücretlendirme işi ise 120.000 satırla karşılaşır. İki sayı aynı
bölmeden çıkıyor ama aynı şeyi saymıyor: 4.000 satıcı, 120.000 satıcı-gün. Bu kursun ilerleyen
Temel Nitelikler konusu gün sonu işini bu ikinci sayı üzerinden bölümlere ayırır, bu yüzden
ikisinin birbirinin yerine kullanılmaması gerekir.

#### Duyarlılık

Bir varsayım tablosunun en önemli çıktısı sayılar değil, sayıların varsayımlara duyarlılığıdır.
Aşağıdaki betik on üç varsayımı tek tek oynatır ve yedi sonucun kaç katına çıktığını yazar.
Önbellek isabeti ikiye katlanamayacağı için oynatması isabetsizliğin iki katına çıkması olarak
tanımlanmıştır; toplu pencere ile fatura satırına toplanan kalem ise yarılanır, çünkü ikisinin de
sıkılaşması küçülmesidir.

```js
// tasarim/duyarlilik.mjs — her varsayim tek basina oynatildiginda hangi sonuc kac katina cikiyor
import { V, hesapla } from "./varsayim.mjs";

const OYNAMA = {
  gunlukKullanici: (v) => v * 2,
  kullaniciBasinaSorgu: (v) => v * 2,
  gunlukGonderi: (v) => v * 2,
  gonderiBasinaOlay: (v) => v * 2,
  takipYanitiBayt: (v) => v * 2,
  olayKaydiBayt: (v) => v * 2,
  gonderiKaydiBayt: (v) => v * 2,
  tepeCarpani: (v) => v * 2,
  onbellekIsabeti: () => 0.8,          // isabet 0.90 -> 0.80: isabetsizlik iki katina cikiyor
  topluPencereSaat: (v) => v / 2,      // pencere yarilaniyor: ayni is yarim surede bitmeli
  topluKapsananGun: (v) => v * 2,
  saklamaGun: (v) => v * 2,
  faturaSatirinaKalem: (v) => v / 2,   // satira yarisi kadar kalem toplanir
};

const SONUC = [["tepe ucta istek/s", "uc/s"], ["depoya ulasan istek/s", "depo/s"],
  ["okuma cikis Mbit/s", "cikis"], ["toplu is Mbit/s", "toplu"],
  ["gunluk veri artisi MB", "artis"], ["saklanan veri GB", "saklama"],
  ["donem satici-gun", "sat-gun"]];
const taban = hesapla(V);
const kat = {};

console.log(`${"oynatilan varsayim".padEnd(26)}${SONUC.map(([, k]) => k.padStart(8)).join("")}`);
for (const [ad, oynat] of Object.entries(OYNAMA)) {
  const yeni = hesapla({ ...V, [ad]: oynat(V[ad]) });
  kat[ad] = SONUC.filter(([s]) => Math.abs(yeni[s] - taban[s]) > 1e-9).map(([s]) => s);
  const satir = SONUC.map(([s]) => (kat[ad].includes(s) ? `x${(yeni[s] / taban[s]).toFixed(2)}` : "-").padStart(8));
  console.log(`${ad.padEnd(26)}${satir.join("")}`);
}

const enGenis = Object.entries(kat).sort((a, b) => b[1].length - a[1].length)[0];
console.log(`\nen cok sonuc oynatan varsayim = ${enGenis[0]} (${enGenis[1].length}/${SONUC.length})`);
for (const [s] of SONUC) {
  const kaynak = Object.keys(kat).filter((a) => kat[a].includes(s));
  console.log(`${s.padEnd(23)} bagli varsayim = ${kaynak.length}`);
}
```

```
oynatilan varsayim            uc/s  depo/s   cikis   toplu   artis saklama sat-gun
gunlukKullanici              x1.81   x1.30   x2.00       -       -       -       -
kullaniciBasinaSorgu         x1.81   x1.30   x2.00       -       -       -       -
gunlukGonderi                x1.19   x1.70       -   x2.00   x2.00   x2.00   x2.00
gonderiBasinaOlay            x1.19   x1.70       -       -   x1.63   x1.63       -
takipYanitiBayt                  -       -   x2.00       -       -       -       -
olayKaydiBayt                    -       -       -       -   x1.63   x1.63       -
gonderiKaydiBayt                 -       -       -   x2.00   x1.37   x1.37       -
tepeCarpani                  x2.00   x2.00   x2.00       -       -       -       -
onbellekIsabeti                  -   x1.30       -       -       -       -       -
topluPencereSaat                 -       -       -   x2.00       -       -       -
topluKapsananGun                 -       -       -   x2.00       -       -   x2.00
saklamaGun                       -       -       -       -       -   x2.00       -
faturaSatirinaKalem              -       -       -       -       -       -   x2.00

en cok sonuc oynatan varsayim = gunlukGonderi (6/7)
tepe ucta istek/s       bagli varsayim = 5
depoya ulasan istek/s   bagli varsayim = 6
okuma cikis Mbit/s      bagli varsayim = 4
toplu is Mbit/s         bagli varsayim = 4
gunluk veri artisi MB   bagli varsayim = 4
saklanan veri GB        bagli varsayim = 5
donem satici-gun        bagli varsayim = 3
```

Matris üç şey söylüyor. Birincisi, hiçbir varsayım bütün sonuçları oynatmıyor: en geniş etkili
varsayım günlük gönderi sayısı ve o da yedi sonucun altısını tutuyor. İkincisi, "iki katına
çıkarsa iki katına çıkar" beklentisi çoğu hücrede yanlış. Günlük etkin kullanıcı iki katına
çıktığında uçtaki tepe istek hızı 1,81 katına çıkıyor, çünkü yazma akışı bu varsayıma bağlı
değil; deponun gördüğü yük yalnız 1,30 katına çıkıyor, çünkü okumanın yüzde onu depoya
ulaşıyor. Aynı büyüme farklı katmanlarda farklı büyüklükte görünüyor.

Üçüncüsü, bir sonucun kaç varsayıma bağlı olduğu güvenilirliğinin ölçüsüdür. Depoya ulaşan
istek hızı altı varsayıma birden bağlı; içlerinden biri yanlışsa sayı yanlıştır. Saklanan veri
beş varsayıma bağlı. Bu yüzden bir tasarım tartışmasında "depoya saniyede yüz otuz dokuz istek
geliyor" cümlesi tek başına savunulamaz; savunma varsayım tablosuna işaret eder.

#### Özet

- Kabaca büyüklük hesabı doğru sayıyı değil doğru büyüklük sırasını arar; girdisi tek bir yerde
  toplanmış varsayım tablosudur.
- On üç varsayımdan çıkan hesaplar: uçta tepe 513,89 istek/s (okuma 416,67, yazma 97,22),
  günlük veri artışı 976 MB, 730 günde 712,48 GB, günde 4.000 fatura satırı ve dönemde 120.000
  satıcı-gün — son ikisi aynı bölmeden çıkar ama aynı şeyi saymaz.
- Önbelleğin arkasında yük dengesi tersine dönüyor: depoya ulaşan okuma 41,67, yazma 97,22 ve
  yazma/okuma oranı 2,33 — okuma ağırlıklı sistem depoda yazma ağırlıklıdır.
- Seyrek akış bant genişliğine hâkim olabilir: gün sonu işi 10,80 GB'ı dört saate sıkıştırdığı
  için 6 Mbit/s istiyor, tepe okuma çıkışının 3,75 katı.
- Bir eşik hesapla doğrulanabilir: tarama saniyede 833,33 kayıt olduğundan gönderi başına 1,20
  ms vardır ve önceki dersin 1 ms eşiği 0,20 ms pay bırakır.
- Duyarlılık matrisi "iki kat girdi iki kat sonuç" beklentisini yanlışlıyor: günlük kullanıcı
  iki katına çıktığında uçtaki tepe 1,81, depodaki yük 1,30 katına çıkıyor.

#### Sonraki Adım

Elde bir bileşen listesi, bir eşik kümesi ve yirmi bir hesaplanmış sayı var. Bunlar bir tasarım
değil, tasarımın malzemesidir; tasarım bir başkasına anlatılıp savunulduğunda vardır. Sonraki
ders bu anlatımı ele alır: bileşenlerin ve akışların diyagrama nasıl geçtiğini, hangi sayının
hangi kenarda durduğunu, ödünleşimin nasıl yazıldığını ve her sayının yanına sınıfının
yazılmasının anlatımı nasıl denetlenebilir kıldığını.

### Tasarımı Anlatmak

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/tasarimi-anlatmak

Bir tasarımın savunulabilir biçimde sunulması: kenar etiketleri hesaptan üretilen kutu-ok diyagramı, senaryo, eşik, değer, değerin sınıfı ve ödenen sayıdan oluşan beş alanlı karar kaydı, eksik alanların sayılması ve ölçüsüz cümlelerin anlatımdan ayıklanması.

Önceki dört ders bir tasarımın malzemesini üretti: beş bileşen ve yedi sözleşme, daraltılmış
bir kapsam, dört eşik ve on üç varsayımdan çıkan yirmi bir hesap. Bu malzeme tek başına bir
tasarım değildir. Tasarım, bir başkasına anlatıldığında ve o kişi karşı çıktığında savunulabildiği
ölçüde vardır.

Bu ders anlatımın biçimini ele alır. Biçim üç parçadan oluşur: akışları ve sınırları gösteren bir
diyagram, her kararı beş alanla kaydeden bir karar kaydı ve her sayının yanında duran sınıfı.
Mimari Biçemler kursunda kurulan biçem seçimi ve karar tablosu burada yeniden anlatılmaz;
oradaki üç parçalı savunma biçimi bu kursun sayı sınıflarıyla birlikte kullanılır.

#### Diyagram Neyi Göstermek Zorunda

Bir tasarım diyagramı süs değildir; okuyanın karara katılmasını ya da karşı çıkmasını sağlayan
bir belgedir. Bunun için dört şeyi taşımak zorundadır: **bileşenler**, akışın **yönü**, kenarın
hangi **akışa** ait olduğu ve kenarın üzerindeki **sayı**. Dördüncüsü genellikle eksiktir ve
eksik olduğunda diyagram yalnız bir kutu dizilişi olur.

Kenar sayılarının elle yazılması iki risk taşır: bir varsayım değiştiğinde diyagram güncellenmez
ve sayının hangi sınıftan olduğu kaybolur. İkisinin çözümü diyagramı hesaptan üretmektir.
Aşağıdaki ilk dosya önceki dersin varsayım tablosundan yalnız bu anlatımda geçen sayıları
yeniden hesaplar.

```js
// tasarim/hesap.mjs — anlatimda gecen sayilar; girdiler Kabaca Buyukluk Hesabi dersinin varsayim tablosundan
const GUN = 86_400;
export const V = { gunlukKullanici: 2_000_000, kullaniciBasinaSorgu: 6, gunlukGonderi: 400_000,
  gonderiBasinaOlay: 7, tepeCarpani: 3, onbellekIsabeti: 0.9, topluKapsananGun: 30,
  topluPencereSaat: 4, gonderiKaydiBayt: 900, olayKaydiBayt: 220, saklamaGun: 730 };

const gunlukBayt = V.gunlukGonderi * V.gonderiKaydiBayt + V.gunlukGonderi * V.gonderiBasinaOlay * V.olayKaydiBayt;
export const H = {
  okumaTepe: ((V.gunlukKullanici * V.kullaniciBasinaSorgu) / GUN) * V.tepeCarpani,
  yazmaTepe: ((V.gunlukGonderi * V.gonderiBasinaOlay) / GUN) * V.tepeCarpani,
  depoOkuma: ((V.gunlukKullanici * V.kullaniciBasinaSorgu) / GUN) * V.tepeCarpani * (1 - V.onbellekIsabeti),
  tarama: (V.topluKapsananGun * V.gunlukGonderi) / (V.topluPencereSaat * 3600),
  gonderiBasinaMs: (V.topluPencereSaat * 3600 * 1000) / (V.topluKapsananGun * V.gunlukGonderi),
  saklananGB: (gunlukBayt * V.saklamaGun) / 1e9,
};
```

Çizim bir kutu-ok düzeninden oluşur ve kenar etiketleri yukarıdaki değerlerden gelir. Sınıf
harfleri etiketin sonunda durur: `V` varsayım, `H` hesap, `O` ölçüm.

```js
// tasarim/diyagram.mjs — kenar etiketleri hesaptan uretilen kutu-ok cizimi (V varsayim, H hesap, O olcum)
import { H } from "./hesap.mjs";

const e = (x, birim, sinif) => `${x.toFixed(2)} ${birim} ${sinif}`;
const K = { UC: "+-------------+", DEPO: "+------------------+" };
function satir(...parca) {
  let s = "";
  for (const [kol, metin] of parca) s = s.padEnd(kol) + metin;
  return s;
}

const cizim = [
  satir([2, "dis aktor"], [25, "uc bileseni"], [48, "paylasilan bilesen"]),
  "",
  satir([2, "alici, satici"], [25, K.UC]),
  satir([3, "takip sorgusu   ----> "], [25, "|  takip-ucu  |"], [40, " ---+"], [48, e(H.depoOkuma, "istek/s", "H")]),
  satir([3, e(H.okumaTepe, "istek/s", "H")], [25, K.UC], [44, "|"]),
  satir([44, "|"]),
  satir([2, "tasiyici"], [25, K.UC], [44, "|"], [48, K.DEPO]),
  satir([3, "durum olayi     ----> "], [25, "| olay-alici  |"], [40, " ---+-> "], [48, "| gonderi-deposu   |"]),
  satir([3, e(H.yazmaTepe, "istek/s", "H")], [25, K.UC], [44, "|"], [48, `| ${e(H.saklananGB, "GB", "H").padEnd(17)}|`]),
  satir([44, "|"], [48, K.DEPO]),
  satir([2, "satici"], [25, K.UC], [44, "|"]),
  satir([3, "gun sonu istegi ----> "], [25, "| toplu-isci  |"], [40, " ---+"], [48, e(H.tarama, "kayit/s", "H")]),
  satir([3, "1 is/gun V"], [25, K.UC]),
];
for (const s of cizim) console.log(s);
console.log(`\ntoplu iste gonderi basina pay = ${H.gonderiBasinaMs.toFixed(2)} ms H`);
```

```
  dis aktor              uc bileseni            paylasilan bilesen

  alici, satici          +-------------+
   takip sorgusu   ----> |  takip-ucu  | ---+   41.67 istek/s H
   416.67 istek/s H      +-------------+    |
                                            |
  tasiyici               +-------------+    |   +------------------+
   durum olayi     ----> | olay-alici  | ---+-> | gonderi-deposu   |
   97.22 istek/s H       +-------------+    |   | 712.48 GB H      |
                                            |   +------------------+
  satici                 +-------------+    |
   gun sonu istegi ----> | toplu-isci  | ---+   833.33 kayit/s H
   1 is/gun V            +-------------+

toplu iste gonderi basina pay = 1.20 ms H
```

Diyagramın söylediği ilk şey, üç dış aktörün üç ayrı uca girmesi ve üçünün aynı bileşende
birleşmesidir. Bu, ilk dersin ölçtüğü olguyu görünür kılıyor: `gonderi-deposu` üç akışın da
dokunduğu bileşendir ve her kısıt önce orada birikir.

İkinci şey kenar sayılarının **asimetrisi**dir. Sol kenarda saniyede 416,67 istek var, aynı
akışın sağ kenarında 41,67. Aradaki fark bir bileşen kararının ta kendisidir ve diyagramda tek
bir sayı çifti olarak görünüyor. Kenarına sayı yazılmayan bir diyagram bu farkı gizler; okuyan
üç okun eşit yük taşıdığını sanır.

Üçüncüsü sınıf harflerinin dağılımıdır. Beş kenardan dördü `H`, biri `V`. Gün sonu isteğinin
günde bir kez gelmesi hesaplanmış bir sonuç değil, seçilmiş bir varsayımdır ve harfi bunu
söylüyor. Bir kenarda `O` olsaydı, o sayının bu makinede ölçüldüğü ve başka bir ortamda
değişeceği okunacaktı.

#### Karar Kaydı

Diyagram durumu gösterir, kararı göstermez. "Neden üç ayrı uç" ya da "neden tarife kuralı ayrı
bir bileşen değil" sorularının yanıtı ayrı bir kayıtta durur. Kayıt beş alandan oluşur ve
alanların üçü Mimari Biçemler kursundaki savunma biçiminden gelir.

- **Senaryo:** hangi nitelik, hangi uyaran altında sorulmaktadır.
- **Eşik:** o nitelikte kabul edilen değer ve kaynağı.
- **Değer:** kararın o ölçütte aldığı sayı.
- **Değerin sınıfı:** varsayım, hesap ya da ölçüm.
- **Ödenen:** karşılığında büyüyen sayı, yani ödünleşimin öteki yarısı.

Beşinci alan olmadan kayıt bir savunma değil bir ilandır. Dört karar aşağıda bu beş alanla
yazılmıştır; dördüncüsünde iki alan bilinçli olarak boş bırakılmıştır.

```js
// tasarim/anlatim.mjs — karar kaydinin bes alani ve anlatim cumlelerinin olcu denetimi
import { H } from "./hesap.mjs";

const KARAR = [
  { ad: "okuma ve yazma ayri bilesenlere konur",
    senaryo: "yazma dalgasi surerken alici takip sorgusu yapar",
    esik: "takip yaniti ortancasi en cok 200 ms",
    deger: `${H.yazmaTepe.toFixed(2)} istek/s yazma ayni surece dusmez`, sinif: "hesap",
    odenen: "bilesen 3 -> 4, yeni sinir 1" },
  { ad: "tarife kurali surec icinde cagrilir",
    senaryo: "gun sonu isi otuz gunluk gonderiyi tarar",
    esik: "gonderi basina en cok 1 ms",
    deger: `${H.gonderiBasinaMs.toFixed(2)} ms pay`, sinif: "hesap",
    odenen: "tarife ayri yayinlanamaz, birlikte yayinlanan parca 2" },
  { ad: "takip yaniti onbellekten karsilanir",
    senaryo: "ayni takip numarasi kisa aralikla yeniden sorulur",
    esik: "depoya ulasan okuma en cok 50 istek/s",
    deger: `${H.depoOkuma.toFixed(2)} istek/s`, sinif: "hesap (0.90 isabet varsayimina bagli)",
    odenen: "yanit bir onbellek yasi kadar bayat olabilir" },
  { ad: "gun sonu isi dort saatlik pencerede kosar",
    senaryo: "satici raporu sabah ister",
    esik: `tarama en az ${H.tarama.toFixed(2)} kayit/s`,
    deger: null, sinif: null,
    odenen: "pencere disinda tarama yapilamaz" },
];

const ALAN = ["senaryo", "esik", "deger", "sinif", "odenen"];
for (const k of KARAR) {
  const eksik = ALAN.filter((a) => k[a] === null);
  console.log(`${k.ad}\n  ${5 - eksik.length}/5 alan${eksik.length ? ` — eksik: ${eksik.join(", ")}` : ""}`);
}
const eksiksiz = KARAR.filter((k) => ALAN.every((a) => k[a] !== null));
console.log(`\nsavunulabilir karar = ${eksiksiz.length}/${KARAR.length}`);
console.log(`odunlesimi yazili karar = ${KARAR.filter((k) => k.odenen !== null).length}/${KARAR.length}`);

const CUMLE = [
  "okuma yolu yazma dalgasindan bagimsizdir",
  "depoya ulasan tepe istek hizi 138.89/s",
  "tasarim olceklenebilir",
  "gun sonu isi 10.80 GB tarar",
];
console.log("");
for (const c of CUMLE) console.log(`${/\d/.test(c) ? "olculu " : "olcusuz"}: ${c}`);
console.log(`olcusuz cumle = ${CUMLE.filter((c) => /\d/.test(c) === false).length}/${CUMLE.length}`);
```

```
okuma ve yazma ayri bilesenlere konur
  5/5 alan
tarife kurali surec icinde cagrilir
  5/5 alan
takip yaniti onbellekten karsilanir
  5/5 alan
gun sonu isi dort saatlik pencerede kosar
  3/5 alan — eksik: deger, sinif

savunulabilir karar = 3/4
odunlesimi yazili karar = 4/4

olcusuz: okuma yolu yazma dalgasindan bagimsizdir
olculu : depoya ulasan tepe istek hizi 138.89/s
olcusuz: tasarim olceklenebilir
olculu : gun sonu isi 10.80 GB tarar
olcusuz cumle = 2/4
```

Dört karardan üçü beş alanı da taşıyor, biri üçünü. Eksik olanın nesi eksik olduğu da önemli:
senaryosu, eşiği ve ödediği sayı yazılı, ama eşiğe karşı alınan değer ve o değerin sınıfı boş.
Bu, tasarım metinlerinde en sık görülen eksiktir; karar bir eşikle birlikte ilan edilir, eşiğin
karşılandığı gösterilmez. Dört saatlik pencere kararının savunulabilir olması için taramanın
saniyede 833,33 kayda yetiştiğinin gösterilmesi ve bu sayının sınıfının söylenmesi gerekir —
tek işçiyle hesap, işçi sayısı seçildikten sonra ölçüm.

Ödünleşim satırları da okunmaya değer. Dört kararın dördü de bir bedel yazıyor ve bedellerin
hiçbiri "karmaşıklık" gibi ölçüsüz bir sözcük değil: bileşen sayısının artması, birlikte
yayınlanan parça sayısı, yanıtın bayatlama olasılığı, pencere dışında tarama yapılamaması.
Ödünleşimi ölçüsüz sözcüklerle yazan bir karar kaydı, ödünleşimi yazmamış sayılır.

#### Ölçüsüz Cümle

Son denetim anlatımın kendisine bakar. Dört cümlenin ikisi sayı içermiyor: "okuma yolu yazma
dalgasından bağımsızdır" ve "tasarım ölçeklenebilir". İkisi de tasarım metinlerinde sık geçer ve
ikisi de bir şey söylemez. Birincisi düzeltilebilir: bağımsızlığın ölçüsü, yazma akışındaki
büyümenin okuma yanıtına ne kadar geçtiğidir ve bu bir sayıyla yazılabilir. İkincisi
düzeltilemez, çünkü hangi niteliğin hangi yükte ne kadar bozulduğunu söylemiyor; yerine bir
nitelik, bir yük ve bir eşik yazılmadıkça cümle atılır.

Sayı taşıyan iki cümle ise sınıfını da taşımak zorundadır. "Depoya ulaşan tepe istek hızı
138,89" cümlesi altı varsayıma bağlı bir hesaptır ve öyle sunulmalıdır; "gün sonu işi 10,80 GB
tarar" cümlesi de öyle. Bir tasarım anlatımının denetlenebilir olması, içindeki her sayının
kaynağının izlenebilmesi anlamına gelir.

#### Özet

- Bir tasarım anlatımı üç parçadan oluşur: akış ve sınır gösteren diyagram, beş alanlı karar
  kaydı ve her sayının yanındaki sınıfı.
- Diyagram bileşen, yön, akış ve kenar sayısını taşımak zorundadır; kenar etiketleri hesaptan
  üretildiğinde varsayım değiştikçe güncel kalır ve sınıfı kaybolmaz.
- Örnek diyagramda kenar asimetrisi bir bileşen kararını görünür kılıyor: aynı akış sol kenarda
  416,67 istek/s, sağ kenarda 41,67 istek/s taşıyor.
- Karar kaydının beş alanı senaryo, eşik, değer, değerin sınıfı ve ödenen sayıdır; örnekte dört
  karardan üçü beş alanı taşıdı, biri değer ve sınıf alanları boş kaldığı için savunulamaz sayıldı.
- Ödünleşim ölçüsüz bir sözcükle yazılamaz; dört kararın bedeli bileşen sayısı, birlikte
  yayınlanan parça, bayatlama olasılığı ve pencere kısıtı olarak yazıldı.
- Anlatımdaki dört cümleden ikisi sayı taşımıyordu; sayı taşımayan cümle ya bir ölçüyle
  yeniden yazılır ya da atılır.

#### Sonraki Adım

Bu konu bir tasarımın nasıl kurulduğunu ve nasıl anlatıldığını gösterdi: bileşenlerin ayrılması,
gereksinimin iki yarısı, varsayımdan hesaba geçiş ve her kararın bir gerekçeye bağlanması.
Gerekçenin dayandığı şey ise hâlâ adlandırılmadı. Bu dersin eşiklerinde geçen "takip yanıtı
ortancası", "depoya ulaşan istek hızı", "pencere içinde bitme" ölçütleri sanki bilinen
kavramlarmış gibi kullanıldı; oysa "hızlı", "ölçeklenir" ve "ayakta kalır" cümlelerinin
karşılığı olan nitelikler tek tek tanımlanmadı. Sonraki konu bu ölçütleri sırayla tanımlar ve
ilk ders en sık birbirine karıştırılan çiftle başlar: gecikme ile verim aynı sistemin iki ayrı
sorusunun yanıtıdır ve birinin iyileşmesi ötekinin iyileşmesi anlamına gelmez.

## Temel Nitelikler

Bir sistemin yük ve arıza altındaki davranışını tanımlayan ölçütler: gecikme ile verimin birbirinden bağımsızlığı, başarım ile ölçeklenebilirliğin farkı, yatay ve dikey ölçeklemenin sınırları, hizmet erişilebilirliğinin kesinti bütçesi olarak sayıya dökülmesi, CAP teoreminin doğru okunması, bölünme dışındaki gecikme ödünleşimi, güçlü ile sonunda tutarlılık arasındaki modeller ve etkin–etkin ile etkin–pasif devralma kalıpları.

### Gecikme ve Verim

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/gecikme-ve-verim

İki ölçütün birbirinden bağımsız iki eksen olduğunun ölçülmesi: eşzamanlılık artarken verimin doyması ve gecikmenin kötüleşmesi, eşzamanlılık ile verim ve gecikme arasındaki bağıntının ölçümle doğrulanması, doyuma yaklaşmanın gecikme maliyetinin bir kuyruk modeliyle gösterilmesi ve her sayının varsayım, hesap ya da ölçüm olarak sınıflandırılması.

Önceki konu bir tasarımın nasıl kurulduğunu ve nasıl anlatıldığını ele aldı: bileşenlerin
ayrılması, gereksinimin işlevsel ve işlevsel olmayan yarılarına bölünmesi, kaynak ihtiyacının
kabaca hesaplanması ve her kararın bir gerekçeyle sunulması. Gerekçenin dayandığı şey ise
adlandırılmadı. "Bu tasarım hızlıdır", "bu tasarım ölçeklenir", "bu tasarım ayakta kalır"
cümlelerinin hiçbiri bir ölçüt içermez; üçü de tartışmayı bitirmek yerine başlatır, çünkü
karşı taraf aynı cümleyi tersine çevirdiğinde elde ölçülecek bir şey kalmaz.

Bu konu o ölçütleri tanımlar. İlk ders en sık birbirine karıştırılan çiftle başlar: bir önceki
konuda eşiklerde geçen "takip yanıtı ortancası" ile "depoya ulaşan istek hızı" iki ayrı ölçütün
adıdır ve ikisi arasında hiçbir zorunlu bağ yoktur. Dersin işi bu bağımsızlığı bir düzenekte
ölçmek, sonra bağımsızlığın nerede bittiğini ve neden bittiğini göstermektir.

#### Üç Akış ve Sayının Sınıfı

Kurs boyunca aynı sistem ele alınır: bir **gönderi takip ve ücretlendirme servisi**. Üç akışı
vardır. **Okuma** akışı takip sorgusudur: kullanıcı bir takip numarası verir, gönderinin son
durumunu alır. **Yazma** akışı taşıyıcıdan gelen durum olayıdır: küçük kayıtlar sürekli akar.
**Toplu** akış satıcının gün sonu ücretlendirmesidir: günde bir kez, çok büyük bir iş.

Bu konu yeni varsayım seçmez. Kabaca Büyüklük Hesabı dersinin on iki satırlık varsayım tablosu
ve ondan çıkan hesaplar burada girdi olarak kullanılır. Üç akışın ihtiyaç duyulan sayıları
şunlardır: uçta tepe istek hızı **513,89 istek/s** — 416,67'si okuma, 97,22'si yazma; önbelleğin
arkasında depoya ulaşan tepe hız **138,89 istek/s**; gün sonu işi otuz günü kapsayan **12
milyon kaydı dört saatlik pencerede** tarar, yani **833,33 kayıt/s** ve kayıt başına 1,20 ms.
Hepsi hesap sınıfındadır ve hiçbiri dışarıdan alınmamıştır.

Sistem Tasarımı Nedir dersinde kurulan sınıflandırma bu konunun bütün sayılarında da uygulanır:
bir sayı ya seçilmiş bir **varsayım**dır, ya varsayımlardan çıkan bir **hesap**tır, ya da bir
düzenekten alınmış bir **ölçüm**dür. Bu dersin katkısı üçüncü sınıftadır — yukarıdaki hesaplar
gereken kapasiteyi söylüyor, ama bir sürecin ne taşıdığını söylemiyor. O sayı ölçülür.

#### İki Ölçüt İki Ayrı Eksendir

**Gecikme** (latency) bir işin başlangıcından bitişine kadar geçen süredir; birimi zamandır.
Ağ Modelleri ve Protokoller kursunda dört bileşene ayrılmıştı: iletim, yayılım, kuyruk ve
işleme. **Verim** (throughput) birim zamanda tamamlanan iş sayısıdır; birimi iş bölü zamandır.
İki ölçütün birimleri farklıdır, dolayısıyla biri ötekinin yerine kullanılamaz.

Üç akış bu iki ekseni ayrı köşelere yerleştirir. Takip sorgusu düşük gecikme ister; kullanıcı
yanıtı bekler ve tek bir yanıtın süresi doğrudan ona görünür. Gün sonu
ücretlendirmesi yüksek verim ister; 12 milyon kaydın dört saatte taranması gerekir ve tek tek
hiçbir kaydın ne zaman bittiği önemli değildir. Aynı sistemin bir akışında milisaniye,
ötekinde saat ölçek birimidir.

Ayrımın kritik sonucu şudur: bir akışın verimini artırmak gecikmesini kötüleştirebilir. Gün sonu
işi kayıtları gruplayarak verimini katlayabilir, ama gruplanan her kayıt grubun tamamlanmasını
bekler. Tersi de olur: gecikmeyi kısaltmak verimi düşürebilir, çünkü her işi hemen başlatmak
gruplamanın kazancından vazgeçmek demektir.

İki ölçütün bir asimetrisi daha vardır. Verim tek bir sayıdır: birim zamanda tamamlanan iş
sayısı sayılır ve biter. Gecikme tek bir sayı değildir, bir **dağılımdır**; aynı yükte bazı
istekler hızlı, bazıları yavaş yanıtlanır. Bu yüzden gecikme **yüzdeliklerle** bildirilir:
ortanca isteklerin yarısının altında kaldığı süre, p99 yüzde birinin aştığı süredir. Ortalama
gecikme bildirmek en az bilgi taşıyan seçenektir, çünkü tek bir çok yavaş istek ortalamayı
kaydırır ve dağılımın biçimini saklar.

#### Eşzamanlılık Arttıkça Ne Oluyor

Aşağıdaki düzenek takip ucunu yerel bir sunucu olarak kurar. Her istek iki şey harcar: kayıt
aramasının yerine geçen bir bekleme ve bir işlemci payı. İkisi de düzeneğin parametresidir,
ölçüm değildir.

```js
// takip/sunucu.mjs — takip sorgusu ucu: her istek bir bekleme ve bir islemci payi harcar
import { createServer } from "node:http";

const BEKLEME = 3;                 // kayit aramasinin yerine gecen bekleme (ms), duzenegin parametresi
const ISLEMCI = 0.20;              // istek basina islemci payi (ms), duzenegin parametresi

function isle(ms) {               // ms kadar islemci mesgul eder
  const bit = performance.now() + ms;
  let t = 0;
  while (performance.now() < bit) t += 1;
  return t;
}

const port = Number(process.argv[2]);
if (Number.isInteger(port) === false) console.log("kullanim: node takip/sunucu.mjs <baglanti-noktasi>");
else createServer(async (istek, yanit) => {
  const no = new URL(istek.url, "http://yerel").searchParams.get("no") ?? "-";
  await new Promise((c) => setTimeout(c, BEKLEME));
  isle(ISLEMCI);
  const govde = JSON.stringify({ no, durum: "aktarma merkezinde", bolge: "35", adim: 4 });
  yanit.writeHead(200, { "content-type": "application/json" });
  yanit.end(govde);
}).listen(port);
```

İstemci yedi **eşzamanlılık** (concurrency) düzeyinde çalışır. Her düzeyde belirtilen sayıda
istek hep havada tutulur; iki saniye boyunca gönderilen istek sayısı verimi, tek tek ölçülen
süreler gecikme yüzdeliklerini verir.

```js
// takip/yukle.mjs — artan escamanlilikla istek gonderir; her duzeyde verim ve gecikme yazar
import { Agent, request } from "node:http";

const port = Number(process.argv[2]);
const DUZEY = [1, 2, 4, 8, 16, 32, 64];
const SURE = 2000;                 // her duzeyin olcum suresi (ms)

const agent = new Agent({ keepAlive: true, maxSockets: 256 });

function birIstek(no) {
  return new Promise((coz, sap) => {
    const bas = performance.now();
    const r = request({ port, path: `/takip?no=${no}`, agent }, (y) => {
      y.resume();
      y.on("end", () => coz(performance.now() - bas));
    });
    r.on("error", sap);
    r.end();
  });
}

function yuzdelik(dizi, p) {
  const s = [...dizi].sort((a, b) => a - b);
  return s[Math.min(s.length - 1, Math.floor((p / 100) * s.length))];
}

async function duzey(n) {
  const gecikme = [];
  const bit = performance.now() + SURE;
  const bas = performance.now();
  await Promise.all(Array.from({ length: n }, async (_, k) => {
    let i = 0;
    while (performance.now() < bit) gecikme.push(await birIstek(`G${k}-${i++}`));
  }));
  const gecen = (performance.now() - bas) / 1000;
  return { n, istek: gecikme.length, verim: gecikme.length / gecen,
    orta: yuzdelik(gecikme, 50), p99: yuzdelik(gecikme, 99) };
}

if (Number.isInteger(port) === false) console.log("kullanim: node takip/yukle.mjs <baglanti-noktasi>");
else {
  await birIstek("isinma");
  console.log("escaman  istek   verim(istek/s)  ortanca(ms)  p99(ms)  verim*ortanca");
  for (const n of DUZEY) {
    const s = await duzey(n);
    const little = (s.verim * s.orta) / 1000;
    console.log(`${String(s.n).padStart(6)}  ${String(s.istek).padStart(6)}  ` +
      `${s.verim.toFixed(0).padStart(13)}  ${s.orta.toFixed(2).padStart(10)}  ` +
      `${s.p99.toFixed(2).padStart(7)}  ${little.toFixed(2).padStart(22)}`);
  }
  agent.destroy();
}
```

Sürücü betik sunucuyu başlatır, ölçümü koşturur ve sunucuyu durdurur. Bağlantı noktası numarası
ortama bağlıdır; makinede kullanımdaysa değiştirilmelidir.

{/* run: skip */}
```bash
# olc.sh — sunucu baslatilir, yedi escamanlilik duzeyi olculur, sunucu durdurulur
node takip/sunucu.mjs 8811 & SUNUCU=$!
sleep 1
node takip/yukle.mjs 8811
kill $SUNUCU
```

Çıktı makineden makineye değişir; örnek bir koşum:

```
escaman  istek   verim(istek/s)  ortanca(ms)  p99(ms)  verim*ortanca
     1     463            231        4.33     4.78                    1.00
     2     936            468        4.46     5.05                    2.09
     4    1764            880        4.80     5.38                    4.23
     8    3038           1515        5.67     6.14                    8.59
    16    4849           2417        6.65     7.57                   16.06
    32    8089           4031        8.21     9.56                   33.10
    64    8593           4268       15.15    16.46                   64.64
```

Bu sayılar ölçümdür ve bu makinede alınmıştır. Mutlak değerleri başka bir makinede
tekrarlanmaz; tekrarlanan şey tablonun **biçimidir**.

#### İki Bölge

Tablo iki ayrı bölgeye ayrılır ve dersin savı bu ayrımdadır.

Birinci bölgede, eşzamanlılık 1'den 4'e çıkarken verim 231'den 880'e, yani 3,81 katına çıktı;
ortanca gecikme 4,33 ms'den 4,80 ms'ye, yani 1,11 katına çıktı. Verim neredeyse eşzamanlılıkla
birlikte büyüdü, gecikme yerinde saydı. **Bu bölgede iki ölçüt bağımsızdır:** verim artıyor,
gecikme hakkında hiçbir şey söylemiyor.

İkinci bölgede tablo tersine döner. Eşzamanlılık 32'den 64'e çıkarken verim 4031'den 4268'e,
yani yalnızca 1,06 katına çıktı; ortanca gecikme 8,21 ms'den 15,15 ms'ye, yani 1,85 katına
çıktı. Eşzamanlılığı iki katına çıkarmanın karşılığı %6 verim ve iki kat gecikmedir. **Bu
bölgede bağımsızlık biter:** verim bir üst sınıra dayanmıştır ve eklenen her istek yalnızca
beklemeye eklenir.

Üst sınırın nereden geldiği düzenekte yazılıdır. Her istek 0,20 ms işlemci payı harcıyor ve
sunucu tek bir iş parçacığında çalışıyor; işlemci payı bölünemeyen kaynaktır. Beklemeler
üst üste binebilir, işlemci payı binemez. Sunucu Tarafı Temelleri kursunda kurulan ayrım
budur: bekleyen girdi-çıktı ucuzdur, işlemciyi meşgul eden hesap sırayı kilitler.

#### Bağıntı

Son sütun iki ölçütü birbirine bağlar. Her satırda verim ile ortanca gecikmenin çarpımı,
gecikme saniyeye çevrildiğinde eşzamanlılık düzeyine eşit çıkıyor: 1,00, 2,09, 4,23, 8,59,
16,06, 33,10, 64,64. Bu bir kaza değil, kuyruk kuramının temel bağıntısıdır. Önbellekleme,
Kuyruklar ve Eşzamansız İşleme kursunda $L = \lambda W$ biçiminde kurulmuştu; buradaki
karşılığı şudur:

$$
N = X \times R
$$

$N$ havadaki iş sayısı, $X$ verim, $R$ gecikmedir. Bağıntının tasarım sonucu doğrudandır:
**üç büyüklükten ikisi seçilirse üçüncüsü seçilemez.** Havadaki iş sayısı sabit tutulup verim
artırılamıyorsa, gecikme büyümek zorundadır — başka çıkışı yoktur. İkinci bölgedeki davranış
bu zorunluluğun görünür hâlidir.

Aynı bağıntı ölçüm okumanın kuralını da verir. Yalnız verimi bildiren bir rapor, hangi
eşzamanlılıkta alındığını söylemedikçe gecikme hakkında hiçbir şey söylemez; yalnız gecikmeyi
bildiren bir rapor da yükü söylemedikçe okunamaz. Bir ölçütün tek başına bildirilmesi eksik
bildirimdir.

#### Doyuma Yaklaşmanın Bedeli

İkinci bölgenin girişinde ne olduğunu bir model gösterir. Tek sunuculu bir kuyrukta, servis
hızı $\mu$ ve varış hızı $\lambda$ iken **doluluk** (utilization) $\rho = \lambda / \mu$
olarak tanımlanır ve sistemde geçirilen ortalama süre $1 / (\mu - \lambda)$ olur. Aşağıdaki
hesap bu modeli ölçülen üst sınırla besler. **Bu bir modeldir, ölçüm değildir**; varışların
ve servis sürelerinin dağılımı hakkında varsayım içerir ve gerçek bir sunucunun gecikmesini
öngörmez. Gösterdiği şey oranların yönüdür.

```js
// hesap/kuyruk.mjs — tek sunuculu kuyruk MODELI: doyuma yaklasan verimin gecikmeye maliyeti
const MU = 4268;                   // olculen ust sinir: bu duzenekte bir surecin doyum verimi (istek/s)

console.log(`servis hizi mu = ${MU} istek/s (olculen ust sinir)`);
console.log("doluluk   varis hizi(istek/s)   modeldeki ortalama sure(ms)   %30 duruma gore kat");
const taban = 1000 / (MU - 0.30 * MU);
for (const rho of [0.30, 0.50, 0.70, 0.80, 0.90, 0.95, 0.99]) {
  const T = 1000 / (MU - rho * MU);
  console.log(`${(rho * 100).toFixed(0).padStart(6)}%  ${(rho * MU).toFixed(0).padStart(19)}  ` +
    `${T.toFixed(2).padStart(27)}  ${(T / taban).toFixed(1).padStart(18)}`);
}

const tepe = [416.67, 833.33];   // Kabaca Buyukluk Hesabi: tepe okuma hizi ve sorgu varsayimi ikiye katlanirsa
for (const t of tepe) {
  console.log(`tepe ${t} istek/s -> doluluk ${((t / MU) * 100).toFixed(1)}%, ` +
    `ust sinir tepenin ${(MU / t).toFixed(1)} kati, ` +
    `modeldeki ortalama sure ${(1000 / (MU - t)).toFixed(2)} ms`);
}
```

```
servis hizi mu = 4268 istek/s (olculen ust sinir)
doluluk   varis hizi(istek/s)   modeldeki ortalama sure(ms)   %30 duruma gore kat
    30%                 1280                         0.33                 1.0
    50%                 2134                         0.47                 1.4
    70%                 2988                         0.78                 2.3
    80%                 3414                         1.17                 3.5
    90%                 3841                         2.34                 7.0
    95%                 4055                         4.69                14.0
    99%                 4225                        23.43                70.0
tepe 416.67 istek/s -> doluluk 9.8%, ust sinir tepenin 10.2 kati, modeldeki ortalama sure 0.26 ms
tepe 833.33 istek/s -> doluluk 19.5%, ust sinir tepenin 5.1 kati, modeldeki ortalama sure 0.29 ms
```

Model tek bir şeyi söylüyor: dolulukla birlikte verim doğrusal büyürken süre doğrusal
büyümüyor. %30'dan %99'a çıkmak varış hızını 3,3 katına, süreyi 70 katına çıkarıyor. Verimin
son parçası, gecikmenin sınırsız büyümesiyle satın alınır. Doluluğun yüksek tutulması bir
verimlilik başarısı gibi görünür ve bir gecikme kararıdır.

Son iki satır hesabı ölçümle birleştirir. Tepe okuma hızı 416,67 istek/s, düzenekte ölçülen
üst sınır 4268 istek/s; oran 10,2'dir ve doluluk %9,8'de kalır. Kullanıcı başına sorgu iki
katına çıktığında oran 5,1 olur. Buradan çıkan sonuç ölçünün kendisi değil, **yöntemdir**:
tepe hız varsayımlardan hesaplanır, üst sınır düzenekten ölçülür, ikisinin oranı payı verir.
Gerçek takip ucu bu düzenekten fazlasını yapacağı için üst sınırı daha düşük olur; oran ise
aynı biçimde okunur. Oran 1'in altına düştüğünde tasarım artık çalışmıyordur; 2 ile 3
arasındayken tek bir arıza bütün payı silecek kadar dar demektir.

#### Özet

- Gecikme bir işin süresi, verim birim zamanda tamamlanan iş sayısıdır; birimleri farklıdır
  ve biri ötekinin yerine kullanılamaz.
- Ölçümde eşzamanlılık 1'den 4'e çıkarken verim 3,81 katına çıktı, ortanca gecikme 1,11
  katında kaldı: bu bölgede iki ölçüt bağımsızdır.
- Eşzamanlılık 32'den 64'e çıkarken verim 1,06 katına çıktı, gecikme 1,85 katına çıktı: verim
  üst sınıra dayandığında eklenen her istek yalnızca beklemeye eklenir.
- Ölçülen her satırda $N = X \times R$ tuttu; üç büyüklükten ikisi seçilirse üçüncüsü seçilemez,
  bu yüzden tek başına bildirilen verim ya da gecikme okunamaz.
- Kuyruk modeli dolulukla sürenin doğrusal büyümediğini gösterdi: %30'dan %99'a varış hızı
  3,3 katına, süre 70 katına çıkıyor; doluluğu yüksek tutmak bir gecikme kararıdır.
- Hesaplanan tepe okuma hızı 416,67 istek/s, ölçülen üst sınır 4268 istek/s; oran 10,2'dir ve
  kullanıcı başına sorgu iki katına çıktığında 5,1'e iner.

#### Sonraki Adım

Bu ders tek bir süreci sabit tuttu ve yükü değiştirdi. Ortaya çıkan iki bölge, "bu sistem
hızlıdır" cümlesinin neden yetersiz olduğunu gösterdi: sistemin hızı ölçüldüğü yüke bağlıdır
ve düşük yükte alınmış bir sayı yüksek yükteki davranış hakkında hiçbir şey söylemez. Buradan
iki ayrı soru çıkar. Birincisi, belirli bir yükte sistem ne kadar iyidir. İkincisi, yük
büyüdüğünde bu iyilik ne kadar dayanır. İki soru sık sık tek bir sözcükle karşılanır ve
karşılanmamalıdır: birinin adı başarım, ötekinin adı ölçeklenebilirliktir. Sonraki ders iki
kavramı ayırır: gün sonu işinin iki gerçekleştirimini dört ayrı yükte ölçer, ikisinin de
bugünün eşiğini karşıladığını gösterir ve aradaki farkın ancak yük büyütüldüğünde
sayılabildiğini ortaya koyar.

### Başarım ve Ölçeklenebilirlik

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/basarim-ve-olceklenebilirlik

İki kavramın yük altında ayrışması: başarımın belirli bir yükteki ölçüt değeri, ölçeklenebilirliğin ölçütün yükle değişimi olduğunun gösterilmesi, gün sonu işinin iki gerçekleştiriminin dört yükte ölçülmesi, eşiği karşılayan en büyük yükün kapasite olarak hesaplanması ve sabit çarpan kazancının mertebe kazancından ayrılması.

Önceki ders tek bir süreci sabit tutup yükü değiştirdi ve ortaya iki bölge çıktı: verimin
eşzamanlılıkla büyüdüğü bölge ile verimin bir üst sınıra dayanıp gecikmenin büyüdüğü bölge. Aynı
sistemin iki ayrı yükte iki ayrı davranış göstermesi, tek bir ölçümün sistem hakkında ne kadar
az şey söylediğini de gösterdi.

Buradan iki soru çıkar. Belirli bir yükte sistem ne kadar iyidir ve yük büyüdüğünde bu iyilik
ne kadar dayanır. Bu ders iki soruyu ayrı adlarla karşılar ve farkı gün sonu ücretlendirme işi
üzerinde sayar. Ayrımı görünür kılmanın tek yolu **birden fazla yükte ölçmektir**; tek bir
yükteki ölçüm, hangi soruya yanıt verdiğini bile söylemez.

#### Bir Nokta ile Bir Eğri

**Başarım** (performance) belirli bir yükte ölçülen ölçüt değeridir: "bu iş bu makinede bu kadar
kayıtla 460 milisaniye sürüyor" bir başarım ifadesidir. Tek bir noktadır ve o noktanın dışında
hiçbir şey söylemez.

**Ölçeklenebilirlik** (scalability) ölçütün yükle birlikte nasıl değiştiğidir: yük iki katına
çıktığında sürenin kaç katına çıktığı. Bir nokta değil, bir eğridir. Bir sistemin
ölçeklenebilirliği hakkında tek bir ölçümden hiçbir şey çıkarılamaz, çünkü bir noktadan eğri
geçirilemez.

İki kavramın karıştırılması pratik bir yanlışa yol açar: başarımı iyileştiren bir değişiklik
ölçeklenebilirliği iyileştirmiş sayılır. Aşağıdaki ölçüm bunun neden yanlış olduğunu gösteriyor.
Kalite Nitelikleri dersinin nitelik aileleri listesinde başarım, başarım verimliliği ailesine
girer; ölçeklenebilirlik listede yoktur ve liste kapalı olmadığı için bu alanda ayrı bir aile
olarak eklenir. İkisinin nitelik senaryolarında da ölçüm parçası farklıdır: biri sabit bir yükte
eşik, öteki yükün büyümesi karşısında davranış belirtir.

#### Aynı İşin İki Gerçekleştirimi

Gün sonu ücretlendirmesi kalemleri fatura satırlarında toplar. Bir fatura satırı bir satıcının
bir gününe karşılık gelir; bundan sonra bu gruplama birimine **bölüm** denecek ve satıcı
numarası ile gün birlikte **bölüm anahtarını** verecektir. İki gerçekleştirim aynı sonucu verir,
farklı yollardan. **A**, her bölüm için bütün kalemleri tarar. **B**, kalemleri bir kez geçer ve
bölüm anahtarını dizin olarak kullanır.

Kalem sayısı ile bölüm sayısı bağımsız değildir. Oranı veren varsayım Kabaca Büyüklük Hesabı
dersinin tablosunda V13 olarak duruyor: **bir fatura satırına 100 kalem toplanır**. Buradan V3
ile tutan bir zincir çıkar; günde 400 000 gönderi bu oranla günde 4000 fatura satırı, yani 4000
satıcı demektir. Otuz günü tarayan ücretlendirme işi bu yüzden 120 000 bölüm görür: 4000 satıcı
çarpı 30 gün. Varsayımın duyarlılığı hesapta gösterilecek.

```js
// toplu/gruplama.mjs — gun sonu ucretlendirmesinin iki gerceklestirimi ayni dort yukte olculur
const TARIFE = { kademe: [[1, 3000], [5, 4800], [20, 9600]], bolge: { "34": 100, "06": 115, "35": 125 }, asgari: 2500 };
const BOLGE = ["34", "06", "35"];
const BOLUM_BASINA = 100;          // V13: bir fatura satirina toplanan kalem sayisi

function kalemler(n, bolum) {
  const d = new Array(n);
  for (let i = 0; i < n; i += 1) {
    d[i] = { bolum: i % bolum, agirlik: (i % 20) + 1, bolge: BOLGE[i % 3], oran: (i % 5) / 20 };
  }
  return d;
}

function net(k) {
  const kademe = TARIFE.kademe.find(([s]) => k.agirlik <= s) ?? [0, 9600];
  const taban = Math.max(TARIFE.asgari, Math.round((kademe[1] * TARIFE.bolge[k.bolge]) / 100));
  return taban - Math.round(taban * Math.min(k.oran, 0.4));
}

function faturaA(veri, bolum) {    // her bolum icin butun kalemler taranir
  const cikti = new Array(bolum).fill(0);
  for (let b = 0; b < bolum; b += 1) {
    for (const k of veri) if (k.bolum === b) cikti[b] += net(k);
  }
  return cikti;
}

function faturaB(veri, bolum) {    // tek gecis, bolum anahtariyla toplanir
  const cikti = new Array(bolum).fill(0);
  for (const k of veri) cikti[k.bolum] += net(k);
  return cikti;
}

function olc(f, veri, bolum) {
  const bas = performance.now();
  const r = f(veri, bolum);
  return { ms: performance.now() - bas, imza: r[0] + r[bolum - 1] };
}

// A kat: yuk ikiye katlanirken surenin kac katina ciktigi. A mertebe: log2(kat) — 1 dogrusal,
// 2 kare buyume. Ham ms makineye baglidir, mertebe ise gerceklestirimin ozelligidir.
console.log("kalem     bolum      A(ms)     B(ms)     A/B  A us/kalem  B us/kalem   A kat  mertebe  ayni");
let oncekiA = 0;
for (const n of [20_000, 40_000, 80_000, 160_000]) {
  const bolum = n / BOLUM_BASINA;
  const veri = kalemler(n, bolum);
  const a = olc(faturaA, veri, bolum);
  const b = olc(faturaB, veri, bolum);
  const kat = oncekiA === 0 ? null : a.ms / oncekiA;
  oncekiA = a.ms;
  console.log(`${String(n).padStart(7)}${String(bolum).padStart(10)}` +
    `${a.ms.toFixed(1).padStart(11)}${b.ms.toFixed(1).padStart(10)}${(a.ms / b.ms).toFixed(0).padStart(8)}` +
    `${((a.ms * 1000) / n).toFixed(2).padStart(12)}${((b.ms * 1000) / n).toFixed(2).padStart(12)}` +
    `${(kat === null ? "-" : kat.toFixed(2)).padStart(8)}${(kat === null ? "-" : Math.log2(kat).toFixed(2)).padStart(9)}` +
    `${String(a.imza === b.imza).padStart(6)}`);
}
```

```
kalem     bolum      A(ms)     B(ms)     A/B  A us/kalem  B us/kalem   A kat  mertebe  ayni
  20000       200       13.3       1.4       9        0.67        0.07       -        -  true
  40000       400       32.2       0.7      45        0.81        0.02    2.42     1.28  true
  80000       800      121.9       1.8      66        1.52        0.02    3.78     1.92  true
 160000      1600      471.7       2.9     160        2.95        0.02    3.87     1.95  true
```

Milisaniye sütunları ölçümdür ve bu makinede alınmıştır; başka bir makinede başka değerler
çıkar. Son iki sütun bu yüzden eklenmiştir: `A kat` ile `mertebe`, ham sürelerden **türetilmiş**
büyüklüklerdir ve makineden makineye değişmezler. `ayni` sütunu iki gerçekleştirimin aynı
toplamları ürettiğini doğruluyor; farklı sonuç veren iki gerçekleştirimin süreleri
karşılaştırılamaz.

#### Tablonun Söylediği

Mutlak süreler dördüncü ve beşinci sütunda değil, **kalem başına** sütunlarında okunur.

B'nin kalem başına süresi dört yükte 0,07 ve üç kez 0,02 mikrosaniyedir; ilk satırdaki fark
ısınmadan gelir, sonrası sabittir. Yük sekiz katına çıktığında kalem başına süre değişmiyor:
**işin maliyeti kalem sayısıyla doğru orantılı.**

A'nın kalem başına süresi bu koşumda 0,67'den 2,95 mikrosaniyeye çıkıyor. Yük sekiz katına
çıkarken kalem başına maliyet de büyüyor, çünkü her kalem daha çok bölüm için taranıyor. Asıl
okuma `mertebe` sütunundadır. Değer 1 olsaydı süre yükle doğru orantılı büyüyordu; 2 olması
sürenin yükün karesiyle büyüdüğünü gösterir. Ölçümde son iki ikiye katlamada 1,92 ve 1,95 çıkıyor,
yani **yük iki katına çıktığında süre dört katına çıkıyor.** İlk ikiye katlamada değer 1,28'de
kalıyor; sebebi en küçük yükte çalışma zamanının henüz ısınmamış olmasıdır ve aşağıdaki hesap
katsayıyı bu yüzden en küçük değil en büyük ölçümden alır. Mutlak süreler makineye göre değişir,
mertebe değişmez — sütunun eklenme nedeni budur.

Şimdi kritik gözlem. İlk satırda A ile B arasındaki oran 10 dolayındadır ve A'nın mutlak süresi
on beş milisaniyeyi geçmez — bir toplu iş için hiç sorun değil. Bu yükte alınmış bir başarım
ölçümü A'yı kabul edilebilir bulur ve etmekle haklıdır. Dördüncü satırda oran yüzü aşar (bu
koşumda 160). **Aynı sistem, aynı kod, aynı makine; değişen tek şey yük.** Oranın kendisi yükün
bir işlevidir, dolayısıyla "A, B'den şu kadar yavaştır" cümlesi yüksüz söylendiğinde anlamsızdır.

#### Kapasite

Eğriyi karara çeviren şey bir eşiktir. Kabaca Büyüklük Hesabı dersinde gün sonu işinin dört
saatlik bir pencerede koştuğu ve otuz günü kapsayan 12 milyon kaydı taradığı hesaplanmıştı.
**Kapasite**, eşiği karşılayan en büyük yüktür. Aşağıdaki hesap ölçülen katsayıları alır, iki
gerçekleştirimin süresini bugünün ve iki ile dört katı hacmin altında bulur, sonra her birinin
kapasitesini çıkarır.

```js
// hesap/kapasite.mjs — olculen katsayilardan dort saatlik pencerede kapasite ve sabit carpan kazancinin etkisi
const PENCERE = 4 * 3600 * 1000;   // V10: toplu is penceresi (ms)
const GUNLUK = 400_000;            // V3: gunde olusan yeni gonderi
const GUN = 30;                    // V11: ucretlendirmenin taradigi gun
const BUGUN = GUNLUK * GUN;        // taranan kayit
const BOLUM_BASINA = 100;          // varsayim: bir fatura satirina toplanan kalem sayisi

console.log(`taranan kayit = ${BUGUN}, gunluk bolum = ${GUNLUK / BOLUM_BASINA} (= satici), ` +
  `${GUN} gunde bolum = ${BUGUN / BOLUM_BASINA}`);

const OLCUM = { n: 160_000, bolum: 1_600, aMs: 471.7, bMs: 2.9 };  // toplu/gruplama.mjs son satiri
const aBirim = OLCUM.aMs / (OLCUM.n * OLCUM.bolum);    // ms / kontrol
const bBirim = OLCUM.bMs / OLCUM.n;                    // ms / kalem
console.log(`girdi: bu makinedeki bir kosumun olcumu (A ${OLCUM.aMs} ms, B ${OLCUM.bMs} ms, ` +
  `n = ${OLCUM.n}); asagidaki butun sureler ve kapasiteler bu iki sayiya baglidir`);

const aSure = (n) => aBirim * n * (n / BOLUM_BASINA);
const bSure = (n) => bBirim * n;
const saat = (ms) => ms / 3_600_000;

console.log(`A birim = ${aBirim.toExponential(2)} ms/kontrol, B birim = ${bBirim.toExponential(2)} ms/kalem`);
console.log("kayit          A suresi(saat)   B suresi(saat)   A pencereye sigar");
for (const kat of [1, 2, 4]) {
  const n = BUGUN * kat;
  console.log(`${String(n).padStart(9)} (x${kat})  ${saat(aSure(n)).toFixed(3).padStart(13)}  ` +
    `${saat(bSure(n)).toFixed(5).padStart(15)}  ${String(aSure(n) <= PENCERE).padStart(17)}`);
}

const aKapasite = (birim) => Math.sqrt((PENCERE * BOLUM_BASINA) / birim);
const bKapasite = (birim) => PENCERE / birim;
console.log(`\nA kapasitesi = ${(aKapasite(aBirim) / 1e6).toFixed(1)} milyon kayit ` +
  `(bugunun ${(aKapasite(aBirim) / BUGUN).toFixed(2)} kati)`);
console.log(`B kapasitesi = ${(bKapasite(bBirim) / 1e9).toFixed(0)} milyar kayit ` +
  `(bugunun ${(bKapasite(bBirim) / BUGUN).toFixed(0)} kati)`);
console.log(`gerceklestirim 100 kat hizlansa: A kapasitesi x${(aKapasite(aBirim / 100) / aKapasite(aBirim)).toFixed(0)}, ` +
  `B kapasitesi x${(bKapasite(bBirim / 100) / bKapasite(bBirim)).toFixed(0)}`);

const yarim = aBirim * BUGUN * (BUGUN / (BOLUM_BASINA / 2));
console.log(`varsayim 100 yerine 50 olsa: A suresi ${saat(yarim).toFixed(3)} saat ` +
  `(x${(yarim / aSure(BUGUN)).toFixed(0)}), B suresi degismez`);
```

```
taranan kayit = 12000000, gunluk bolum = 4000 (= satici), 30 gunde bolum = 120000
girdi: bu makinedeki bir kosumun olcumu (A 471.7 ms, B 2.9 ms, n = 160000); asagidaki butun sureler ve kapasiteler bu iki sayiya baglidir
A birim = 1.84e-6 ms/kontrol, B birim = 1.81e-5 ms/kalem
kayit          A suresi(saat)   B suresi(saat)   A pencereye sigar
 12000000 (x1)          0.737          0.00006               true
 24000000 (x2)          2.948          0.00012               true
 48000000 (x4)         11.793          0.00024              false

A kapasitesi = 28.0 milyon kayit (bugunun 2.33 kati)
B kapasitesi = 794 milyar kayit (bugunun 66207 kati)
gerceklestirim 100 kat hizlansa: A kapasitesi x10, B kapasitesi x100
varsayim 100 yerine 50 olsa: A suresi 1.474 saat (x2), B suresi degismez
```

İlk satır bölüm sayımının V3 ile tuttuğunu gösteriyor: günde 4000 bölüm, yani 4000 satıcı, otuz
günde 120 000 bölüm. Bölüm sayısı satıcı sayısıyla karıştırılmamalıdır — biri günlük, öteki
dönemlik bir sayıdır ve A'nın maliyeti dönemlik olana bağlıdır.

İkinci satır bütün hesabın neye dayandığını yazıyor: girdi tek bir koşumun ölçümüdür. Aşağıdaki
saat ve kapasite değerlerinin hepsi o iki sayıyla birlikte değişir; sabit olan, aralarındaki
oranlar ve eğrilerin biçimidir.

Üçüncü satır dersin en önemli sonucudur: **A bugünün eşiğini karşılıyor.** 12 milyon kaydı 0,737
saatte, yani kırk dört dakikada tarıyor; dört saatlik pencerenin içindedir. Bir kabul sınaması bu
gerçekleştirimi geçirir, bir başarım raporu onu kusursuz gösterir.

Hacim iki katına çıktığında A 2,948 saate çıkar — hâlâ pencerenin içinde, ama payı dört kat
küçülmüştür. Dört katına çıktığında 11,793 saattir ve pencere kırılır. Hacim iki katına
çıkarken sürenin dört katına çıkması ölçeklenebilirlik sorununun tanımıdır; başarım sorunu
olsaydı süre de iki katına çıkardı.

Kapasite satırları aynı şeyi tek sayıya indiriyor. A bu ölçümle 28,0 milyon kayıt taşır, bugünün
2,33 katı; başka bir makinede sayı değişir, bugünün küçük bir katı olması değişmez. B 794 milyar
taşır — bu sayı aritmetik bir uzatmadır ve o hacme çok önce bellek sınırı girer; anlamı
"pratikte bu iş artık zaman sınırına takılmaz"dır. İki gerçekleştirim arasındaki karar, ölçülen
süreler değil bu paylardır.

#### Sabit Çarpan Mertebeyi Yenmez

Son iki satır iki ayrı iyileştirme türünü ayırıyor.

Gerçekleştirim 100 kat hızlandırılırsa — daha ucuz karşılaştırma, daha sıkı döngü, daha iyi veri
düzeni — A'nın kapasitesi yalnız 10 katına çıkar. Süre yükün karesiyle büyüdüğü için kapasite
hızın karekökü kadar büyür. Aynı 100 katlık kazanç B'nin kapasitesini 100 katına çıkarır. **Sabit
çarpan kazancı, mertebesi kötü olan bir çözümde kendi kadar geri dönmez.**

Son satır varsayımın duyarlılığını veriyor. Fatura satırına toplanan kalem 100 yerine 50 olsa
bölüm sayısı iki katına çıkar; A'nın süresi 1,474 saate, yani iki katına çıkar, B'nin süresi hiç
değişmez. Varsayım yalnız bir gerçekleştirimi ilgilendiriyor. Bir varsayımın yanlış olması bir
tasarımı bozarken ötekini etkilemiyorsa, bu iki tasarım arasındaki gerçek farktır.

#### Özet

- Başarım belirli bir yükte ölçülen tek bir değerdir; ölçeklenebilirlik ölçütün yükle değişimidir
  ve tek bir ölçümden çıkarılamaz.
- Ölçümde B'nin kalem başına süresi sekiz kat yükte sabit kaldı (0,02 mikrosaniye), A'nın süresi
  büyüdü; türetilen `mertebe` sütunu son iki ikiye katlamada 1,92 ve 1,95 verdi, yani süre kalem
  sayısının karesiyle büyüyor. Ham süreler makineye bağlıdır, mertebe değildir.
- A ile B arasındaki oran yükün işlevidir: en küçük yükte 10 dolayında, en büyük yükte yüzü
  aşıyor. Yüksüz bildirilen bir oran anlamsızdır.
- A bugünün eşiğini karşılıyor: 12 milyon kaydı bu ölçümle 0,737 saatte tarıyor. Hacim dört
  katına çıktığında 11,793 saate çıkar ve dört saatlik pencere kırılır.
- Kapasite A için bu ölçümle 28,0 milyon kayıt, bugünün 2,33 katıdır; B için zaman sınırı
  pratikte bağlayıcı değildir ve yerini bellek sınırı alır.
- Gerçekleştirim 100 kat hızlanırsa A'nın kapasitesi 10, B'nin kapasitesi 100 katına çıkar;
  sabit çarpan kazancı mertebeyi yenmez.

#### Sonraki Adım

Bu ders yükü değiştirdi ve kaynağı sabit tuttu: ölçümlerin hepsi tek bir süreçte, tek bir
işçiyle alındı. Kapasite hesabı da bu varsayımla geçerlidir — Kabaca Büyüklük Hesabı dersinin
kayıt başına 1,20 milisaniyelik payı da öyleydi. Kaynak değiştirilebilir bir büyüklüktür ve
değiştirilmesinin iki yolu vardır: aynı birimi büyütmek ya da birim sayısını artırmak. İkisi
farklı sınırlara çarpar, farklı koşullar ister ve maliyetleri farklı eğrilerle büyür. Sonraki
ders işçi sayısını 1'den 16'ya çıkararak gün sonu işinin hızlanmasını ölçer, hızlanmanın
durduğu noktayı bulur ve iki yolun maliyetini aynı eşiğin altında karşılaştırır.

### Yatay ve Dikey Ölçekleme

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/yatay-ve-dikey-olcekleme

Kaynağı değiştirmenin iki yolu ve her birinin sert sınırı: aynı işin bir işçiden on altı işçiye bölünmesiyle hızlanmanın ve verimliliğin ölçülmesi, bölümleme kararının seri payı ve üst sınırı nasıl değiştirdiğinin sayılması, çekirdek sayısının dikey ölçeklemeye koyduğu sınırın ölçülmesi ve iki yolun maliyet eğrilerinin aynı hedef altında karşılaştırılması.

Önceki ders yükü değiştirdi ve kaynağı sabit tuttu; bütün ölçümler tek bir işçiyle alındı.
Kapasite hesabı da bu varsayımla geçerliydi. Kaynak ise değiştirilebilir bir büyüklüktür ve
değiştirilmesinin iki yolu vardır: aynı birimi büyütmek ya da birim sayısını artırmak. Bu ders
iki yolu ayırır, ikisinin de nerede durduğunu ölçer ve maliyetlerini aynı hedef altında
karşılaştırır.

Ayrımın adları katalogda geçtiği gibidir. **Dikey ölçekleme** (vertical scaling) ölçekleme
biriminin kendisini büyütmektir: aynı birime daha çok işlemci, daha çok bellek. **Yatay
ölçekleme** (horizontal scaling) birim sayısını artırmaktır. Sunucu Tarafı Temelleri kursunda
ölçekleme biriminin süreç olduğu ve süreçlerin bellek paylaşmadığı kurulmuştu; bu ders o
kuralın sonucunu bir ölçüye çevirir.

#### Aynı İş, Artan İşçi Sayısı

Ölçülen iş gün sonu ücretlendirmesidir: otuz günü kapsayan 12 milyon kayıt fiyatlanır ve her
fatura satırı için bir denetim izi üretilir. Önceki derste kurulan gruplama birimi geçerlidir —
bir **bölüm** bir satıcının bir günüdür, dolayısıyla otuz günlük taramada 120 000 bölüm vardır
(4000 satıcı çarpı 30 gün). İş bir işçiden on altı işçiye kadar bölünür ve her düzeyde toplam
süre ölçülür. Kayıtlar okunmaz, deterministik olarak üretilir; ölçülen şey hesap payının
paralelleşmesidir, girdi-çıktı değildir.

```js
// olcek/isci.mjs — bir isci: kendi payindaki kalemleri fiyatlar, imzalar ve bolum toplamlarini dondurur
import { parentPort, workerData } from "node:worker_threads";

const TARIFE = { kademe: [[1, 3000], [5, 4800], [20, 9600]], bolge: { "34": 100, "06": 115, "35": 125 }, asgari: 2500 };
const BOLGE = ["34", "06", "35"];

function net(agirlik, bolge, oran) {
  const kademe = TARIFE.kademe.find(([s]) => agirlik <= s) ?? [0, 9600];
  const taban = Math.max(TARIFE.asgari, Math.round((kademe[1] * TARIFE.bolge[bolge]) / 100));
  return taban - Math.round(taban * Math.min(oran, 0.4));
}

function imza(metin) {              // fatura satirinin denetim izi
  let h = 2166136261;
  for (let i = 0; i < metin.length; i += 1) h = Math.imul(h ^ metin.charCodeAt(i), 16777619) >>> 0;
  return h;
}

function pay({ bas, bit, adim, bolum }) {
  const toplam = new Map();
  for (let i = bas; i < bit; i += adim) {
    const b = i % bolum;
    const deger = net((i % 20) + 1, BOLGE[i % 3], (i % 5) / 20);
    const iz = imza(`G${i};${BOLGE[i % 3]};${deger}`);
    const onceki = toplam.get(b) ?? { net: 0, iz: 0 };
    toplam.set(b, { net: onceki.net + deger, iz: (onceki.iz ^ iz) >>> 0 });
  }
  return [...toplam];
}

if (workerData === null) console.log("bu dosya olcek/kos.mjs tarafindan isci olarak calistirilir");
else parentPort.postMessage(pay(workerData));
```

```
bu dosya olcek/kos.mjs tarafindan isci olarak calistirilir
```

Kalem sayısı V3 ile V11'in çarpımıdır ve Kabaca Büyüklük Hesabı dersindeki tablodan gelir; bu
ders kendi hacim sayısını seçmez. Bölüm sayısı V13'ten türetilir: fatura satırına yüz
kalem toplandığına göre on iki milyon kalem 120 000 bölüme düşer. Bölüm sayısı
satıcı sayısı değildir — 4000 satıcının otuz günü 120 000 satıcı-gün eder.

Sürücü işi iki farklı biçimde böler. **İndis** bölümlemesi kalemleri bitişik bloklara ayırır;
bir bölümün kalemleri bütün işçilere dağılır. **Anahtar** bölümlemesi adımlı ilerler; her bölüm
tek bir işçiye düşer. İkisi de aynı sayıda kalem işler ve aynı sonucu üretmelidir.

```js
// olcek/kos.mjs — ayni is 1..16 isciye bolunur; hizlanma, verimlilik ve birlestirme payi olculur
import { Worker } from "node:worker_threads";
import { availableParallelism } from "node:os";

const KALEM = 12_000_000;          // V3 x V11: otuz gunu kapsayan kayit sayisi
const BOLUM = KALEM / 100;         // varsayim: bir fatura satirina 100 kalem -> 4000 satici x 30 gun
const ISCI = [1, 2, 4, 8, 12, 16];

function isci(veri) {
  return new Promise((coz, sap) => {
    const w = new Worker(new URL("./isci.mjs", import.meta.url), { workerData: veri });
    w.on("message", coz);
    w.on("error", sap);
  });
}

function bolumler(n, kip) {        // "indis": bitisik blok, "anahtar": adimli
  return kip === "indis"
    ? Array.from({ length: n }, (_, s) => ({ bas: Math.floor((s * KALEM) / n), bit: Math.floor(((s + 1) * KALEM) / n), adim: 1, bolum: BOLUM }))
    : Array.from({ length: n }, (_, s) => ({ bas: s, bit: KALEM, adim: n, bolum: BOLUM }));
}

async function kos(n, kip) {
  const bas = performance.now();
  const paylar = await Promise.all(bolumler(n, kip).map(isci));
  const paralel = performance.now() - bas;
  const birlesikBas = performance.now();
  const fatura = new Map();
  let cakisma = 0;
  for (const pay of paylar) {
    for (const [b, v] of pay) {
      const onceki = fatura.get(b);
      if (onceki === undefined) fatura.set(b, { ...v });
      else { onceki.net += v.net; onceki.iz = (onceki.iz ^ v.iz) >>> 0; cakisma += 1; }
    }
  }
  const birlestirme = performance.now() - birlesikBas;
  const imza = [...fatura].reduce((a, [, v]) => (a ^ v.iz) >>> 0, 0);
  return { paralel, birlestirme, toplam: paralel + birlestirme, bolum: fatura.size, cakisma, imza };
}

console.log(`cekirdek = ${availableParallelism()}, kalem = ${KALEM}, bolum = ${BOLUM}`);
for (const kip of ["indis", "anahtar"]) {
  console.log(`\nbolumleme = ${kip}`);
  console.log("isci   paralel(ms)  birlestirme(ms)  toplam(ms)  hizlanma  verimlilik  cakisan kayit  imza");
  let taban = 0;
  for (const n of ISCI) {
    const r = await kos(n, kip);
    if (n === 1) taban = r.toplam;
    console.log(`${String(n).padStart(4)}  ${r.paralel.toFixed(0).padStart(11)}  ${r.birlestirme.toFixed(1).padStart(15)}  ` +
      `${r.toplam.toFixed(0).padStart(10)}  ${(taban / r.toplam).toFixed(2).padStart(8)}  ` +
      `${(taban / r.toplam / n).toFixed(2).padStart(10)}  ${String(r.cakisma).padStart(13)}  ${r.imza}`);
  }
}
```

{/* mask: [ ]*[0-9][0-9.]*(?=(?:[ ]+[^ ]+){2,6}$) */}
{/* mask: (?<=cekirdek[ ]=[ ])[0-9]+ */}
```
cekirdek = 12, kalem = 12000000, bolum = 120000

bolumleme = indis
isci   paralel(ms)  birlestirme(ms)  toplam(ms)  hizlanma  verimlilik  cakisan kayit  imza
   1         1674              8.4        1683      1.00        1.00              0  799471432
   2          941             13.3         954      1.76        0.88         120000  799471432
   4          602             24.6         626      2.69        0.67         360000  799471432
   8          580             42.9         622      2.70        0.34         840000  799471432
  12          883             70.6         953      1.76        0.15        1320000  799471432
  16          882             68.3         950      1.77        0.11        1800000  799471432

bolumleme = anahtar
isci   paralel(ms)  birlestirme(ms)  toplam(ms)  hizlanma  verimlilik  cakisan kayit  imza
   1         1662              9.9        1672      1.00        1.00              0  799471432
   2          879              5.6         885      1.89        0.94              0  799471432
   4          549              5.5         554      3.02        0.75              0  799471432
   8          321              6.8         328      5.11        0.64              0  799471432
  12          284              5.5         289      5.79        0.48              0  799471432
  16          364              6.9         370      4.51        0.28              0  799471432
```

Bu sayılar ölçümdür ve bu makinede alınmıştır; çekirdek sayısı 12'dir ve başka bir makinede
tablonun kırılma noktası başka yerdedir. İmza sütunu on iki koşumda da aynı değeri veriyor
(799471432), yani bütün bölümlemeler aynı faturayı üretti; farklı sonuç veren koşumların
süreleri karşılaştırılamaz. Tek işçili iki taban süresi 1683 ve 1672 milisaniyedir; aradaki
fark ölçüm gürültüsüdür ve bu yüzden hızlanma her kipin kendi tabanına göre okunur.

#### Bir Sert Sınır

Anahtar bölümlemesinde hızlanma 1'den 12 işçiye kadar büyüyor: 1,89, 3,02, 5,11 ve 5,79. On altı
işçide **düşüyor**: 4,51. Bu düşüş ölçüm hatası değil, dikey ölçeklemenin sınırının ta kendisi.
Makinede 12 çekirdek var; on altı işçi on iki çekirdeği paylaşmak zorundadır ve paylaşımın
kendisi bir maliyettir. Birimi büyütmenin bir noktada duracağı sezgisel bir iddia değil,
tabloda okunan bir sayıdır.

Verimlilik sütunu aynı şeyi başka açıdan söylüyor. **Paralel verimlilik** (parallel efficiency)
işçi başına elde edilen hızlanma payıdır, yani hızlanmanın işçi sayısına bölümü; Kalite
Nitelikleri dersinin başarım verimliliği ailesiyle karıştırılmamalıdır, o bir nitelik ailesinin
adıdır. Ölçümde iki işçide 0,94, dört işçide 0,75, sekiz işçide 0,64, on iki işçide 0,48.
**Her eklenen işçi öncekinden az getirir.** Değerin 1'in altına düşmesi bir kusur değil, paralel
işin doğasıdır; kararı ilgilendiren şey ne kadar hızlı düştüğüdür.

#### Yatay Ölçeklemenin Koşulu

İki bölümlemenin farkı dersin ikinci sonucudur. Aynı iş, aynı işçi sayısı, aynı makine — sekiz
işçide hızlanma anahtar bölümlemesinde 5,11, indis bölümlemesinde 2,70. Neredeyse iki katı fark
yalnızca **işin nasıl bölündüğünden** geliyor.

Farkın kaynağı çakışan kayıt sütununda. İndis bölümlemesinde on altı işçi 1 800 000 çakışan
kayıt üretti: bir bölümün toplamı birden çok işçide parça parça durduğu için her parça
birleştirme adımında toplanmak zorunda. Anahtar bölümlemesinde bu sayı sıfırdır. Birleştirme
süresi de buna göre ayrışıyor: on altı işçide 68,3 milisaniyeye karşı 6,9 milisaniye.

Sunucu Tarafı Temelleri kursunda durumsuz süreç kuralı konmuştu: istekler arasında yaşaması
gereken durum süreç dışına taşınır. Buradaki ölçüm o kuralın ölçekleme tarafındaki karşılığıdır.
Yatay ölçekleme birim sayısını artırmakla olmaz; **işin, birimler arasında paylaşılan durum
gerektirmeyecek biçimde bölünebilmesiyle** olur. Bölümleme anahtarının seçimi bu yüzden bir
ayrıntı değil, ölçeklenebilirlik kararının kendisidir. Bölüm ve bölümleme terimleri İleri SQL
kursunda tablo bölümleme bağlamında kurulmuştu; buradaki bağlam işin işçilere bölünmesidir,
verinin diske değil.

#### Seri Pay, Üst Sınır ve Maliyet

Ölçülen hızlanmadan bir sayı daha çıkarılabilir. İşin bir kısmı bölünemez — işçilerin
başlatılması, payların toplanması, sonucun yazılması. Bu **seri pay** $s$ ise, $n$ işçiyle en
iyi hızlanma şudur:

$$
S(n) = \frac{1}{s + \dfrac{1 - s}{n}}
$$

Bağıntı tersten çözülünce ölçülen bir hızlanmadan seri pay çıkar ve $n$ sonsuza giderken
hızlanma $1/s$ ile sınırlanır. Aşağıdaki hesap bunu iki bölümleme için yapar, sonra bir hedefi
karşılamanın iki yoldaki maliyetini karşılaştırır. Dikey maliyet için bir **varsayım** gerekir:
birimin gücü iki katına çıktığında birim maliyeti kaç katına çıkar. Üç değer birlikte veriliyor
çünkü sonuç bu varsayıma duyarlıdır.

```js
// hesap/maliyet.mjs — olculen hizlanmadan seri pay, ust sinir ve iki yolun maliyeti
const OLCUM = { anahtar: { isci: 8, hizlanma: 5.11 }, indis: { isci: 8, hizlanma: 2.70 } };
const MAKINE_SINIRI = 5.79;        // olculen: bu makinede tek birimin en yuksek hizlanmasi (12 cekirdek)

const seriPay = (n, S) => (1 / S - 1 / n) / (1 - 1 / n);
const amdahl = (s, n) => 1 / (s + (1 - s) / n);
const gerekenBirim = (s, K) => (1 - s) / (1 / K - s);

console.log("bolumleme   olculen(isci/hizlanma)   seri pay   ust sinir(1/s)");
for (const [ad, o] of Object.entries(OLCUM)) {
  const s = seriPay(o.isci, o.hizlanma);
  console.log(`${ad.padEnd(12)}${`${o.isci} / ${o.hizlanma.toFixed(2)}`.padStart(21)}${(s * 100).toFixed(1).padStart(11)}%` +
    `${(1 / s).toFixed(1).padStart(17)}`);
}

const s = seriPay(OLCUM.anahtar.isci, OLCUM.anahtar.hizlanma);
console.log("\nhedef  yatay birim   yatay maliyet   dikey x2.0   dikey x2.5   dikey x3.0   dikey ulasilir");
for (const K of [2, 4, 8, 16]) {
  const birim = gerekenBirim(s, K);
  const dikey = (c) => c ** Math.log2(K);
  console.log(`${`x${K}`.padStart(5)}${(birim > 0 ? birim.toFixed(1) : "ulasilmaz").padStart(13)}` +
    `${(birim > 0 ? birim.toFixed(1) : "-").padStart(16)}${dikey(2.0).toFixed(1).padStart(13)}` +
    `${dikey(2.5).toFixed(1).padStart(13)}${dikey(3.0).toFixed(1).padStart(13)}` +
    `${String(K <= MAKINE_SINIRI).padStart(15)}`);
}

console.log(`\n16 isciye kadar amdahl ongorusu (anahtar bolumlemesi, s = ${(s * 100).toFixed(1)}%):`);
console.log([1, 2, 4, 8, 12, 16].map((n) => `${n}:${amdahl(s, n).toFixed(2)}`).join("  "));
```

```
bolumleme   olculen(isci/hizlanma)   seri pay   ust sinir(1/s)
anahtar                  8 / 5.11        8.1%             12.4
indis                    8 / 2.70       28.0%              3.6

hedef  yatay birim   yatay maliyet   dikey x2.0   dikey x2.5   dikey x3.0   dikey ulasilir
   x2          2.2             2.2          2.0          2.5          3.0           true
   x4          5.4             5.4          4.0          6.3          9.0           true
   x8         20.8            20.8          8.0         15.6         27.0          false
  x16    ulasilmaz               -         16.0         39.1         81.0          false

16 isciye kadar amdahl ongorusu (anahtar bolumlemesi, s = 8.1%):
1:1.00  2:1.85  4:3.22  8:5.11  12:6.35  16:7.23
```

Seri pay satırları bölümleme kararının bedelini tek sayıya indiriyor: anahtar bölümlemesinde
%8,1 ve üst sınır 12,4; indis bölümlemesinde %28,0 ve üst sınır 3,6. Aynı iş, aynı donanım —
üst sınır üç kattan fazla ayrışıyor. İndis bölümlemesi seçilmiş bir sistemde on altı yerine bin
birim eklense hızlanma 3,6'yı geçmez.

Maliyet tablosu iki eğrinin biçimini gösteriyor. Yatay maliyet birim sayısıyla doğrusal ödenir
ama gereken birim sayısı doğrusal değildir: iki kat için 2,2 birim, dört kat için 5,4, sekiz kat
için 20,8. On altı kat satırında sayı yerine "ulaşılmaz" yazıyor, çünkü hedef seri payın koyduğu
12,4 üst sınırının üstündedir — o hedefe kaç birim eklenirse eklensin varılamaz. Dikey maliyet
ise varsayıma tamamen bağlı: çarpan 2,0 ise sekiz kat için 8,0 birim — yataydan ucuz; çarpan
3,0 ise 27,0 birim — yataydan pahalı.

Son sütun tartışmayı bitiriyor. Dikey yolun sekiz katına çıkması bu makinede **mümkün değil**,
çünkü ölçülen en yüksek hızlanma 5,79'dur. Dikey ölçeklemenin asıl sorunu maliyet eğrisi değil,
eğrinin bir yerde bitmesidir. Yatay yol pahalıdır ama sınırı seri paydan gelir, donanımdan
değil — ve seri pay bir tasarım kararıdır, ölçüm tablosunun ilk satırı bunu gösteriyor.

Son satır modelin kendi sınırını da gösteriyor. Bağıntı on iki işçi için 6,35, on altı işçi için
7,23 hızlanma öngörüyor; ölçülen değerler 5,79 ve 4,51'dir. Model çekirdek sayısını bilmez ve
hiç düşmez. **Bir modelin öngörüsü ölçümden ayrıldığında düzeltilecek olan ölçüm değil, modelin
varsayımıdır** — burada eksik varsayım işçi başına bir çekirdeğin bulunmasıdır.

#### Özet

- Dikey ölçekleme ölçekleme birimini büyütmek, yatay ölçekleme birim sayısını artırmaktır;
  ikisi farklı sınırlara çarpar.
- Anahtar bölümlemesinde hızlanma 12 işçide 5,79'a çıktı, 16 işçide 4,51'e düştü: çekirdek
  sayısı dikey yolun ölçülen sert sınırıdır.
- Paralel verimlilik her eklenen işçiyle düşüyor: 2 işçide 0,94, 8 işçide 0,64, 12 işçide 0,48.
- İşin bölünme biçimi hızlanmayı neredeyse iki katı değiştirdi: sekiz işçide 5,11'e karşı 2,70.
  İndis bölümlemesi 16 işçide 1 800 000 çakışan kayıt ve 68,3 ms birleştirme üretti, anahtar
  bölümlemesi 0 ve 6,9 ms.
- Ölçülen hızlanmadan çıkan seri pay anahtar bölümlemesinde %8,1 (üst sınır 12,4), indis
  bölümlemesinde %28,0 (üst sınır 3,6); bölümleme anahtarı bir ölçeklenebilirlik kararıdır.
- Hedefi sekiz katına çıkarmak yatay yolda 20,8 birim ister, dikey yolda bu makinede
  ulaşılamaz; on altı kat yatay yolda da ulaşılmazdır, çünkü seri pay üst sınırı 12,4'te tutar.

#### Sonraki Adım

Buraya kadarki üç ders sistemin **çalıştığı** varsayımıyla ölçüm yaptı. Yük, kapasite, hızlanma
ve maliyet — hepsi ayakta bir sistemin sayılarıdır. Ölçeklemenin gerekçesi de tek başına yük
değildir: on iki milyon kaydı 289 milisaniyede tarayan bir düzenek zaten yeterken birim sayısını
artırmanın başka bir nedeni olmalıdır. O neden birimlerin ayakta kalmamasıdır. Bir birim durduğunda
sistemin ne kadarı durur, ne kadar süre durur ve bu süre kabul edilebilir midir? Üçüncü soru bir
yüzdeyle yanıtlanır ve yüzde tek başına hiçbir şey söylemez: yüzde doksan dokuz ile yüzde doksan
dokuz virgül dokuz arasındaki fark, dakika olarak yazılana kadar görünmez. Sonraki ders hizmet
erişilebilirliğini bir kesinti bütçesine çevirir ve bileşenlerin birleştirilmesinin bu bütçeye ne
yaptığını hesaplar.

### Erişilebilirliğin Sayısal İfadesi

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/erisilebilirligin-sayisal-ifadesi

Hizmet erişilebilirliği yüzdesinin bir kesinti bütçesine çevrilmesi: yüzdelerin yıl, ay, hafta ve gün başına süreye dönüştürülmesi, bütçenin planlı işler ile arıza arasında bölünmesi, hedefin yükseltilmesinin planlı işleri olanaksız kılması ve seri bir zincirde çarpımın, kopyalamada tümleyenin bileşik erişilebilirliğe etkisinin hesaplanması.

Önceki üç ders sistemin çalıştığı varsayımıyla ölçüm yaptı: yük, kapasite, hızlanma ve maliyet.
Bir birim durduğunda sorulacak sorular başkadır. Sistemin ne kadarı durur, ne kadar süre durur
ve bu süre kabul edilebilir mi? Üçüncü soru bir yüzdeyle yanıtlanır ve yüzde tek başına hiçbir
şey söylemez.

Bu ders yüzdeyi bir süreye çevirir, o süreyi harcanabilir bir bütçe olarak ele alır ve
bileşenlerin birleştirilmesinin bütçeye ne yaptığını hesaplar. Bütün sayılar hesap sınıfındadır;
girdileri açıkça adlandırılmış varsayımlardır.

#### İki Erişilebilirlik ve İki Tanım

**Hizmet erişilebilirliği** (availability), sistemin isteklere yanıt verebildiği zamanın toplam
zamana oranıdır. Terim, arayüz **erişilebilirliği** (accessibility) ile karıştırılmamalıdır;
ikincisi bir arayüzün yardımcı teknolojilerle kullanılabilmesidir ve Erişilebilir Bileşen Kalıpları
kursunun konusudur. Bu derste geçen erişilebilirlik daima hizmet erişilebilirliğidir ve kısaltılmaz.

Oranın iki tabanı vardır ve aynı kesinti iki tabanda farklı görünür. **Zaman tabanlı** ölçüm
çalışan süreyi toplam süreye böler; kesinti dakikası sayılır. **İstek tabanlı** ölçüm başarılı
isteği toplam isteğe böler; kaç kullanıcının etkilendiği sayılır. İkisi ayrışır çünkü trafik
düzgün dağılmaz: Kabaca Büyüklük Hesabı dersinin tepe çarpanı 3 olduğuna göre, tepe saatte
düşen beş dakika, ortalama yükte düşen beş dakikanın üç katı isteği etkiler. Bu ders bütçeyi
zaman tabanlı kurar, çünkü bütçe önceden ayrılan bir miktardır ve trafiği bilmeden ayrılır.

#### Yüzdeyi Süreye Çevirmek

Yüzde biçimi karşılaştırmayı yanıltır: yüzde 99,9 ile yüzde 99,99 arasındaki 0,09 puanlık fark
küçük görünür. Aynı fark dakikaya çevrildiğinde görünmez olmaktan çıkar.

```js
// hizmet/butce.mjs — hizmet erisilebilirligi yuzdesinin donem basina kesinti butcesine cevrilmesi
const DONEM = [["yil", 365 * 24 * 60], ["ay", 30 * 24 * 60], ["hafta", 7 * 24 * 60], ["gun", 24 * 60]];
const YUZDE = [99, 99.5, 99.9, 99.95, 99.99, 99.999];

const yaz = (dk) => (dk >= 60 ? `${(dk / 60).toFixed(1)} sa` : dk >= 1 ? `${dk.toFixed(1)} dk` : `${(dk * 60).toFixed(1)} sn`);

console.log(`${"yuzde".padEnd(9)}${DONEM.map(([a]) => a.padStart(12)).join("")}`);
for (const y of YUZDE) {
  const kesir = 1 - y / 100;
  console.log(`${`%${y}`.padEnd(9)}${DONEM.map(([, dk]) => yaz(kesir * dk).padStart(12)).join("")}`);
}

const bir = 1 - 99.9 / 100;
const iki = 1 - 99.99 / 100;
console.log(`\n%99.9 -> %99.99: aylik butce ${yaz(bir * 43200)} yerine ${yaz(iki * 43200)}, ` +
  `${(bir / iki).toFixed(0)} kat daralma`);
console.log(`bir dokuz eklemek kesinti payini her seferinde 10'a boler; yuzde 0.09 puanlik fark ` +
  `aylik ${yaz((bir - iki) * 43200)} demektir`);
```

```
yuzde             yil          ay       hafta         gun
%99           87.6 sa      7.2 sa      1.7 sa     14.4 dk
%99.5         43.8 sa      3.6 sa     50.4 dk      7.2 dk
%99.9          8.8 sa     43.2 dk     10.1 dk      1.4 dk
%99.95         4.4 sa     21.6 dk      5.0 dk     43.2 sn
%99.99        52.6 dk      4.3 dk      1.0 dk      8.6 sn
%99.999        5.3 dk     25.9 sn      6.0 sn      0.9 sn

%99.9 -> %99.99: aylik butce 43.2 dk yerine 4.3 dk, 10 kat daralma
bir dokuz eklemek kesinti payini her seferinde 10'a boler; yuzde 0.09 puanlik fark aylik 38.9 dk demektir
```

Ay, otuz gün olarak alınmıştır; ayların uzunluğu eşit olmadığı için bütçenin dönemi baştan
tanımlanmalıdır, yoksa aynı yüzde şubatta başka bir dakika sayısı verir.

Tablonun ilk sonucu ölçek farkıdır. Sözlü tartışmada "yüzde doksan dokuz erişilebilir" cümlesi
güçlü durur; karşılığı bir yılda 87,6 saat, yani üç buçuk günü aşan bir kesintidir. Yüzde
99,999 aynı yılda 5,3 dakikadır — tek bir yeniden başlatma bu bütçenin tamamını harcar.

İkinci sonuç dönem seçiminin ölçüsüdür. Yüzde 99,9 bir ayda 43,2 dakika, bir günde 1,4 dakika
verir. İki sayı aynı hedefi anlatır ama farklı davranışa izin verir: aylık bütçe tek bir 43
dakikalık kesintiyi kabul eder, günlük bütçe etmez. **Hedefin dönemi hedefin kendisi kadar
belirleyicidir.**

#### Bütçe Harcanır

Kesinti bütçesinin asıl kullanımı, kesintiyi başa gelen bir şey olmaktan çıkarıp harcanan bir
kaynağa çevirmesidir. Bütçenin bir kısmı bilinçli olarak harcanır: her sürüm geçişinde süreçler
kapanıp açılır, planlı bakımda hizmet durur. Kalan kısım arızaya ayrılmış paydır.

Aşağıdaki hesap dört varsayım alır. **Hedef yüzde 99,9**; gerekçesi takip sorgusunun ticari bir
taahhüt taşıması ama ödeme akışı olmamasıdır. **Ayda 20 dağıtım** ve **dağıtım başına 15 saniye
yanıtsızlık**; gerekçesi sürüm geçişinde eski sürecin kapanıp yenisinin açılmasıdır. **Ayda 10
dakika planlı bakım.** Bir de **kurtarma süresi 10 dakika**; İlişkisel Veritabanı Yönetimi
kursundaki kurtarma süresi hedefiyle aynı büyüklüktür.

```js
// hizmet/harcama.mjs — aylik kesinti butcesinin planli islere ve arizaya bolunmesi
const AY = 30 * 24 * 60;           // dakika
const HEDEF = 99.9;                // varsayim: hizmet erisilebilirligi hedefi
const DAGITIM = 20;                // varsayim: aylik dagitim sayisi
const DAGITIM_SN = 15;             // varsayim: dagitim basina yanitsizlik (saniye)
const BAKIM_DK = 10;               // varsayim: aylik planli bakim (dakika)
const KURTARMA_DK = 10;            // varsayim: bir arizanin kurtarma suresi (dakika)

function butce(hedef, dagitim) {
  const toplam = (1 - hedef / 100) * AY;
  const planli = (dagitim * DAGITIM_SN) / 60 + BAKIM_DK;
  return { toplam, planli, ariza: toplam - planli, adet: (toplam - planli) / KURTARMA_DK };
}

console.log("hedef      dagitim   aylik butce   planli   arizaya kalan   kaldirilan ariza");
for (const [hedef, dagitim] of [[HEDEF, DAGITIM], [HEDEF, DAGITIM * 2], [99.99, DAGITIM]]) {
  const b = butce(hedef, dagitim);
  console.log(`%${String(hedef).padEnd(9)}${String(dagitim).padStart(7)}` +
    `${b.toplam.toFixed(1).padStart(14)} dk${b.planli.toFixed(1).padStart(9)} dk` +
    `${b.ariza.toFixed(1).padStart(16)} dk${b.adet.toFixed(2).padStart(19)}`);
}

const b = butce(HEDEF, DAGITIM);
console.log(`\nplanli islerin butcedeki payi = ${((b.planli / b.toplam) * 100).toFixed(1)}%`);
console.log(`hedef %99.99 olsa planli isler butcenin ${((butce(99.99, DAGITIM).planli / butce(99.99, DAGITIM).toplam) * 100).toFixed(0)}%'i olur`);
```

```
hedef      dagitim   aylik butce   planli   arizaya kalan   kaldirilan ariza
%99.9          20          43.2 dk     15.0 dk            28.2 dk               2.82
%99.9          40          43.2 dk     20.0 dk            23.2 dk               2.32
%99.99         20           4.3 dk     15.0 dk           -10.7 dk              -1.07

planli islerin butcedeki payi = 34.7%
hedef %99.99 olsa planli isler butcenin 347%'i olur
```

İlk satır bütçenin nasıl bölündüğünü gösteriyor: 43,2 dakikanın 15,0'ı planlı işlere gidiyor,
yani bütçenin yüzde 34,7'si daha hiçbir arıza olmadan harcanmış durumda. Arızaya kalan 28,2
dakika, on dakikalık kurtarma süresiyle ayda 2,82 arıza demektir: iki arıza bütçeye sığar,
üçüncüsü hedefi kırar.

İkinci satır varsayımın duyarlılığıdır: dağıtım sayısı iki katına çıktığında arıza payı 28,2'den
23,2 dakikaya, kaldırılabilen arıza 2,82'den 2,32'ye düşüyor. Daha sık yayın yapmak, daha az
arıza hakkı demektir — ikisi aynı bütçeden ödenir.

Üçüncü satır dersin en sert sonucudur. Hedef yüzde 99,99'a çıkarıldığında aylık bütçe 4,3
dakikaya iner ve planlı işlerin 15,0 dakikası bütçenin **yüzde 347'sini** tutar; arıza payı eksi
10,7 dakikadır. Hedef, hiçbir arıza olmasa bile karşılanamaz. **Bir erişilebilirlik hedefi
yükseltilirken dağıtım biçiminin de değişmesi gerekir**; yoksa hedef bir niyet beyanı olarak
kalır. Kesinti bütçesinin bir hedefi olanaksız olarak işaretleyebilmesi, onu bir ölçüt yapan
şeydir.

#### Bileşik Sistemde Çarpım

Bir isteğin yanıtlanması için birden çok bileşenin birlikte çalışması gerekir. Takip sorgusu uç
sürece gelir, önbelleğe bakar, gerekirse gönderi deposuna gider ve durum olay akışından
beslenir. Bileşenlerden biri düştüğünde istek yanıtlanamıyorsa, bileşenler **seri** bağlıdır ve
bileşik erişilebilirlik çarpımdır.

```js
// hizmet/bilesik.mjs — seri zincirde carpim, kopyada tumleyen: takip yolunun bilesik erisilebilirligi
const AY = 30 * 24 * 60;           // dakika
const ZINCIR = ["uc surec", "onbellek", "gonderi deposu", "olay akisi"];
const BILESEN = 0.999;             // varsayim: bilesen basina hizmet erisilebilirligi

const dakika = (a) => (1 - a) * AY;
const seri = (a, n) => a ** n;
const kopyali = (a, k) => 1 - (1 - a) ** k;

console.log(`zincir = ${ZINCIR.length} bilesen, bilesen basina %${(BILESEN * 100).toFixed(1)}`);
console.log("bilesen sayisi   bilesik erisilebilirlik   aylik kesinti");
for (let n = 1; n <= ZINCIR.length; n += 1) {
  const a = seri(BILESEN, n);
  console.log(`${String(n).padStart(14)}   ${(a * 100).toFixed(4).padStart(21)}%   ${dakika(a).toFixed(1).padStart(9)} dk`);
}

console.log("\nkopya sayisi   bilesen kesinti payi   zincir kesinti payi   aylik kesinti");
for (const k of [1, 2, 3]) {
  const b = kopyali(BILESEN, k);
  const z = seri(b, ZINCIR.length);
  console.log(`${String(k).padStart(12)}   ${(1 - b).toExponential(2).padStart(20)}   ` +
    `${(1 - z).toExponential(2).padStart(19)}   ${(dakika(z) * 60).toFixed(3).padStart(9)} sn`);
}

const iyi = 0.9999;
console.log(`\nduyarlilik: bilesen %${(iyi * 100).toFixed(2)} olsa kopyasiz zincir ` +
  `%${(seri(iyi, ZINCIR.length) * 100).toFixed(4)}, aylik ${dakika(seri(iyi, ZINCIR.length)).toFixed(1)} dk`);
console.log(`en zayif halka: zincir hicbir bilesenin uzerine cikamaz (ust sinir %${(BILESEN * 100).toFixed(1)})`);
```

```
zincir = 4 bilesen, bilesen basina %99.9
bilesen sayisi   bilesik erisilebilirlik   aylik kesinti
             1                 99.9000%        43.2 dk
             2                 99.8001%        86.4 dk
             3                 99.7003%       129.5 dk
             4                 99.6006%       172.5 dk

kopya sayisi   bilesen kesinti payi   zincir kesinti payi   aylik kesinti
           1                1.00e-3               3.99e-3   10352.458 sn
           2                1.00e-6               4.00e-6      10.368 sn
           3                1.00e-9               4.00e-9       0.010 sn

duyarlilik: bilesen %99.99 olsa kopyasiz zincir %99.9600, aylik 17.3 dk
en zayif halka: zincir hicbir bilesenin uzerine cikamaz (ust sinir %99.9)
```

Birinci tablo çarpımın yönünü veriyor: her bileşen yüzde 99,9 olmasına karşın dört bileşenlik
zincir yüzde 99,6006'dır ve aylık kesinti 43,2 dakikadan 172,5 dakikaya, yani neredeyse dört
katına çıkar. Kesinti payları yaklaşık olarak toplanır. Bunun tasarım sonucu doğrudandır:
**bileşen eklemek erişilebilirliği düşürür**, çünkü seri bir zincirde her yeni bileşen yeni bir
tek nokta demektir. Mimari Biçemler kursunda mikroservis düzeninin faturası birim sayısıyla
büyüyen durum sayısı olarak sayılmıştı; buradaki karşılığı çarpımdır.

Aynı tablo bir üst sınır da veriyor. Seri bir zincir en zayıf bileşeninin üzerine çıkamaz:
kopyalama olmadan, yüzde 99,9'luk bir bileşen içeren bir yol yüzde 99,95 olamaz. Bir hedef
bileşen hedeflerine bölünmeden konursa, tutulup tutulmadığı bileşenlere bakılarak sınanamaz.

İkinci tablo tersi yöndeki tek aracı gösteriyor: aynı bileşenin birden çok kopyasını koymak.
Kopyalar **koşut** bağlıdır — hepsi birlikte düşmedikçe bileşen ayaktadır — ve kesinti payı
kopya sayısıyla üs alır. Bir bileşenin kesinti payı binde birden ikinci kopyayla milyonda bire,
üçüncü kopyayla milyarda bire iner; dört bileşenlik zincirin aylık kesintisi 10 352 saniyeden
10,4 saniyeye, sonra 0,010 saniyeye düşer.

Bu ikinci tablonun bir varsayımı vardır ve varsayım gerçekte tam tutmaz: **kopyaların
birbirinden bağımsız düştüğü.** Aynı hatalı sürümü çalıştıran iki kopya aynı istekte birlikte
düşer; aynı yapılandırma hatası ikisini birlikte bozar. Bağımsızlık tutmadığı ölçüde gerçek
erişilebilirlik hesaplananın altında kalır, dolayısıyla bu sayılar bir **üst sınırdır**. Kopya
eklemek de aritmetikte göründüğü kadar ucuz değildir; kopyaların birbirinden habersiz kalması
başka bir maliyet doğurur ve o maliyet bu konunun geri kalanının konusudur.

Son satır duyarlılığı veriyor: bileşen erişilebilirliği yüzde 99,99 olsaydı kopyasız zincir
yüzde 99,9600 ve aylık kesinti 17,3 dakika olurdu. Aynı sonuca iki yoldan gidilebiliyor —
bileşeni iyileştirmek ya da kopyalamak — ve ikisinin maliyeti önceki dersin maliyet eğrileriyle
karşılaştırılır.

#### Özet

- Hizmet erişilebilirliği sistemin yanıt verebildiği zamanın oranıdır ve arayüz
  erişilebilirliğinden ayrı bir kavramdır; zaman tabanlı ile istek tabanlı ölçüm aynı kesintiyi
  farklı gösterir.
- Yüzde 99,9 yılda 8,8 saat, ayda 43,2 dakika, günde 1,4 dakika kesintidir; bir dokuz eklemek
  payı 10'a böler ve 0,09 puanlık fark aylık 38,9 dakika demektir.
- Hedefin dönemi hedef kadar belirleyicidir: aylık 43,2 dakika tek bir uzun kesintiye izin
  verir, günlük 1,4 dakika vermez.
- Bütçenin yüzde 34,7'si planlı işlere gidiyor (20 dağıtım ve 10 dakika bakım); arızaya kalan
  28,2 dakika on dakikalık kurtarma süresiyle ayda 2,82 arızadır.
- Hedef yüzde 99,99'a çıkarıldığında planlı işler bütçenin yüzde 347'sini tutar ve hedef hiçbir
  arıza olmadan bile karşılanamaz; hedefi yükseltmek dağıtım biçimini değiştirmeyi gerektirir.
- Seri zincirde erişilebilirlikler çarpılır: dört tane yüzde 99,9'luk bileşen yüzde 99,6006 ve
  aylık 172,5 dakika verir. Koşut kopyalarda kesinti payı üs alır, ama hesap kopyaların bağımsız
  düştüğünü varsaydığı için bir üst sınırdır.

#### Sonraki Adım

Bu ders hizmet erişilebilirliğini bir bütçeye çevirdi ve bütçenin nasıl harcandığını saydı:
dağıtım, bakım, arıza. Açıkta kalan soru bütçenin **neden** harcandığıdır. Kesintinin bir kısmı
arızadan gelir — bir bileşen düşer, kurtarılana kadar bütçeden dakika gider. Bir kısmı ise
bilinçli bir karardan gelir ve bu kısım aritmetikte görünmez. Kopya eklemenin faturası son
tabloda yarım kalmıştı: kopyalar birbirinden habersiz kaldığında sistem iki şeyden birini seçmek
zorundadır. Yanıt vermeyi mi seçer, doğru yanıt vermeyi mi? Yanıt vermeyi seçmek bütçeyi
korur ve yanlış bir değer döndürür; doğru yanıt vermek için beklemek ya da reddetmek bütçeden
harcar. Sonraki ders bu seçimi adlandırır, iki politikayı aynı arıza senaryosunda ölçer ve
kesinti bütçesinden kaç dakikanın hangi politika yüzünden gittiğini sayar.

### Erişilebilirlik ve Tutarlılık Gerilimi

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/erisilebilirlik-ve-tutarlilik-gerilimi

CAP teoreminin doğru okunması: bölünme dayanıklılığının bir seçim olmadığının gösterilmesi, aynı ağ bölünmesi senaryosunda yanıt verme ve reddetme politikalarının yanıtlanan istek ile bayat yanıt sayılarının ölçülmesi, reddetmenin harcadığı kesinti bütçesinin ve yanıt vermenin ürettiği bayat yanıt sayısının hesaplanması, teoremin yaygın yanlış okunuşlarının ayırt edilmesi.

Önceki ders hizmet erişilebilirliğini bir bütçeye çevirdi: yüzdeler yıllık kesinti süresine
dönüştü, bütçenin nasıl harcandığı sayıldı. Açıkta kalan soru bütçenin **neden** harcandığıdır.
Kesintinin bir kısmı arızadan gelir; bir kısmı ise bilinçli bir karardan. Bir kopya ötekinden
habersiz kaldığında sistem iki şeyden birini seçmek zorundadır: yanıt vermeyi mi, doğru yanıt
vermeyi mi.

Bu ders o seçimi adlandırır. Seçim keyfi bir tercih değildir; bir ağ üzerinde duran her sistemin
zorunlu olarak verdiği ve genellikle farkında olmadan verdiği bir karardır. Kararın adı **CAP
teoremi**dir ve teorem, alanın en çok yanlış okunan cümlesidir.

#### Üç Harf ve Seçilmeyen Harf

Teorem üç özelliği adlandırır.

**Tutarlılık** (consistency): her okuma, en son onaylanmış yazmayı görür. Sistem, dışarıdan tek
bir kopyası varmış gibi davranır. **Hizmet erişilebilirliği** (availability): çalışan her kopyaya
gelen her istek bir yanıt alır — hata değil, yanıt. Bu terim arayüz erişilebilirliğiyle
(accessibility) karıştırılmamalıdır; o, Erişilebilir Bileşen Kalıpları kursunun konusudur ve bu derste geçmez.
**Bölünme dayanıklılığı** (partition tolerance): kopyalar arasındaki iletiler kaybolduğunda bile
sistem çalışmayı sürdürür.

Üçüncü terimdeki **ağ bölünmesi**, İlişkisel Veritabanı Yönetimi kursunda geçen **bölümleme**
ile aynı şey değildir: bölümleme veriyi bilerek parçalara ayırmaktır, ağ bölünmesi ise
kopyaların birbirini görememesidir. Aynı kök, iki ayrı olgu.

Teoremin yanlış okunuşu buradan başlar, çünkü üç harf sanki üç seçenekmiş gibi sunulur. Değildir.
Ağ bölünmesi bir tasarım seçeneği değil, bir olgudur: kablo kopar, anahtar yeniden başlar, bir
bölge birkaç saniye ötekini duymaz. Bu olguyu "seçmemek" diye bir şey yoktur; olan tek şey, olgu
gerçekleştiğinde sistemin ne yapacağıdır. Teoremin gerçek ifadesi şudur: **ağ bölünmesi
sürerken tutarlılık ile hizmet erişilebilirliği birlikte sağlanamaz.** Bölünme yokken teorem
sessizdir.

Çoğaltma ve çoğaltma gecikmesi İlişkisel Veritabanı Yönetimi kursunda kuruldu; burada yeniden
anlatılmaz. Ölçülecek olan, o kopyaların bağı koptuğunda politikanın ne yaptığıdır.

#### İki Bölgeli Model

Gerçek bir küme kurmak yerine davranış süreç içi bir modelle gösterilir. Kopyalar birer nesne,
bağın kesikliği açık bir parametredir. Aşağıdaki metinde geçen sayıların hepsi bu modelin
koşumundan gelir; gerçek bir ağdan ölçülmüş gecikme değildir ve modelde saat kullanılmadığı için
her koşumda aynı çıkar.

Gönderi takip servisinin iki bölgesi var: taşıyıcı durum olayları `b34` bölgesine gelir, takip
sorguları iki bölgeye de gelebilir.

```js
// cap/model.mjs — iki bolgeli kopya modeli: kopyalar birer nesne, bag ve ileti acik parametre
export function kur() {
  const durum = { bag: true, ileti: 0 };
  const kopya = { b34: new Map(), b35: new Map() };
  const komsu = { b34: "b35", b35: "b34" };

  function yaz(bolge, anahtar, deger, tur) {
    kopya[bolge].set(anahtar, { deger, tur });
    if (durum.bag === false) return { yayilan: 0 };
    durum.ileti += 1;
    kopya[komsu[bolge]].set(anahtar, { deger, tur });
    return { yayilan: 1 };
  }

  // "yanit-ver": yerel kaydi dogrulamadan dondurur. "reddet": yanit ancak komsuyla
  // dogrulanabildiginde verilir; bag kesikse istek reddedilir.
  function oku(bolge, anahtar, politika) {
    const yerel = kopya[bolge].get(anahtar) ?? null;
    if (politika === "yanit-ver") return { yanit: yerel, red: false };
    if (durum.bag === false) return { yanit: null, red: true };
    durum.ileti += 1;
    return { yanit: yerel, red: false };
  }

  return { durum, kopya, yaz, oku };
}
```

İki politikanın kodda bir tek satırla ayrıldığına dikkat edilmelidir. `reddet` politikası, bağ
kesikken hiçbir şey döndürmez; elinde bir değer olsa bile onun en son değer olduğunu
doğrulayamadığı için yanıt vermez. Bütün ödünleşim bu satırın içindedir.

#### Aynı Senaryo, İki Politika

Sürücü betik on iki turluk bir senaryo koşturur. Her turda bir taşıyıcı durum olayı `b34`
bölgesine yazılır ve bir takip sorgusu gelir; sorgu sırayla iki bölgeye düşer. Bağ 3. turdan
8. tura kadar kesiktir.

```js
// cap/olc.mjs — ayni senaryo iki okuma politikasiyla: yanitlanan, reddedilen ve bayat sayilari
import { kur } from "./model.mjs";

const TAKIP = "TR-9042";
const OLAY = ["kabul", "cikis", "aktarma-34", "aktarma-41", "hat-35", "dagitim",
  "teslim-denemesi", "adres-dogrulama", "yeniden-dagitim", "teslim", "imza", "kapali"];
const BOLUNME = [3, 8]; // bag bu turlar arasinda kesik (iki uc dahil)

function kosum(politika) {
  const k = kur();
  const s = { istek: 0, yanit: 0, red: 0, bayat: 0, iz: [] };
  for (let tur = 1; tur <= OLAY.length; tur++) {
    k.durum.bag = tur < BOLUNME[0] || tur > BOLUNME[1];
    k.yaz("b34", TAKIP, OLAY[tur - 1], tur); // tasiyici olayi her zaman b34'e gelir
    const gercek = k.kopya.b34.get(TAKIP);
    const bolge = tur % 2 === 1 ? "b35" : "b34"; // takip sorgusu iki bolgeye sirayla gelir
    const r = k.oku(bolge, TAKIP, politika);
    s.istek += 1;
    if (r.red) { s.red += 1; s.iz.push(`${bolge}:red`); continue; }
    s.yanit += 1;
    const bayat = r.yanit.tur < gercek.tur;
    if (bayat) s.bayat += 1;
    s.iz.push(`${bolge}:${r.yanit.deger}${bayat ? "~" : ""}`);
  }
  return { ...s, ileti: k.durum.ileti };
}

const pencere = (a) => a.slice(BOLUNME[0] - 1, BOLUNME[1]);
console.log(`senaryo: ${OLAY.length} tur, bag ${BOLUNME[0]}-${BOLUNME[1]}. turlarda kesik`);
console.log("politika    | yanit | red | bayat | ileti | bolunme penceresi");
console.log("------------|-------|-----|-------|-------|------------------");
const cikti = {};
for (const p of ["yanit-ver", "reddet"]) {
  const s = kosum(p);
  cikti[p] = s;
  console.log(`${p.padEnd(11)} | ${String(`${s.yanit}/${s.istek}`).padStart(5)} | ` +
    `${String(s.red).padStart(3)} | ${String(s.bayat).padStart(5)} | ` +
    `${String(s.ileti).padStart(5)} | ${pencere(s.iz).join(" ")}`);
}
const bp = BOLUNME[1] - BOLUNME[0] + 1;
const say = (p, k) => pencere(cikti[p].iz).filter(k).length;
console.log(`bolunme penceresinde (${bp} tur): yanit-ver bayat = ` +
  `${say("yanit-ver", (x) => x.endsWith("~"))}/${bp}, reddet red = ` +
  `${say("reddet", (x) => x.endsWith("red"))}/${bp}`);
console.log(`bolunme disinda (${OLAY.length - bp} tur): iki politika da ayni yaniti verdi`);
```

```sh
node cap/olc.mjs
```

```
senaryo: 12 tur, bag 3-8. turlarda kesik
politika    | yanit | red | bayat | ileti | bolunme penceresi
------------|-------|-----|-------|-------|------------------
yanit-ver   | 12/12 |   0 |     3 |     6 | b35:cikis~ b34:aktarma-41 b35:cikis~ b34:dagitim b35:cikis~ b34:adres-dogrulama
reddet      |  6/12 |   6 |     0 |    12 | b35:red b34:red b35:red b34:red b35:red b34:red
bolunme penceresinde (6 tur): yanit-ver bayat = 3/6, reddet red = 6/6
bolunme disinda (6 tur): iki politika da ayni yaniti verdi
```

#### Sayıların Okunması

Son satır teoremin sessiz kaldığı yeri gösteriyor: bölünme dışındaki altı turda iki politika
birbirinden ayırt edilemez. Ödünleşim yalnız bölünme penceresinde vardır ve orada keskindir.

`yanit-ver` politikası 12/12 istek yanıtladı, hiçbirini reddetmedi; karşılığında 3 bayat yanıt
üretti. İzdeki `~` işareti bayat yanıtı gösteriyor: `b35` bölgesi bölünme boyunca `cikis`
durumunu döndürdü, oysa gönderi o sırada `dagitim` ve `adres-dogrulama` aşamalarına geçmişti.
Takip sorgusu yanıt aldı ama yanıt gerçeği söylemiyordu.

`reddet` politikası 6/12 istek yanıtladı; bölünme penceresindeki altı isteğin altısını da geri
çevirdi ve tek bir bayat yanıt üretmedi. Burada gözden kaçan bir ayrıntı var: politika `b34`
bölgesinden gelen istekleri de reddetti — oysa `b34` her turda en yeni değeri elinde tutuyordu.
Sebep, kopyanın elindeki değerin en yeni olduğunu **bilememesidir**. Bir kopya, komşusunun
kendisinden habersiz bir yazma almış olup olmadığını komşuya sormadan öğrenemez. Tutarlılık
güvencesi doğru değeri döndürmeyi değil, döndürülen değerin doğruluğunu doğrulayabilmeyi
gerektirir; doğrulama kanalı kesildiğinde güvence de kesilir.

İleti sütunu üçüncü bir maliyeti sayıyor. `yanit-ver` politikası 6 ileti harcadı: yalnız bağ
açıkken yayılan altı yazma. `reddet` politikası 12 ileti harcadı — aynı altı yayılma, artı
yanıtlanan her okuma için bir doğrulama iletisi. Bu sayı bölünmeyle ilgili değildir; bölünme
olmasa da orada olurdu. Sonraki dersin konusu tam olarak bu farktır.

#### Bütçenin Nereye Gittiği

Modelin ürettiği oranlar bir yıllık bütçeye çevrilebilir. Girdiler **varsayım**dır: ağ
bölünmesinin yılda kaç kez ve ne kadar sürdüğü, bölünme süresince saniyede kaç takip sorgusu
geldiği. İkinci koşum varsayımın duyarlılığını gösterir: bölünme süresi iki katına çıkarsa
sonuçlar ne olur.

```js
// cap/butce.mjs — modelin oranlarini yillik butceye cevirir; girdiler varsayimdir
const YIL = 365 * 24 * 3600;
const VARSAYIM = { bolunme: 12, sure: 40, sorgu: 30 }; // yilda kez, saniye, saniyedeki takip sorgusu
const MODEL = { redOrani: 6 / 6, bayatOrani: 3 / 6 };  // olcumden gelen oranlar

const yuzde = (s) => (100 * (1 - s / YIL)).toFixed(4);
for (const kat of [1, 2]) {
  const s = VARSAYIM.bolunme * VARSAYIM.sure * kat;
  const istek = s * VARSAYIM.sorgu;
  console.log(`bolunme ${s} sn/yil (${VARSAYIM.bolunme} kez x ${VARSAYIM.sure * kat} sn)` +
    ` -> pencerede ${istek} takip sorgusu`);
  console.log(`  reddet   : red = ${Math.round(istek * MODEL.redOrani)} istek,` +
    ` hizmet erisilebilirligi = %${yuzde(s * MODEL.redOrani)}, bayat = 0`);
  console.log(`  yanit-ver: red = 0 istek,` +
    ` hizmet erisilebilirligi = %${yuzde(0)}, bayat = ` +
    `${Math.round(istek * MODEL.bayatOrani)} yanit`);
}
```

```
bolunme 480 sn/yil (12 kez x 40 sn) -> pencerede 14400 takip sorgusu
  reddet   : red = 14400 istek, hizmet erisilebilirligi = %99.9985, bayat = 0
  yanit-ver: red = 0 istek, hizmet erisilebilirligi = %100.0000, bayat = 7200 yanit
bolunme 960 sn/yil (12 kez x 80 sn) -> pencerede 28800 takip sorgusu
  reddet   : red = 28800 istek, hizmet erisilebilirligi = %99.9970, bayat = 0
  yanit-ver: red = 0 istek, hizmet erisilebilirligi = %100.0000, bayat = 14400 yanit
```

İki politika aynı olguyu iki ayrı para birimiyle ödüyor. `reddet` politikası bütçeden 480 saniye
harcadı ve hizmet erişilebilirliğini yüzde 99,9985'e indirdi; bunun karşılığında yanlış bilgi
üretmedi. `yanit-ver` politikası bütçeden hiç harcamadı ama 7.200 takip sorgusuna eski durumu
söyledi. Varsayım iki katına çıktığında iki sayı da doğrusal büyüdü: yüzde 99,9970 ve 14.400.

Buradaki asıl sonuç, iki maliyetin **karşılaştırılabilir olmadığıdır**. Kesinti biter; yanlış
söylenmiş bir teslim durumu, ona bakıp karar veren birinin işine karışmıştır. Bu yüzden karar
sayıların büyüklüğüne değil, işin hangi hatayı taşıyabildiğine bakılarak verilir. Takip
sorgusunun birkaç saniye eski bir durum göstermesi katlanılabilir; gün sonu ücretlendirmesinin
eski bir duruma göre fatura kesmesi katlanılamaz. Aynı sistemde iki akış, iki ayrı politika.

#### Teoremin Yanlış Okunuşları

Dört yanlış okuma yaygındır ve dördü de ölçümle çürütülür.

**"Üçten ikisini seç."** Teorem bir menü sunmaz. Bölünme dayanıklılığı seçilen bir özellik
değil, ağ üzerinde durmanın sonucudur. Seçim iki harf arasındadır ve yalnız bölünme süresince
geçerlidir.

**"Bizim sistemimiz CA."** Ağ üzerinde dağılmış bir sistem için bu bir sınıf değil, bölünme
düşünülmemiş bir tasarımdır. Bölünme geldiğinde sistem gerçekte bir seçim yapar; kod bunu
yazmadıysa seçimi kütüphanenin öntanımlı davranışı yapar. Ölçümdeki tek satırlık fark, bu
öntanımlı davranışın nerede saklandığını gösteriyor.

**"Seçim sistem geneli içindir."** Ölçümdeki iki koşum aynı modeli kullandı; ayrılan tek şey
okuma politikasıydı. Politika istek başına verilebilir. Takip sorgusu `yanit-ver`, ücretlendirme
okuması `reddet` politikasıyla çalışabilir.

**"Tutarlılık seçilirse sistem yavaşlar, hepsi bu."** İleti sütunu bunun yarısının doğru
olduğunu gösteriyor: doğrulama gerçekten ileti harcar. Ama bölünme süresince harcanan şey süre
değil, yanıtın kendisidir — 6 istek reddedildi. İkisi ayrı maliyetlerdir ve ayrı ele alınır.

#### Özet

- CAP teoremi üç seçenek sunmaz: ağ bölünmesi bir olgudur, seçim yalnız bölünme sürerken
  tutarlılık ile hizmet erişilebilirliği arasındadır.
- Aynı on iki turluk senaryoda `yanit-ver` politikası 12/12 istek yanıtladı ve 3 bayat yanıt
  üretti; `reddet` politikası 6/12 yanıtladı, 6 istek reddetti ve 0 bayat yanıt üretti.
- Bölünme dışındaki altı turda iki politika ayırt edilemedi; ödünleşim yalnız pencerede vardır.
- `reddet` politikası en yeni değeri elinde tutan bölgede de reddetti: tutarlılık güvencesi
  doğru değeri döndürmeyi değil, doğruluğunu doğrulayabilmeyi gerektirir.
- Yılda 12 kez 40 saniye bölünme varsayımıyla `reddet` politikası 14.400 isteği reddederek
  hizmet erişilebilirliğini yüzde 99,9985'e indirdi; `yanit-ver` politikası bütçeden harcamadan
  7.200 bayat yanıt üretti. Varsayım iki katına çıkınca iki sayı da iki katına çıktı.
- İki maliyet aynı birimde değildir; karar, akışın hangi hatayı taşıyabildiğine göre istek
  başına verilir.

#### Sonraki Adım

Ölçümde bir sütun açıklanmadan kaldı. `reddet` politikası 12 ileti, `yanit-ver` politikası 6
ileti harcadı ve bu farkın bölünmeyle ilgisi yoktu: doğrulama iletileri bağ açıkken de
gönderildi. Yani seçim, ağ hiç bölünmese bile bitmiyor. Bölünme yokken de her yazmanın iki
kopyaya da onaylatılması ile bir kopyaya yazıp ötekine yayılmasının beklenmesi arasında bir
karar vardır; bu kararın bedeli reddedilen istek değil, beklenen tur sayısıdır. Sonraki ders
CAP teoreminin sustuğu bu bölgeyi adlandırır ve orada ölçülecek üç şeyi sayar: onay bekleme
adımı, okumada görülen eskilik penceresi ve yazma başına ileti sayısı.

### PACELC

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/pacelc

Bölünme dışındaki gecikme ödünleşimi: CAP teoreminin sustuğu bölgenin adlandırılması, bölünme yokken senkron onay ile eşzamansız yayma politikalarının onay bekleme adımı, yazma başına ileti sayısı ve okumada görülen eskilik penceresi bakımından ölçülmesi, varış aralığı ile gecikme varsayımlarının duyarlılığının gösterilmesi ve bir sistemin iki dalda ayrı ayrı sınıflandırılması.

Önceki dersin ölçümünde bir sütun açıklanmadan kaldı. Reddetme politikası 12 ileti, yanıt verme
politikası 6 ileti harcadı; fark, yanıtlanan her okumanın komşuya doğrulatılmasından geliyordu ve
bu iletiler bağ **açıkken** de gönderildi. Yani tutarlılıkla ilgili karar, ağ hiç bölünmese bile
bitmiyor.

CAP teoremi bu bölgede sessizdir: bölünme yoksa teoremin diyeceği bir şey yoktur. Oysa karar
oradadır ve her istekte ödenir. **PACELC** teoremi CAP'in sustuğu yeri doldurur ve bu dersin
konusu odur.

#### Teoremin İkinci Dalı

PACELC iki dallı bir cümledir. Birinci dal CAP'in söylediğidir: **bölünme** (P) varsa **hizmet
erişilebilirliği** (A) ile **tutarlılık** (C) arasında seçim yapılır. İkinci dal yenidir:
**başka durumda** (E, else — yani bölünme yokken) **gecikme** (L, latency) ile **tutarlılık** (C)
arasında seçim yapılır.

İkinci dalın gerekçesi basit bir olgudur: bir kopyanın elindeki değerin en güncel değer olduğunu
doğrulaması, komşusuyla konuşmasını gerektirir. Bu konuşma ağ üzerinden geçer ve bir bedeli
vardır. Bedel bölünmeye bağlı değildir; bağ sapasağlam olsa da her doğrulama bir gidiş dönüş
ister. Bu yüzden tutarlılık, kesinti yokken de ücretsiz değildir; yalnız ödenen para birimi
değişir — reddedilen istek değil, beklenen zaman.

#### Bölünme Yokken İki Yazma Politikası

Ölçülecek seçim yazma yolundadır. Taşıyıcıdan gelen bir durum olayı iki biçimde ele alınabilir:
her yazmayı iki kopyaya da onaylatmak (`onayli`) ya da bir kopyaya yazıp taşıyıcıya hemen onay
verip komşuya sonra yaymak (`yayilan`). Aşağıdaki model bu iki politikayı aynı olay dizisiyle
koşturur. Bağ hiç kesilmez.

Bu bir modeldir, ölçüm değil: `tur` soyut bir zaman adımıdır, gecikme `D` tur cinsinden bir
parametredir ve hiçbir yerde saat okunmaz. Bu yüzden çıktı her koşumda aynıdır.

```js
// pacelc/model.mjs — bolunme YOKKEN iki yazma politikasi. Tur soyut bir zaman adimidir;
// gecikme D tur cinsinden bir model parametresidir, olculmus bir sure degildir. Ayni takip
// numarasina gelen olaylar siralidir, bu yuzden ucusta tek yazma bulunur.
export function kosum({ tur: N, gecikme: D, aralik, politika }) {
  const yazma = new Map(); // yazmaNo -> { gelis, kabul, gorunur }
  const kuyruk = [];
  let ucus = null, ileti = 0, sira = 0;

  for (let t = 1; t <= N; t++) {
    if ((t - 1) % aralik === 0) {
      sira += 1;
      yazma.set(sira, { gelis: t, kabul: null, gorunur: null });
      kuyruk.push(sira);
    }
    if (politika === "onayli") {
      if (ucus !== null && ucus.biter === t) {
        const y = yazma.get(ucus.no);
        y.kabul = t;      // onay geldi: yazma ayni turda iki kopyada gorunur olur
        y.gorunur = t;
        ileti += 2;       // gidis + onay
        ucus = null;
      }
      if (ucus === null && kuyruk.length > 0) ucus = { no: kuyruk.shift(), biter: t + 2 * D };
    } else {
      while (kuyruk.length > 0) {
        const y = yazma.get(kuyruk.shift());
        y.kabul = t;      // yerel kopyaya yazildi, tasiyiciya hemen onay verildi
        y.gorunur = t + D; // komsuya D tur sonra ulasir
        ileti += 1;
      }
    }
  }

  const tumu = [...yazma.values()];
  const kabuller = tumu.filter((y) => y.kabul !== null);
  const gorunenler = kabuller.filter((y) => y.gorunur <= N);
  const enBuyuk = (a, f) => Math.max(0, ...a.map(f));
  const ort = (a, f) => (a.length === 0 ? 0 : a.reduce((t, y) => t + f(y), 0) / a.length);
  return {
    gelen: tumu.length, kabul: kabuller.length, ileti,
    beklemeOrt: ort(kabuller, (y) => y.kabul - y.gelis),
    iletiPerYazma: kabuller.length === 0 ? 0 : ileti / kabuller.length,
    eskilikMax: enBuyuk(gorunenler, (y) => y.gorunur - y.kabul),
    uctanUcaMax: enBuyuk(gorunenler, (y) => y.gorunur - y.gelis),
  };
}
```

Modelin ölçtüğü dört sayı ayrı ayrı tanımlanmalıdır. **Bekleme**, olayın geldiği tur ile
taşıyıcıya onay verildiği tur arasındaki farktır. **Eskilik penceresi**, bir yazmanın
onaylandığı tur ile ikinci kopyada görünür olduğu tur arasındaki farktır. **Uçtan uca**, olayın
geldiği tur ile ikinci kopyada görünür olduğu tur arasındaki farktır. **İleti**, kabul edilmiş
yazma başına harcanan ileti sayısıdır.

```js
// pacelc/olc.mjs — E dalindaki odunlesim: iki politika, iki varis araligi, uc gecikme degeri
import { kosum } from "./model.mjs";

const TUR = 24;
const s = (x, n) => String(x).padStart(n);
console.log(`bolunme yok. ${TUR} tur. varis araligi ve gecikme D varsayimdir; tur soyut bir adimdir.`);
console.log();
console.log("aralik | D | politika | kabul | bekleme ort | bekleyen | ileti/yazma | eskilik | uctan uca");
console.log("-------|---|----------|-------|-------------|----------|-------------|---------|----------");
for (const aralik of [1, 4]) {
  for (const D of [1, 2, 4]) {
    for (const politika of ["onayli", "yayilan"]) {
      const r = kosum({ tur: TUR, gecikme: D, aralik, politika });
      console.log(`${s(aralik, 6)} | ${s(D, 1)} | ${politika.padEnd(8)} | ` +
        `${s(`${r.kabul}/${r.gelen}`, 5)} | ${s(r.beklemeOrt.toFixed(1), 11)} | ` +
        `${s(r.gelen - r.kabul, 8)} | ${s(r.iletiPerYazma.toFixed(2), 11)} | ` +
        `${s(`${r.eskilikMax} tur`, 7)} | ${s(`${r.uctanUcaMax} tur`, 9)}`);
    }
  }
}
```

```sh
node pacelc/olc.mjs
```

```
bolunme yok. 24 tur. varis araligi ve gecikme D varsayimdir; tur soyut bir adimdir.

aralik | D | politika | kabul | bekleme ort | bekleyen | ileti/yazma | eskilik | uctan uca
-------|---|----------|-------|-------------|----------|-------------|---------|----------
     1 | 1 | onayli   | 11/24 |         7.0 |       13 |        2.00 |   0 tur |    12 tur
     1 | 1 | yayilan  | 24/24 |         0.0 |        0 |        1.00 |   1 tur |     1 tur
     1 | 2 | onayli   |  5/24 |        10.0 |       19 |        2.00 |   0 tur |    16 tur
     1 | 2 | yayilan  | 24/24 |         0.0 |        0 |        1.00 |   2 tur |     2 tur
     1 | 4 | onayli   |  2/24 |        11.5 |       22 |        2.00 |   0 tur |    15 tur
     1 | 4 | yayilan  | 24/24 |         0.0 |        0 |        1.00 |   4 tur |     4 tur
     4 | 1 | onayli   |   6/6 |         2.0 |        0 |        2.00 |   0 tur |     2 tur
     4 | 1 | yayilan  |   6/6 |         0.0 |        0 |        1.00 |   1 tur |     1 tur
     4 | 2 | onayli   |   5/6 |         4.0 |        1 |        2.00 |   0 tur |     4 tur
     4 | 2 | yayilan  |   6/6 |         0.0 |        0 |        1.00 |   2 tur |     2 tur
     4 | 4 | onayli   |   2/6 |        10.0 |        4 |        2.00 |   0 tur |    12 tur
     4 | 4 | yayilan  |   6/6 |         0.0 |        0 |        1.00 |   4 tur |     4 tur
```

#### Sayıların Okunması

En temiz iki sütun eskilik ve iletidir. `onayli` politikasının eskilik penceresi altı koşumun
altısında 0 tur; `yayilan` politikasının eskilik penceresi tam olarak `D` tur — 1, 2 ve 4.
Bu, ikinci dalın tanımını sayıya çeviriyor: eşzamansız yayma, tutarlılığı gecikme parametresi
kadar bir pencereyle takas eder. Karşılığında ileti sayısı yazma başına 2,00'dan 1,00'a iner.
Onay iletisi, tutarlılığın kesinti yokken de ödenen ücretidir.

Bekleme sütunu ücretin kime kesildiğini gösteriyor. `yayilan` politikasında bekleme her koşumda
0,0 tur: taşıyıcı onayını hemen alır. `onayli` politikasında bekleme, varış aralığı 4 olan
koşumlarda tam olarak $2D$ turdur — 2,0 ve 4,0. Yani seyrek varışta senkron onayın bedeli
öngörülebilir ve sabittir.

Varış aralığı 1 olan koşumlar bambaşka bir şey gösteriyor. Orada bekleme 7,0'a, 10,0'a ve 11,5'e
çıkıyor ve `bekleyen` sütunu 13, 19, 22 oluyor. Sebep şudur: aynı takip numarasına gelen olaylar
sıralı olmak zorundadır, bu yüzden uçuşta tek bir yazma bulunur ve politika her yazmayı $2D$
turda bir kabul edebilir. Varış aralığı $2D$'nin altına düştüğünde kuyruk büyür. Bu, Gecikme ve
Verim dersindeki bağımsızlığın aynısıdır: yazma başına gecikme $2D$'de sabit kalırken verim
düşer ve düşen verim beklemeyi büyütür. Kuyruğun ne yapılacağı — reddetmek, yavaşlatmak, geri
basınç uygulamak — Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunun konusudur ve burada
yeniden ele alınmaz.

`uctan uca` sütununda bir okuma tuzağı var. Varış aralığı 1 ve $D = 4$ satırında bu sayı 15,
oysa $D = 2$ satırında 16. Sayı küçüldüğü için durum iyileşmiş değildir: sütun yalnız kabul
edilmiş yazmalar üzerinden hesaplanıyor ve o satırda 24 olayın yalnız 2'si kabul edildi. Kuyrukta
kalan 22 olayın uçtan uca gecikmesi henüz tanımlı değildir. Doluluğa yaklaşan bir düzenekte
gecikme ortalaması yanıltıcı olur; `bekleyen` sütunu okunmadan gecikme sütunu okunmamalıdır.

Son olarak `onayli` politikasının uçtan uca sayısının 0 olmadığına dikkat edilmelidir. Senkron
onay, okuyucunun gerçeği daha çabuk görmesini sağlamaz; sistemin henüz doğrulayamadığı bir şeyi
söz vermemesini sağlar. Eskilik penceresi 0 çıkıyor çünkü ölçü, sistemin verdiği sözle okunan
değer arasındadır. Olay ile okunan değer arasındaki mesafe kapanmaz, yalnız görünmez olur.

#### İki Dalın Ayrı Sınıflandırılması

Bir sistem tek harfle değil, iki dal için ayrı ayrı adlandırılır. Önceki dersin okuma politikaları
ile bu dersin yazma politikaları dört bileşim üretir.

| Sınıf | Bölünmede | Bölünme dışında | Politika çifti |
|---|---|---|---|
| PC/EC | tutarlılık | tutarlılık | `reddet` + `onayli` |
| PA/EL | hizmet erişilebilirliği | gecikme | `yanit-ver` + `yayilan` |
| PC/EL | tutarlılık | gecikme | `reddet` + `yayilan` |
| PA/EC | hizmet erişilebilirliği | gecikme yerine tutarlılık | `yanit-ver` + `onayli` |

Üçüncü satır ilk bakışta tuhaf görünür ama tutarlı bir tasarımdır: bağ açıkken yazmalar
eşzamansız yayılır, bağ kesildiğinde okuma reddedilir. Sistem hızlıdır ve bölünmede yanlış
söylemek yerine susar; ödediği bedel, bağ açıkken de `D` turluk bir eskilik penceresidir.

Sınıflandırma yine sistem geneli için değil, akış başına yapılır. Gönderi takip servisinde takip
sorgusu PA/EL dalını, gün sonu ücretlendirmesi PC/EC dalını seçebilir; ikisi aynı kopyaların
üzerinde çalışır. Ücretlendirmenin bir gönderiyi eski durumuyla faturalaması, iki turluk bir
pencerede bile yanlış fatura üretir; takip sorgusunun iki tur eski bir durum göstermesi
katlanılır bir hatadır.

#### Özet

- PACELC iki dallı bir cümledir: bölünme (P) varsa hizmet erişilebilirliği (A) ile tutarlılık (C)
  arasında, başka durumda (E) gecikme (L) ile tutarlılık (C) arasında seçim yapılır.
- Modelde `onayli` politikasının eskilik penceresi bütün koşumlarda 0 tur, `yayilan`
  politikasının eskilik penceresi tam olarak gecikme parametresi kadar — 1, 2 ve 4 tur — çıktı.
- Tutarlılığın bölünme dışındaki ücreti ileti sütununda göründü: yazma başına 2,00 ileti karşısında
  1,00 ileti.
- Varış aralığı 4 iken `onayli` politikasının beklemesi $2D$ turda sabit kaldı (2,0 ve 4,0);
  varış aralığı 1'e indiğinde kuyruk büyüdü ve bekleme 7,0'dan 11,5'e çıktı, bekleyen olay 13'ten
  22'ye yükseldi.
- Senkron onay okuyucunun gerçeği daha çabuk görmesini sağlamaz; uçtan uca gecikme kalır, yalnız
  sistem doğrulayamadığı değeri söz olarak vermez.
- Sınıflandırma iki dal için ayrı ve akış başına yapılır: takip sorgusu PA/EL, ücretlendirme
  PC/EC dalında olabilir.

#### Sonraki Adım

Bu dersin ölçümünde eskilik penceresi tek bir sayıya indi: 0 ya da `D` tur. Bu, sorunun yalnız
kaba hâlidir. Bir okuyucunun `D` turluk bir pencerede ne göreceği, pencerenin genişliğinden çok
hangi güvencenin verildiğine bağlıdır. Aynı gönderiyi iki istemci aynı anda sorduğunda farklı
durum görebilir; bir istemci ilerleyen bir durum dizisi yerine geri giden bir dizi görebilir;
kendi yazdığı olayı sonraki sorgusunda bulamayabilir. Bunların hepsi aynı `D` penceresinin içinde
olur ve hiçbiri ötekinin yerine geçmez. Sonraki ders bu güvenceleri adlandırır: güçlü, zayıf ve
sonunda tutarlılık; aynı olay dizisi üç okuma politikasıyla okunur ve farklı değer görme sayısı,
yakınsama için gereken tur sayısı ile monotonik okuma ihlali sayılır.

### Tutarlılık Modelleri

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/tutarlilik-modelleri

Güçlü, zayıf ve sonunda tutarlılığın ayrılması: dağıtık tutarlılığın işlem yalıtımından farklı bir soru olduğunun söylenmesi, aynı olay dizisinin üç modelle okunup iki istemcinin farklı değer görme sayısının, yakınsama için gereken tur sayısının ve monotonik okuma ihlallerinin ölçülmesi, yapışkan yönlendirmenin monotonik okumayı düzeltirken istemciler arası farkı büyütmesinin gösterilmesi.

Önceki ders eskilik penceresini tek bir sayıya indirdi: 0 ya da `D` tur. Bu sayı bir pencerenin
genişliğidir, içinde ne olabileceğini söylemez. Aynı `D` turluk pencerede iki istemci aynı
gönderiyi sorup farklı durum görebilir; bir istemci ilerleyen bir dizi yerine geri giden bir dizi
görebilir; üçüncü bir istemci kendi yazdığı olayı sonraki sorgusunda bulamayabilir. Bunlar ayrı
olgulardır ve hiçbiri ötekinin yerine geçmez.

Pencerenin içini tanımlayan şeye **tutarlılık modeli** denir: sistemin okumalar hakkında ne söz
verdiği. Bu ders üç modeli adlandırır ve aynı olay dizisini üçüyle okuyup sözlerin farkını sayar.

#### Model, Yalıtım Düzeyi Değildir

Tutarlılık sözcüğü depoda iki ayrı yerde geçti. Veri Modelleme ve İlişkisel Kuram kursunda ACID
özelliklerinden biri, İleri SQL kursunda yalıtım düzeylerinin ölçütüydü. Buradaki soru başkadır
ve ikisi birbirinin yerine geçmez: **işlem yalıtımı** eşzamanlı işlemlerin birbirinin yarım
işini görüp görmediğini düzenler, **dağıtık tutarlılık** ise onaylanmış bir yazmanın kopyalar
arasında ne zaman görünür olduğunu düzenler. Bir sistem en katı yalıtım düzeyini uygularken
sonunda tutarlı olabilir; ikisi ayrı ayrı seçilir. Yalıtım düzeyleri bu derste yeniden
anlatılmaz.

Çoğaltmanın nasıl yürüdüğü de İlişkisel Veritabanı Yönetimi kursunda kuruldu. Burada ölçülen,
aynı çoğaltmanın üstüne konan sözün ne olduğudur.

#### Üç Model

**Güçlü tutarlılık**: her okuma, en son onaylanmış yazmayı görür. Sistem dışarıdan tek kopyalı
görünür. Bedeli, yerel kopyanın elindeki değerin en yeni olduğunu doğrulamasıdır.

**Sonunda tutarlılık** (eventual consistency): okuma en son yazmayı görmeyebilir, ancak yazma
durduğunda bütün kopyaların aynı değere **yakınsayacağı** güvence altındadır. Terim Veri
Modelleme ve İlişkisel Kuram kursunda tanıtıldı; buradaki ekleme, yakınsamanın kendiliğinden
olmadığıdır — kaybolan bir yayılımın yeniden gönderilmesini sağlayan bir onarım mekanizması
gerekir.

**Zayıf tutarlılık**: hiçbir söz verilmez. Okuma eski değer görebilir ve kopyalar hiç
yakınsamayabilir. Bu, sonunda tutarlılığın gevşek bir hâli değildir; yakınsama güvencesinin
yokluğudur ve aradaki fark ölçülebilir.

#### Üç Kopyalı Düzenek

Model üç bölgeli bir kopya kümesi kurar. Yazmalar `b34` bölgesine gelir ve `b35` ile `b06`
bölgelerine yayılır; yayılım gecikmeleri ve bir kayıp kuralı model parametreleridir. İki istemci
her turda aynı takip numarasını okur ve sırayla farklı bölgelere yönlenir.

```js
// tutarlilik/model.mjs — uc kopyali surec ici model. Tur soyut bir adimdir; gecikme, kayip
// kurali ve onarim araligi model parametreleridir, olculmus sureler degildir.
const GECIKME = { b35: 1, b06: 3 };          // yayilimin hedefe varmasi icin gecen tur
const KAYIP = (yazma) => yazma % 5 === 0;    // b06'ya giden yayilim bu yazmalarda kaybolur
const ONARIM = 2;                            // onarimli modellerde yeniden gonderme araligi
const YOL = { A: ["b34", "b35", "b06"], B: ["b06", "b35", "b34"] };
const SABIT = { A: ["b35"], B: ["b06"] };    // yapiskan yonlendirme: istemci tek kopyada kalir

export function kosum({ tur: N, yazmaSonu: W, model, sabit = false }) {
  const surum = { b34: 0, b35: 0, b06: 0 };
  const gorulen = { A: 0, B: 0 };
  const iz = { A: [], B: [] };
  let ucus = [], ileti = 0, farkli = 0, ihlal = 0, yakinsama = null;

  for (let tur = 1; tur <= N; tur++) {
    if (tur <= W) {
      surum.b34 = tur; // tasiyici olayi b34'e yazilir, tasiyiciya hemen onay verilir
      for (const h of ["b35", "b06"]) {
        ileti += 1;
        ucus.push({ hedef: h, yazma: tur, varir: tur + GECIKME[h], kayip: h === "b06" && KAYIP(tur) });
      }
    }
    const varan = ucus.filter((m) => m.varir === tur);
    ucus = ucus.filter((m) => m.varir !== tur);
    for (const m of varan) {
      if (m.kayip === false) { surum[m.hedef] = Math.max(surum[m.hedef], m.yazma); continue; }
      if (model === "zayif") continue; // kayip onarilmaz: yakinsama guvencesi yoktur
      ileti += 1;
      ucus.push({ ...m, varir: tur + ONARIM, kayip: false });
    }

    const oku = (istemci) => {
      const yol = sabit ? SABIT[istemci] : YOL[istemci];
      const bolge = yol[(tur - 1) % yol.length];
      if (model !== "guclu") return surum[bolge];
      if (bolge !== "b34") ileti += 2; // yerel kopya, en son yazmayi b34'e dogrulatir
      return surum.b34;
    };
    const deger = { A: oku("A"), B: oku("B") };
    if (deger.A !== deger.B) farkli += 1;
    for (const i of ["A", "B"]) {
      if (deger[i] < gorulen[i]) ihlal += 1;
      gorulen[i] = Math.max(gorulen[i], deger[i]);
      iz[i].push(deger[i]);
    }
    if (tur > W && yakinsama === null && surum.b34 === surum.b35 && surum.b35 === surum.b06) {
      yakinsama = tur - W;
    }
  }
  return { farkli, ihlal, ileti, yakinsama, surum, iz };
}
```

Üç modelin kodda ayrıldığı yer iki satırdır: kayıp bir yayılımın yeniden gönderilip
gönderilmediği ve okumanın `b34`'e doğrulatılıp doğrulatılmadığı. **Monotonik okuma ihlali**,
bir istemcinin daha önce gördüğü bir sürümden eski bir sürüm görmesidir.

```js
// tutarlilik/olc.mjs — ayni olay dizisi uc modelle okunur: fark, ihlal, yakinsama, ileti
import { kosum } from "./model.mjs";

const TUR = 20, YAZMA_SONU = 10;
const s = (x, n) => String(x).padStart(n);
console.log(`${TUR} tur, ${YAZMA_SONU}. tura kadar her turda bir yazma; sonra yazma yok.`);
console.log("iki istemci her turda ayni takip numarasini okur, farkli kopyalara yonlenir.");
console.log();
console.log("model         | farkli deger | monotonik ihlal | yakinsama   | ileti | son surum b34/b35/b06");
console.log("--------------|--------------|-----------------|-------------|-------|----------------------");
const DUZEN = [["guclu", false], ["sonunda", false], ["sonunda", true], ["zayif", false]];
const kayit = {};
for (const [model, sabit] of DUZEN) {
  const r = kosum({ tur: TUR, yazmaSonu: YAZMA_SONU, model, sabit });
  const ad = sabit ? `${model}+sabit` : model;
  kayit[ad] = r;
  console.log(`${ad.padEnd(13)} | ${s(`${r.farkli}/${TUR}`, 12)} | ${s(r.ihlal, 15)} | ` +
    `${s(r.yakinsama === null ? "yakinsamadi" : `${r.yakinsama} tur`, 11)} | ${s(r.ileti, 5)} | ` +
    `${r.surum.b34}/${r.surum.b35}/${r.surum.b06}`);
}
console.log();
for (const ad of Object.keys(kayit)) {
  console.log(`${ad.padEnd(13)} A: ${kayit[ad].iz.A.join(" ")}`);
  console.log(`${ad.padEnd(13)} B: ${kayit[ad].iz.B.join(" ")}`);
}
```

```sh
node tutarlilik/olc.mjs
```

```
20 tur, 10. tura kadar her turda bir yazma; sonra yazma yok.
iki istemci her turda ayni takip numarasini okur, farkli kopyalara yonlenir.

model         | farkli deger | monotonik ihlal | yakinsama   | ileti | son surum b34/b35/b06
--------------|--------------|-----------------|-------------|-------|----------------------
guclu         |         0/20 |               0 |       5 tur |    76 | 10/10/10
sonunda       |         9/20 |               8 |       5 tur |    22 | 10/10/10
sonunda+sabit |        13/20 |               0 |       5 tur |    22 | 10/10/10
zayif         |        13/20 |              12 | yakinsamadi |    20 | 10/10/9

guclu         A: 1 2 3 4 5 6 7 8 9 10 10 10 10 10 10 10 10 10 10 10
guclu         B: 1 2 3 4 5 6 7 8 9 10 10 10 10 10 10 10 10 10 10 10
sonunda       A: 1 1 0 4 4 3 7 7 6 10 10 9 10 10 10 10 10 10 10 10
sonunda       B: 0 1 3 1 4 6 4 7 9 7 10 10 9 10 10 10 10 10 10 10
sonunda+sabit A: 0 1 2 3 4 5 6 7 8 9 10 10 10 10 10 10 10 10 10 10
sonunda+sabit B: 0 0 0 1 2 3 4 4 6 7 8 9 9 9 10 10 10 10 10 10
zayif         A: 1 1 0 4 4 3 7 7 6 10 10 9 10 10 9 10 10 9 10 10
zayif         B: 0 1 3 1 4 6 4 7 9 7 10 10 9 10 10 9 10 10 9 10
```

#### Sayıların Okunması

`guclu` satırı sözün tam karşılığını veriyor: iki istemci hiçbir turda farklı değer görmedi
(0/20), monotonik ihlal 0 ve iki izin de tam olarak yazma dizisinin kendisi. Bedel ileti
sütununda: 76 ileti, en ucuz satırın yaklaşık dört katı. Bu ileti sayısının kaynağı okumadır,
yazma değil — yerel kopyaya düşen her okuma `b34`'e bir gidiş dönüş ekler. Bir okuma yoğun
akışta bedel okuma sayısıyla büyür.

`sonunda` satırı sözün sınırını gösteriyor. Yakınsama 5 tur: yazma bittikten beş tur sonra üç
kopya da 10 sürümünde birleşti. Yakınsama gerçekleşti ama pencere içinde 9 turda iki istemci
farklı değer gördü ve 8 monotonik ihlal oluştu. İzler bunu doğrudan gösteriyor: A istemcisi
`1 1 0` ile başlıyor — üçüncü turda gönderinin durumunu hiç görmemiş gibi bir yanıt alıyor,
çünkü o tur `b06` bölgesine yönlendi. Takip sorgusu için bu, ekranda görünen durumun geriye
gitmesi demektir.

`zayif` satırındaki tek fark bir mekanizmanın yokluğudur ve sonucu son sütunda görünür: kopyalar
`10/10/9` durumunda kaldı, yakınsama hiç olmadı. Onuncu yazma `b06`'ya giderken kaybolduğu ve
yeniden gönderilmediği için o bölge gönderiyi sonsuza kadar bir aşama geride gösterir. Yakınsama
güvencesinin bedeli ölçümde iki iletidir (20'ye karşı 22); sağladığı şey, kalıcı bir sapmanın
olmamasıdır. Sonunda tutarlılığı "hiçbir garanti vermeyen model" sanmak bu iki iletiyi görmemek
anlamına gelir.

#### Oturum Güvenceleri

Monotonik ihlal, tutarlılık modelinden ayrı bir eksende düzeltilebilir. `sonunda+sabit` satırında
model aynı kaldı; değişen tek şey istemcinin her turda aynı kopyaya yönlendirilmesidir —
Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunda tanıtılan **yapışkan yönlendirme**
kalıbının okuma yoluna uygulanmış hâli. İhlal 8'den 0'a
indi, çünkü bir kopyanın sürüm numarası hiç geri gitmez. Bu tür sözlere **oturum güvencesi**
denir; en bilinen ikisi monotonik okuma (bir istemci gördüğü değerden eskisini görmez) ve kendi
yazdığını okumadır (bir istemci kendi yazmasını sonraki okumasında görür).

Aynı satır ikinci ve daha önemli şeyi de söylüyor: farklı değer görme sayısı 9'dan **13'e
çıktı**. Yapışkan yönlendirme istemciyi tek bir kopyaya bağlayınca A istemcisi hep `b35`'i, B istemcisi hep
`b06`'yı okur ve iki bölgenin gecikmesi farklı olduğu için ikisi neredeyse her turda ayrışır.
Oturum güvencesi bir istemcinin kendi gördüğü diziyi düzeltir; istemciler arasındaki farkı
düzeltmez, hatta büyütebilir.

Bu, gönderi takip servisinde iki ayrı gereksinime karşılık gelir. Bir kullanıcının aynı
gönderiyi arka arkaya sorgulaması durumun geri gitmemesini gerektirir; yapışkan yönlendirme bunu
sağlar. Gün sonu ücretlendirmesinin bütün gönderiler için aynı anı esas alması ise oturum
güvencesiyle sağlanamaz — orada güçlü tutarlılık gerekir ve bedeli okuma başına bir gidiş
dönüştür. Kursun sonraki dersinde bu iki gereksinim ayrı kalıplara bağlanacaktır.

#### Özet

- Dağıtık tutarlılık modeli, işlem yalıtımından ayrı bir sorudur: biri eşzamanlı işlemlerin
  birbirini görmesini, öteki onaylanmış bir yazmanın kopyalarda ne zaman göründüğünü düzenler.
- Aynı yirmi turluk olay dizisinde `guclu` model 0/20 farklı değer ve 0 ihlal üretti, bedeli 76
  ileti oldu; `sonunda` model 22 iletiyle 9/20 fark ve 8 ihlal üretti.
- Sonunda tutarlılığın güvencesi yakınsamadır ve kendiliğinden gelmez: onarım mekanizması
  kaldırıldığında (`zayif`) kopyalar `10/10/9` durumunda kaldı ve hiç yakınsamadı; onarımın
  bedeli iki iletiydi.
- Yakınsama 5 tur sürdü; bu süre boyunca söz yalnız "sonunda aynı olacak"tır, okumaların ne
  göreceği hakkında bir şey söylemez.
- Yapışkan yönlendirme monotonik ihlali 8'den 0'a indirdi ama iki istemcinin farklı değer görme
  sayısını 9'dan 13'e çıkardı; oturum güvencesi istemciler arası farkı düzeltmez.

#### Sonraki Adım

Buraya kadar üç dersin hepsi aynı örtük varsayımı taşıdı: kopyaların hepsi ayakta ve yalnız
aralarındaki bağ ya da gecikme sorun çıkarıyor. Bir kopya tamamen düştüğünde soru değişir, çünkü
artık yerine geçecek bir kopyanın bulunması, isteklerin oraya yönlendirilmesi ve bu geçiş
sırasında düşen isteklerin hesaplanması gerekir. Geçişin nasıl düzenlendiği bir kalıp seçimidir:
kopyaların biri yazma alırken ötekinin beklemesi ya da hepsinin aynı anda yazma alması. Sonraki
ders bu iki kalıbı ölçer: etkin–pasif düzende devralma turu ile o sırada düşen istek sayısı,
etkin–etkin düzende çakışan yazma sayısı ve çözüm kuralının ürettiği kayıp yazma sayısı.

### Erişilebilirlik Kalıpları

Source: https://academia.sh/tr/kurslar/sistem-tasarimina-giris/erisilebilirlik-kaliplari

Etkin–etkin ve etkin–pasif devralmanın kalıp olarak karşılaştırılması: aynı arıza senaryosunda devralma turunun ve o sırada düşen istek sayısının ölçülmesi, etkin–etkin düzende çakışan yazma ile son yazan kazanır kuralının ürettiği kayıp yazmanın sayılması, tur sayılarının kursun varsayım tablosuyla isteğe çevrilmesi ve anahtar sahipliğinin çakışmayı nasıl kaldırdığının gösterilmesi.

Buraya kadarki üç ders aynı örtük varsayımı taşıdı: kopyaların hepsi ayaktadır ve sorun yalnız
aralarındaki bağdan ya da gecikmeden gelir. Bir kopya tamamen düştüğünde soru değişir. Artık
yerine geçecek bir kopyanın bulunması, isteklerin oraya yönlendirilmesi ve bu geçiş sırasında
düşen isteklerin hesaplanması gerekir.

Geçişin nasıl düzenlendiği bir **kalıp** seçimidir ve bu ders iki kalıbı aynı arıza senaryosunda
ölçer. Kalıpların altındaki mekanizmalar başka yerde kuruldu: çoğunluk kuralı, çitleme ve sağlık
denetimi sıklığının yanlış devralmayla ödünleşimi İlişkisel Veritabanı Yönetimi kursunun
konusudur; bir bileşen düştüğünde isteğin geri kalanının yanıtlanabilmesi, yani arıza yalıtımı,
Mimari Biçemler kursunda ölçüldü. Burada ölçülen, kalıbın istek ve yazma cinsinden ne kadar
tuttuğudur.

#### İki Kalıp

**Etkin–pasif**: yazmayı yalnız bir kopya kabul eder, öteki hazır bekler. Pasif kopya yazma
almadığı için çakışma olanaksızdır. Etkin kopya düştüğünde yazma kabul eden hiçbir kopya kalmaz;
devralma tamamlanana kadar yazmalar düşer.

**Etkin–etkin**: kopyaların hepsi yazma kabul eder. Bir kopya düştüğünde ötekiler çalışmaya
devam eder, devralma penceresi yoktur. Karşılığında iki kopya aynı anahtara birbirinden habersiz
yazabilir; bu duruma **çakışan yazma** denir ve bir çözüm kuralı gerektirir. Bu dersteki kural
**son yazan kazanır**: aynı pencerede yazılan iki değerden biri seçilir, öteki hiçbir yerde
görünmez.

Gönderi takip servisinde çakışma uydurma bir durum değildir: aynı gönderi bir aktarma noktasında
iki bölgenin tarayıcısından geçebilir ve iki bölge aynı turda yazabilir.

#### Düzenek

Model iki bölgeli bir kopya kümesi kurar. Tarama olayları belirli bir bölgede oluşur; `b34`
bölgesi 9. turdan 12. tura kadar erişilemez. Gecikme, algılama ve terfi tur cinsinden model
parametreleridir.

```js
// kalip/model.mjs — iki bolgeli devralma modeli. Tur soyut bir adimdir; gecikme, algilama ve
// terfi tur cinsinden model parametreleridir, olculmus sureler degildir.
export const OLAY = [            // [tur, tarama bolgesi, durum]
  [1, "b34", "kabul"], [2, "b34", "cikis"],
  [3, "b34", "aktarma-34"], [3, "b35", "hat-35"],
  [4, "b34", "aktarma-41"],
  [5, "b34", "dagitim"], [5, "b35", "dagitim-35"],
  [6, "b35", "teslim-denemesi"],
  [7, "b34", "adres-dogrulama"], [7, "b35", "yeniden-dagitim"],
  [8, "b34", "hat-06"], [9, "b34", "aktarma-06"], [10, "b35", "teslim"],
  [11, "b34", "imza"], [12, "b35", "kapali"], [13, "b34", "fatura-hazir"],
  [14, "b34", "fatura-kesildi"], [14, "b35", "fatura-onay"],
  [15, "b35", "arsiv"], [16, "b34", "arsiv-onay"],
];
export const ARIZA = { bolge: "b34", baslangic: 9, bitis: 12 };
const GECIKME = 1, ALGILAMA = 2, TERFI = 1;
const oteki = (b) => (b === "b34" ? "b35" : "b34");
const canli = (bolge, tur) =>
  bolge !== ARIZA.bolge || tur < ARIZA.baslangic || tur > ARIZA.bitis;

export function kosum({ kalip, tur: N }) {
  const s = { kabul: 0, dusen: 0, cakisan: 0, kayipCakisma: 0, kayipYayilmamis: 0, ileti: 0 };
  let ucus = [], etkin = "b34", devralmaBaslangici = null, devralmaTuru = 0;

  for (let tur = 1; tur <= N; tur++) {
    if (tur === ARIZA.baslangic) { // dusen bolgeden cikmis, henuz varmamis yayilimlar kaybolur
      s.kayipYayilmamis += ucus.filter((m) => m.kaynak === ARIZA.bolge).length;
      ucus = ucus.filter((m) => m.kaynak !== ARIZA.bolge);
    }
    ucus = ucus.filter((m) => m.varir !== tur); // varan yayilimlar hedefte gorunur oldu

    if (kalip === "etkin-pasif" && canli(etkin, tur) === false) {
      if (devralmaBaslangici === null) devralmaBaslangici = tur;
      if (tur === devralmaBaslangici + ALGILAMA + TERFI) {
        etkin = oteki(etkin);
        devralmaTuru = ALGILAMA + TERFI;
      }
    }

    const yazan = new Set();
    for (const [, tarama] of OLAY.filter(([t]) => t === tur)) {
      const hedef = kalip === "etkin-pasif" ? etkin
        : (canli(tarama, tur) ? tarama : oteki(tarama));
      if (canli(hedef, tur) === false) { s.dusen += 1; continue; } // kabul edecek kopya yok
      if (hedef !== tarama) s.ileti += 1;   // tarama uzaktaki kopyaya iletildi
      s.kabul += 1;
      s.ileti += 1;                         // kabul eden kopya komsuya yayar
      yazan.add(hedef);
      ucus.push({ kaynak: hedef, hedef: oteki(hedef), varir: tur + GECIKME });
    }
    if (yazan.size === 2) {  // iki bolge ayni turda, birbirini gormeden yazdi
      s.cakisan += 1;
      s.kayipCakisma += 1;   // son yazan kazanir: yenilen yazma hicbir yerde gorunmez
    }
  }
  return { ...s, devralmaTuru, etkin };
}
```

```js
// kalip/olc.mjs — ayni ariza senaryosunda iki kalip: devralma, dusen istek, cakisma, kayip
import { kosum, OLAY, ARIZA } from "./model.mjs";

const TUR = 16;
const s = (x, n) => String(x).padStart(n);
console.log(`${TUR} tur, ${OLAY.length} tarama olayi. ${ARIZA.bolge} bolgesi ` +
  `${ARIZA.baslangic}-${ARIZA.bitis}. turlarda erisilemez.`);
console.log();
console.log("kalip        | kabul | dusen | devralma | cakisan | kayip(cakisma) | kayip(yayilmamis) | ileti");
console.log("-------------|-------|-------|----------|---------|----------------|-------------------|------");
const kayit = {};
for (const kalip of ["etkin-pasif", "etkin-etkin"]) {
  const r = kosum({ kalip, tur: TUR });
  kayit[kalip] = r;
  console.log(`${kalip.padEnd(12)} | ${s(`${r.kabul}/${OLAY.length}`, 5)} | ${s(r.dusen, 5)} | ` +
    `${s(`${r.devralmaTuru} tur`, 8)} | ${s(r.cakisan, 7)} | ${s(r.kayipCakisma, 14)} | ` +
    `${s(r.kayipYayilmamis, 17)} | ${s(r.ileti, 5)}`);
}
console.log();
console.log(`etkin-pasif devralma sonrasi etkin kopya = ${kayit["etkin-pasif"].etkin}`);
console.log(`etkin-etkin: ariza turlarinda dusen istek = ${kayit["etkin-etkin"].dusen}`);
```

```sh
node kalip/olc.mjs
```

```
16 tur, 20 tarama olayi. b34 bolgesi 9-12. turlarda erisilemez.

kalip        | kabul | dusen | devralma | cakisan | kayip(cakisma) | kayip(yayilmamis) | ileti
-------------|-------|-------|----------|---------|----------------|-------------------|------
etkin-pasif  | 17/20 |     3 |    3 tur |       0 |              0 |                 1 |    24
etkin-etkin  | 20/20 |     0 |    0 tur |       4 |              4 |                 1 |    22

etkin-pasif devralma sonrasi etkin kopya = b35
etkin-etkin: ariza turlarinda dusen istek = 0
```

#### Sayıların Okunması

Kabul sütunu iki kalıbın ilan ettiği farkı doğruluyor. Etkin–pasif düzen 20 tarama olayının
17'sini kabul etti; devralma 3 tur sürdü ve o üç turda gelen 3 olay düştü. Etkin–etkin düzen
20/20 kabul etti ve arıza turlarında hiçbir istek düşmedi, çünkü `b34` bölgesinin tarayıcıları
`b35`'e yönlendi.

Düşen üç olayın hangileri olduğu önemlidir: 9. turda `aktarma-06`, 10. turda `teslim`, 11. turda
`imza`. Bunların ikisi `b35` bölgesinde oluşan taramalardı ve o bölge ayaktaydı — yine de
düştüler. Sebep, pasif kopyanın tanımıdır: yazma kabul etmez. Etkin–pasif düzende bir bölgenin
ayakta olması, yazmasının kabul edileceği anlamına gelmez.

Çakışma sütunu bedelin nereye taşındığını gösteriyor. Etkin–etkin düzende 3, 5, 7 ve 14.
turlarda iki bölge aynı anahtara birbirini görmeden yazdı: 4 çakışma. Son yazan kazanır kuralı
her çakışmada bir yazmayı sildi, yani 4 kayıp yazma. Bu sayı etkin–pasif düzende 0'dır ve
karşılığında orada 3 düşen istek vardır. İki kalıp aynı arızayı ayrı yerde ödüyor: biri kesinti
olarak, öteki kaybolan veri olarak.

Son iki sütun iki kalıbın **ortak** maliyetini gösteriyor. `kayip(yayilmamis)` her iki kalıpta da
1: `b34` bölgesi düştüğünde ondan çıkmış ama henüz karşıya varmamış bir yayılım vardı ve o
kayboldu. Bu, kalıptan değil eşzamansız yayılımdan gelir; senkron onay seçilse bu sayı 0 olurdu
ve bedeli PACELC dersinde ölçülen bekleme olurdu. İleti sayıları da yakındır (24'e karşı 22);
etkin–etkin düzendeki fazlalık, tarama uzaktaki kopyaya iletildiğinde eklenen atlamalardan
gelir. Yani kalıp seçimi bir ileti tasarrufu kararı değildir.

#### Turların İsteğe Çevrilmesi

Tur soyut bir adımdır. Sayıları isteğe çevirmek için iki varsayım gerekir: bir turun kaç saniyeye
karşılık geldiği ve yılda kaç devralma olduğu. Hacim sayıları Kabaca Büyüklük Hesabı dersinin
varsayım tablosundan gelir ve burada yeniden hesaplanır.

```js
// kalip/butce.mjs — modelin tur sayilarini kursun varsayim tablosuyla istege cevirir
const V = { gunlukKullanici: 2_000_000, kullaniciBasinaSorgu: 6, gunlukGonderi: 400_000,
  gonderiBasinaOlay: 7, tepeCarpani: 3 };            // Kabaca Buyukluk Hesabi dersi: V1-V4, V8
const YIL = 365 * 24 * 3600, GUN = 86_400;
const TUR_SANIYE = 1;                                 // varsayim: bir tur bir saniyeye karsilik gelir
const DEVRALMA_YIL = 6;                               // varsayim: yilda kac devralma
const CIFT_TARAMA = 0.05;                             // varsayim: iki bolgede birden uretilen olay orani

const tepeYazma = (V.gunlukGonderi * V.gonderiBasinaOlay / GUN) * V.tepeCarpani;
const tepeUc = tepeYazma + (V.gunlukKullanici * V.kullaniciBasinaSorgu / GUN) * V.tepeCarpani;
console.log(`tepe yazma = ${tepeYazma.toFixed(2)} istek/s, tepe uc = ${tepeUc.toFixed(2)} istek/s`);
console.log();
for (const devralmaTuru of [3, 5]) {
  const sn = devralmaTuru * TUR_SANIYE;
  const yillik = sn * DEVRALMA_YIL;
  console.log(`etkin-pasif, devralma ${devralmaTuru} tur (${sn} sn):`);
  console.log(`  pencerede dusen yazma = ${(sn * tepeYazma).toFixed(2)}, dusen uc istegi = ${(sn * tepeUc).toFixed(2)}`);
  console.log(`  yilda ${DEVRALMA_YIL} devralma -> ${yillik} sn, hizmet erisilebilirligi = ` +
    `%${(100 * (1 - yillik / YIL)).toFixed(5)}`);
}
console.log();
for (const oran of [CIFT_TARAMA, CIFT_TARAMA * 2]) {
  const cakisan = V.gunlukGonderi * V.gonderiBasinaOlay * oran;
  console.log(`etkin-etkin, cift tarama orani ${oran.toFixed(2)}: cakisan yazma = ${cakisan}/gun, ` +
    `son yazan kazanir -> kayip yazma = ${cakisan}/gun`);
}
```

```
tepe yazma = 97.22 istek/s, tepe uc = 513.89 istek/s

etkin-pasif, devralma 3 tur (3 sn):
  pencerede dusen yazma = 291.67, dusen uc istegi = 1541.67
  yilda 6 devralma -> 18 sn, hizmet erisilebilirligi = %99.99994
etkin-pasif, devralma 5 tur (5 sn):
  pencerede dusen yazma = 486.11, dusen uc istegi = 2569.44
  yilda 6 devralma -> 30 sn, hizmet erisilebilirligi = %99.99990

etkin-etkin, cift tarama orani 0.05: cakisan yazma = 140000/gun, son yazan kazanir -> kayip yazma = 140000/gun
etkin-etkin, cift tarama orani 0.10: cakisan yazma = 280000/gun, son yazan kazanir -> kayip yazma = 280000/gun
```

Etkin–pasif kalıbın devralma penceresi bütçeden çok az yer tutuyor: yılda 6 devralma 18 saniye
eder ve hizmet erişilebilirliğini yüzde 99,99994'te bırakır. Devralma 5 tura çıksa 30 saniye ve
yüzde 99,99990 olur. Bütçe açısından bu kalıp neredeyse bedavadır. Bedel yıllık yüzdede değil,
tek bir pencerede toplanır: her devralmada 291,67 durum olayı ve uçta 1.541,67 istek düşer, hepsi
üç saniyenin içinde. Kesinti bütçesi ortalamayı ölçer, tek pencerede yoğunlaşan bir kaybı
ölçmez.

Etkin–etkin kalıbın sayısı bambaşka bir mertebede. Çift tarama oranı yüzde 5 varsayıldığında
günde 140.000 çakışan yazma çıkıyor ve son yazan kazanır kuralı bunların hepsini kayıp yazmaya
çeviriyor; oran iki katına çıkınca 280.000 oluyor. Bu kayıp bir kesinti değildir, bütçede
görünmez ve kendini bir hata olarak duyurmaz — yalnız bazı gönderilerin durum geçmişinde bir
adım eksik kalır.

#### Kalıbın Seçimi ve Anahtar Sahipliği

Ölçülen sayılar seçimi akış başına belirliyor. Taşıyıcı durum olayları için etkin–pasif kalıp
yerindedir: üç saniyelik pencerede düşen 291,67 olay taşıyıcı tarafından yeniden gönderilebilir,
oysa kaybolan bir durum güncellemesi geri getirilemez. Gün sonu ücretlendirmesi için de aynısı
geçerlidir; ücretlendirme eksik durum geçmişiyle yanlış fatura üretir. Takip sorgusu ise okumadır
ve iki kalıpta da pasif kopyadan karşılanabilir — okuma için devralma penceresi diye bir şey
yoktur.

Etkin–etkin kalıbın çakışma maliyeti kalıbın zorunlu parçası değildir. Çakışma, aynı anahtara iki
bölgenin yazmasından doğar; yazma anahtara göre tek bir bölgeye yönlendirilirse — bu kalıba
**anahtar sahipliği** eklenmesi denir — çakışan yazma 0'a iner ve her bölge kendi anahtar
kümesinin etkin kopyası olur. Bu düzenlemede sistem bir bütün olarak etkin–etkindir, tek bir
anahtar için etkin–pasiftir. Ölçümdeki 4 çakışma, sahiplik kuralı olmadığında ortaya çıkan
sayıdır; kalıbın kaçınılmaz bedeli değil, eksik bir kararın sonucudur.

#### Özet

- Etkin–pasif kalıpta yazmayı tek kopya kabul eder: çakışma 0, ama etkin kopya düştüğünde
  devralma tamamlanana kadar yazma kabul edilmez.
- Aynı arıza senaryosunda etkin–pasif düzen 17/20 olay kabul etti, devralma 3 tur sürdü ve 3
  olay düştü; düşenlerin ikisi ayakta olan bölgede oluşmuştu, çünkü pasif kopya yazma almaz.
- Etkin–etkin düzen 20/20 kabul etti ve arıza turlarında hiç istek düşmedi; karşılığında 4
  çakışan yazma oluştu ve son yazan kazanır kuralı 4 yazmayı sildi.
- Eşzamansız yayılımın kaybı iki kalıpta da aynı çıktı (1 yayılmamış yazma); bu maliyet kalıptan
  değil yazma politikasından gelir.
- Varsayımlarla çevrildiğinde etkin–pasif devralma yılda 18 saniye tutuyor (yüzde 99,99994) ama
  her pencerede 291,67 durum olayı ve 1.541,67 uç isteği düşürüyor; kesinti bütçesi tek pencerede
  yoğunlaşan kaybı ölçmez.
- Çakışma kalıbın zorunlu bedeli değildir: anahtar sahipliği eklendiğinde her anahtarın tek bir
  etkin kopyası olur ve çakışan yazma 0'a iner.

#### Kurs Kapanışı

Kurs bir tasarım problemini iki adımda ele aldı. **Yaklaşım** konusu tek satırlık bir isteği
gereksinime ayırdı: bileşen sınırları, sözleşmeler ve nitelik eşikleri ayrıldı, on bir sorunun
beşinin yanıtlı olduğu sayıldı, kapsam daraltmasıyla bileşen 12'den 5'e indirildi ve varsayım
tablosundan uçta tepe 513,89 istek/s ile günde 976 MB veri artışı hesaplandı. Konunun son dersi
tasarımı anlatmanın biçimini verdi: beş alanlı karar kaydı ve kenarları hesaptan etiketlenen bir
diyagram — aynı akış sol kenarda 416,67 istek/s, sağ kenarda 41,67 istek/s taşıyor.

**Temel Nitelikler** konusu bu tahminlerin üzerine niteliklerin her birini sayıya döktü: gecikme
ile verimin bağımsızlığı, eşzamanlılık artarken verimin doğrusala yakın büyümesi ve ortanca
gecikmenin neredeyse sabit kalmasıyla ölçüldü; başarım ile ölçeklenebilirliğin farkı ve yatay ile dikey ölçeklemenin
sınırları ayrıldı; hizmet erişilebilirliği bir bütçeye çevrildi; bütçenin neden harcandığı CAP
teoremiyle adlandırıldı; bölünme dışındaki gecikme ödünleşimi PACELC ile ayrıldı; tutarlılık
modelleri yakınsama ve monotonik okuma cinsinden ayrıldı; devralma iki kalıp olarak ölçüldü.

Kursun asıl kuralı bu sayıların yanında durdu. Her sayının bir **sınıfı** yazıldı: **varsayım**
seçilen bir girdidir ve duyarlılığı gösterilir — günlük etkin kullanıcı 2.000.000 böyle bir
sayıdır ve iki katına çıktığında uçtaki tepe 1,81 katına çıkar. **Hesap** varsayımlardan
aritmetikle çıkar ve `node` ile üretilir — tepe okuma 416,67 istek/s, saklanan veri 712,48 GB,
bu dersteki 1.541,67 düşen istek. **Ölçüm** bir düzenekten çıkar ve ortama bağlılığı işaretlenir
— eşzamanlılık düzeneğinden çıkan verim üst sınırı ile son üç dersin süreç içi model koşumları:
12 turluk bölünmede 6 reddedilen istek, üç kopyalı modelde 8 monotonik okuma ihlali ve bu
derste 4 çakışan yazma. Sınıfsız bir sayı karar taşımaz; kursun ilk dersinde dört karardan biri
bu yüzden denetlenemez sayılmıştı.

Kursun bıraktığı soru bir katman aşağıdadır. Bütün nitelikler tanımlandı, eşikler kondu ve
kalıplar seçildi; ama istek daha sisteme **girmedi**. Takip sorgusu bir alan adının çözülmesiyle
başlar, bir kenar önbelleğinden geçebilir, bir yük dengeleyiciye düşer ve bir ağ geçidinden
uygulamaya ulaşır. Bu yolun hiçbir parçası bu kursta tasarlanmadı — hesapta önbellek yalnız bir
çarpandı, yönlendirme ise modelde tek satırlık bir seçimdi. Sonraki kurs **Trafik Katmanı** o
yolu ele alır: isteğin uygulamaya varmadan önce geçtiği her durak, orada verilen kararlar ve o
kararların bu kursta hesaplanan sayıları nasıl değiştirdiği.

