Ders 02 / 10
Nitelikler Arası Gerilim
Bir niteliği yükselten kararın ötekilerde ölçülen düşüşü: on iki karardan gerilim matrisinin kurulması, çelişen çiftlerin ve en çok bastırılan niteliğin sayılması, hiçbir kararın iyileştirmediği niteliğin bulunması ve gerileme denetiminin bilinen ihlal kümesinde yakaladığı, kaçırdığı, boşa öttüğü durumların ölçülmesi.
İçindekiler
Önceki ders ağacı kurdu ve her yaprağı kendi eşiğine bağladı. O tabloda nitelikler birbirinden bağımsız durur: her yaprağın ayrı eşiği, ayrı gözlem alanı, ayrı denetimi vardır. Ama bir mimari karar tek bir yaprağa dokunmaz. Arama gecikmesini düşüren önbellek katmanı, aynı anda değişimde dokunulan dosya sayısını ve ortama özgü çağrı sayısını yükseltir. Yaprak başına denetim bunu göremez, çünkü her denetim kendi yaprağına bakar.
Bir niteliğin diğerini bastırması yeni bir gözlem değil; erişilebilirlik ile tutarlılık arasındaki gerilim Sistem Tasarımına Giriş kursunda, temel nitelikler konusunda ölçüldü ve burada tekrarlanmaz. Buradaki soru daha genel: bir karar listesi varken hangi nitelik çiftlerinin çeliştiği ve hangi niteliğin sistemli olarak bastırıldığı sayılabilir mi. Kursun sorusu da sürer: bu gerilim koşturulabilir bir denetime çevrilebiliyor mu.
Gerilim Matrisi
Aşağıdaki blok, kurgusal bölgesel kütüphane ağının on dört ölçülen yaprağını, bir çeyrekte önerilen on iki kararı ve kararların bu yapraklara etkisini modelliyor. Kök niteliğin skoru, yapraklarının eşiğe göre payının ortalamasıdır; kararın etkisi, uygulanmadan önceki ve sonraki skor farkıdır.
// gerilim.mjs — nitelikleri ve kararlari modelleyip gerilim matrisini kurar import { mkdirSync, writeFileSync } from "node:fs"; // KN6: kurgusal bolgesel kutuphane aginin on dort olculen yapragi ve baslangic degerleri. // [kod, kok nitelik, ad, birim, esik, yon, baslangic]. Model. const YAPRAK = [ ["P1", "basarim", "arama gecikmesi", "ms", 400, "kucuk", 310], ["P2", "basarim", "odunc islemi gecikmesi", "ms", 600, "kucuk", 420], ["P3", "basarim", "saatlik odunc islemi", "islem", 1200, "buyuk", 1500], ["E1", "erisilebilirlik", "aylik kesinti", "dk", 45, "kucuk", 22], ["E2", "erisilebilirlik", "yedege gecis", "sn", 60, "kucuk", 38], ["E3", "erisilebilirlik", "veri kaybi penceresi", "dk", 5, "kucuk", 2], ["G1", "guvenlik", "kimlik dogrulama kapsami", "%", 100, "buyuk", 96], ["G2", "guvenlik", "sir degeri tazeleme araligi", "gun", 90, "kucuk", 60], ["G3", "guvenlik", "denetim kaydi kapsami", "%", 90, "buyuk", 94], ["S1", "surdurulebilirlik", "degisimde dokunulan dosya", "dosya", 6, "kucuk", 4], ["S2", "surdurulebilirlik", "bagimlilik derinligi", "duzey", 5, "kucuk", 3], ["S3", "surdurulebilirlik", "sinama kapsamasi", "%", 70, "buyuk", 78], ["T1", "tasinabilirlik", "ortama ozgu cagri", "cagri", 12, "kucuk", 7], ["T2", "tasinabilirlik", "uc birim kurulumu", "dk", 45, "kucuk", 30], ]; // KN7: bir ceyrekte onerilen on iki mimari karar. Her karar, baslangic degerlerine gore // dokundugu yapraklarin yeni degerini verir; dokunmadigi yaprak degismez. Model. const KARAR = [ ["arama onbellegi", { P1: 180, S1: 5, S2: 4, T1: 9 }], ["es zamanli cogaltma", { E3: 0.5, E2: 30, P2: 560 }], ["her istekte kimlik dogrulama", { G1: 100, P1: 360, P2: 470 }], ["sir degerinin tazelenmesi", { G2: 30, S1: 5, T1: 10 }], ["denetim kaydinin yayilmasi", { G3: 99, P3: 1380, S1: 5 }], ["katman ayrimi", { S2: 2, S1: 3, P2: 450 }], ["sinama takimini genisletme", { S3: 88 }], ["subede yerel kuyruk", { E1: 12, T2: 40, S1: 5, S2: 4 }], ["otomatik yedege gecis", { E2: 20, E1: 18, S2: 4, G3: 90 }], ["istek basina hiz sinirlama", { E1: 16, P3: 1320, P1: 330 }], ["uyelik verisini ayirma", { G1: 99, S1: 6, P2: 500, T2: 38 }], ["toplu yuklemeyi geceye alma", { P1: 290, P3: 1560, E3: 3 }], ]; const KOK = [...new Set(YAPRAK.map((y) => y[1]))]; // Pay: kucuk yonlu yaprakta esik-deger, buyuk yonluda deger-esik; esige bolunerek // birimsizlestirilir. Kok niteligin skoru, yapraklarinin pay ortalamasidir. const pay = ([, , , , esik, yon], deger) => (yon === "kucuk" ? esik - deger : deger - esik) / esik; const skor = (deger) => Object.fromEntries(KOK.map((k) => { const y = YAPRAK.filter((n) => n[1] === k); return [k, y.reduce((s, n) => s + pay(n, deger[n[0]]), 0) / y.length]; })); const BASLANGIC = Object.fromEntries(YAPRAK.map((y) => [y[0], y[6]])); const temel = skor(BASLANGIC); const DUYARLIK = 0.005; // bu buyuklugun altindaki skor degisimi degisim sayilmaz const etki = KARAR.map(([ad, degisim]) => { const d = skor({ ...BASLANGIC, ...degisim }); const delta = Object.fromEntries(KOK.map((k) => [k, d[k] - temel[k]])); return { ad, degisim, delta }; }); mkdirSync("model", { recursive: true }); writeFileSync("model/model.mjs", `export const YAPRAK = ${JSON.stringify(YAPRAK)};\n` + `export const KARAR = ${JSON.stringify(KARAR)};\n` + `export const BASLANGIC = ${JSON.stringify(BASLANGIC)};\n`); const kisa = (k) => k.slice(0, 4); console.log(`${"karar".padEnd(30)}${"yukselen".padEnd(22)}dusen (olculen dusus)`); for (const e of etki) { const yuk = KOK.filter((k) => e.delta[k] > DUYARLIK); const dus = KOK.filter((k) => e.delta[k] < -DUYARLIK); console.log(`${e.ad.padEnd(30)}${(yuk.map(kisa).join(",") || "-").padEnd(22)}` + `${dus.map((k) => `${kisa(k)} ${(-e.delta[k] * 100).toFixed(1)}`).join(", ") || "-"}`); } // Gerilim matrisi: satir yukselen, sutun dusen nitelik; hucre o ikiliyi ureten karar sayisi. const matris = Object.fromEntries(KOK.map((a) => [a, Object.fromEntries(KOK.map((b) => [b, 0]))])); const dususToplam = Object.fromEntries(KOK.map((k) => [k, 0])); const yukselisSayisi = Object.fromEntries(KOK.map((k) => [k, 0])); for (const e of etki) { const yuk = KOK.filter((k) => e.delta[k] > DUYARLIK); const dus = KOK.filter((k) => e.delta[k] < -DUYARLIK); for (const a of yuk) { yukselisSayisi[a] += 1; for (const b of dus) matris[a][b] += 1; } for (const b of dus) dususToplam[b] += -e.delta[b]; } console.log(`\ngerilim matrisi (satir yukselir, sutun duser; hucre karar sayisi)`); console.log(`${"".padEnd(20)}${KOK.map((k) => kisa(k).padStart(7)).join("")}`); for (const a of KOK) console.log(`${a.padEnd(20)}${KOK.map((b) => (a === b ? "-" : String(matris[a][b])).padStart(7)).join("")}`); const cift = KOK.flatMap((a) => KOK.filter((b) => a !== b && matris[a][b] > 0).map((b) => [a, b])); const karsilikli = cift.filter(([a, b]) => matris[b][a] > 0).length / 2; console.log(`\ncelisen sirali cift ${cift.length}/${KOK.length * (KOK.length - 1)}, ` + `bunlarin ${karsilikli} tanesi karsilikli (iki yonde de bastirma var)`); const dusuren = (k) => etki.filter((e) => e.delta[k] < -DUYARLIK).length; const enCok = KOK.slice().sort((a, b) => dususToplam[b] - dususToplam[a])[0]; console.log(`en cok bastirilan nitelik: ${enCok}; ${dusuren(enCok)} kararda ` + `${KOK.filter((a) => matris[a][enCok] > 0).length} ayri nitelik ugruna dusuruluyor, ` + `toplam olculen dusus ${(dususToplam[enCok] * 100).toFixed(1)} pay puani`); for (const k of KOK) if (yukselisSayisi[k] === 0) console.log(`hicbir kararin iyilestirmedigi nitelik: ${k}; ${KARAR.length} kararin ` + `${dusuren(k)} tanesi dusuruyor, hicbiri yukseltmiyor`);
karar yukselen dusen (olculen dusus)
arama onbellegi basa surd 12.2, tasi 8.3
es zamanli cogaltma eris basa 7.8
her istekte kimlik dogrulama guve basa 6.9
sir degerinin tazelenmesi guve surd 5.6, tasi 12.5
denetim kaydinin yayilmasi guve basa 3.3, surd 5.6
katman ayrimi surd basa 1.7
sinama takimini genisletme surd -
subede yerel kuyruk eris surd 12.2, tasi 11.1
otomatik yedege gecis eris guve 1.5, surd 6.7
istek basina hiz sinirlama eris basa 6.7
uyelik verisini ayirma guve basa 4.4, surd 11.1, tasi 8.9
toplu yuklemeyi geceye alma basa eris 6.7
gerilim matrisi (satir yukselir, sutun duser; hucre karar sayisi)
basa eris guve surd tasi
basarim - 1 0 1 1
erisilebilirlik 2 - 1 2 1
guvenlik 3 0 - 3 2
surdurulebilirlik 1 0 0 - 0
tasinabilirlik 0 0 0 0 -
celisen sirali cift 11/20, bunlarin 2 tanesi karsilikli (iki yonde de bastirma var)
en cok bastirilan nitelik: surdurulebilirlik; 6 kararda 3 ayri nitelik ugruna dusuruluyor, toplam olculen dusus 53.3 pay puani
hicbir kararin iyilestirmedigi nitelik: tasinabilirlik; 12 kararin 4 tanesi dusuruyor, hicbiri yukseltmiyor
Yirmi sıralı nitelik çiftinin 11’inde çelişki ölçülüyor: bir niteliği yükselten en az bir karar ötekini düşürüyor. İkisi karşılıklı — başarım ile erişilebilirlik, başarım ile sürdürülebilirlik. Karşılıklı çift, hangi yönde ilerlenirse ilerlensin ötekinin düştüğü çifttir; kapatılamaz, yalnız düşüşün payı seçilebilir.
En çok bastırılan nitelik sürdürülebilirlik: on iki kararın altısı onu düşürüyor, üç ayrı nitelik uğruna, toplam 53,3 pay puanı. Sürdürülebilirlik yapraklarının ikisi — değişimde dokunulan dosya ve bağımlılık derinliği — hemen her ekleme kararında artar. Bir parça eklemek başarım ya da güvenlik için seçilir; bedelini her seferinde sürdürülebilirlik öder.
Matrisin son satırı sıfırlarla dolu. Hiçbir karar taşınabilirliği yükseltmiyor; dördü düşürüyor. Bu ölçü taşınabilirliğin önemsiz olduğunu göstermez — kimsenin onu hedefleyen bir karar önermediğini gösterir. Eşiği yazmak, o niteliği savunan bir kararın önerileceği anlamına gelmiyor; matris, listede olmayan kararı görünür kılan tek satırdır.
Bir karar hiçbir niteliği düşürmüyor: sınama takımını genişletme. Ölçülen on dört yaprakta bu kararın bedelini taşıyan yaprak yok; ölçülmeyen bedel matriste sıfır görünür. Matris, ölçülen yapraklar kadar dürüsttür.
Gerilemenin Denetimi
Matris bir tablo doldurur, kendiliğinden bir şey engellemez. Sıradaki soru, gerilimin koşturulabilir bir denetime çevrilip çevrilemeyeceğidir: bir karar uygulandığında hiçbir kök niteliğin skoru belirli bir eşikten fazla düşmemeli. Aşağıdaki blok bu denetimi bilinen ihlal kümesine uyguluyor ve eşik seçiminin ne değiştirdiğini sayıyor.
// gerileme.mjs — gerilimi kosturulabilir bir gerileme denetimine cevirir ve bilinen ihlal // kumesinde yakalanan / kacan / yanlis alarm sayar import { YAPRAK, KARAR, BASLANGIC } from "./model/model.mjs"; // KN8: bilinen ihlal kumesi. On iki karar uygulandiktan sonra bes tanesi kayitlarda // "kabul edilemez gerileme" olarak isaretlenmis; kalan yedisinin dususu bilerek kabul // edilmis takastir. Bu isaret bir yargidir, olcumden cikmaz. Model. const IHLAL = ["arama onbellegi", "sir degerinin tazelenmesi", "subede yerel kuyruk", "uyelik verisini ayirma", "katman ayrimi"]; const KOK = [...new Set(YAPRAK.map((y) => y[1]))]; const TAVAN = { "%": 100 }; // yuzde tasiyan yaprak 100'u asamaz const pay = ([, , , , esik, yon], d) => (yon === "kucuk" ? esik - d : d - esik) / esik; const skor = (deger) => Object.fromEntries(KOK.map((k) => { const y = YAPRAK.filter((n) => n[1] === k); return [k, y.reduce((s, n) => s + pay(n, deger[n[0]]), 0) / y.length]; })); const temel = skor(BASLANGIC); const enBuyukDusus = ([, degisim]) => { const d = skor({ ...BASLANGIC, ...degisim }); return Math.max(0, ...KOK.map((k) => (temel[k] - d[k]) * 100)); }; // Denetim: bir karar uygulandiginda hicbir kok niteligin skoru esikten cok dusmemeli. // Esigin nereye konacagi olcumden cikmaz; asagidaki tarama secenekleri sayar. console.log(`${"esik (pay puani)".padEnd(18)}${"atesleme".padStart(9)}${"yakalanan".padStart(10)}` + `${"kacan".padStart(7)}${"yanlis alarm".padStart(14)}`); for (const esik of [2, 4, 6, 8, 10, 12]) { const oten = KARAR.filter((k) => enBuyukDusus(k) > esik).map(([ad]) => ad); const yak = oten.filter((ad) => IHLAL.includes(ad)); console.log(`${String(esik).padEnd(18)}${String(oten.length).padStart(9)}` + `${String(yak.length).padStart(10)}${String(IHLAL.length - yak.length).padStart(7)}` + `${String(oten.length - yak.length).padStart(14)}`); } const SECILEN = 6; const oten = KARAR.filter((k) => enBuyukDusus(k) > SECILEN).map(([ad]) => ad); console.log(`\nsecilen esik ${SECILEN} pay puani`); for (const ad of IHLAL.filter((a) => !oten.includes(a))) console.log(` kacan: ${ad} (en buyuk dusus ` + `${enBuyukDusus(KARAR.find(([k]) => k === ad)).toFixed(1)} pay puani, esigin altinda)`); for (const ad of oten.filter((a) => !IHLAL.includes(a))) console.log(` yanlis alarm: ${ad} (dususu kayitta kabul edilmis)`); // Birikimli etki: kararlar sirayla uygulanir, her etki o yapragin degerini kendi baslangicina // gore carpan olarak degistirir. Tekil denetim her karara ayri baktigi icin birikimi goremez. const son = { ...BASLANGIC }; for (const [, degisim] of KARAR) for (const [kod, yeni] of Object.entries(degisim)) { const y = YAPRAK.find((n) => n[0] === kod); son[kod] = Math.min(son[kod] * (yeni / BASLANGIC[kod]), TAVAN[y[3]] ?? Infinity); } const asan = YAPRAK.filter((y) => pay(y, son[y[0]]) < 0); const tekil = KARAR.flatMap(([ad, d]) => YAPRAK.filter((y) => y[0] in d && pay(y, d[y[0]]) < 0).map((y) => [ad, y[0]])); console.log(`\ntekil kararda esigi asan (karar, yaprak) ikilisi ${tekil.length} ` + `(${tekil.map(([a, k]) => `${a}/${k}`).join(", ")}); on iki karar birlikte uygulandiginda ` + `esigi asan yaprak ${asan.length}, ${[...new Set(asan.map((n) => n[1]))].length} nitelikte`); for (const y of asan) console.log(` ${y[0]} ${y[2].padEnd(26)} ${BASLANGIC[y[0]]} -> ${son[y[0]].toFixed(1)} ` + `${y[3]} (esik ${y[4]})`); // KN9: cevrilemeyen kisim. Denetim dususu olcer, kabul edilebilirligini olcemez; bu bir // yargidir. Yerine muafiyet kaydi konur ve denetim kayda bakar. const muafiyet = oten.filter((a) => !IHLAL.includes(a)); console.log(`\ncevrilemeyen: dususun kabul edilebilirligi (yargi). Yerine ${muafiyet.length} ` + `muafiyet kaydi konuyor; kayittan sonra yanlis alarm ${muafiyet.length} -> 0, ` + `yakalanan ${oten.length - muafiyet.length}, kacan ${IHLAL.length - (oten.length - muafiyet.length)}`); console.log(`denetim maliyeti: karar basina ${YAPRAK.length} yeniden olcum, ` + `${KARAR.length} kararda ${KARAR.length * YAPRAK.length} olcum; ` + `kosum ${KARAR.length * KOK.length + YAPRAK.length} karsilastirma; ` + `bakim ${muafiyet.length} muafiyet kaydi (her karar degistiginde gozden gecirilir)`);
esik (pay puani) atesleme yakalanan kacan yanlis alarm 2 10 4 1 6 4 10 4 1 6 6 9 4 1 5 8 4 4 1 0 10 4 4 1 0 12 3 3 2 0 secilen esik 6 pay puani kacan: katman ayrimi (en buyuk dusus 1.7 pay puani, esigin altinda) yanlis alarm: es zamanli cogaltma (dususu kayitta kabul edilmis) yanlis alarm: her istekte kimlik dogrulama (dususu kayitta kabul edilmis) yanlis alarm: otomatik yedege gecis (dususu kayitta kabul edilmis) yanlis alarm: istek basina hiz sinirlama (dususu kayitta kabul edilmis) yanlis alarm: toplu yuklemeyi geceye alma (dususu kayitta kabul edilmis) tekil kararda esigi asan (karar, yaprak) ikilisi 1 (uyelik verisini ayirma/G1); on iki karar birlikte uygulandiginda esigi asan yaprak 4, 3 nitelikte P2 odunc islemi gecikmesi 420 -> 799.3 ms (esik 600) S1 degisimde dokunulan dosya 4 -> 11.0 dosya (esik 6) T1 ortama ozgu cagri 7 -> 12.9 cagri (esik 12) T2 uc birim kurulumu 30 -> 50.7 dk (esik 45) cevrilemeyen: dususun kabul edilebilirligi (yargi). Yerine 5 muafiyet kaydi konuyor; kayittan sonra yanlis alarm 5 -> 0, yakalanan 4, kacan 1 denetim maliyeti: karar basina 14 yeniden olcum, 12 kararda 168 olcum; kosum 74 karsilastirma; bakim 5 muafiyet kaydi (her karar degistiginde gozden gecirilir)
Eşik taraması tek bir eşiğin işi bitirmediğini gösteriyor. Sekiz pay puanında denetim beş bilinen ihlalin dördünü yakalıyor ve hiç boşa ötmüyor; altıya indirilince yakalama artmıyor, yanlış alarm beşe çıkıyor. İkiye kadar gevşetilse bile beşinci ihlal kaçıyor. Nedeni duyarlılık değil: o kararın en büyük düşüşü 1,7 pay puanı ve kabul edilemez sayılmasının nedeni düşüşün büyüklüğü değil düştüğü yer — yoğun saatteki ödünç işlemi. Denetim skor ortalamasına bakıyor, ortalamanın altındaki dağılıma bakmıyor. Kaçan ihlal denetimin duyarlılığının altında değil, baktığı büyüklüğün dışındadır.
Altı puanlık eşikteki beş yanlış alarmın beşi de bilerek kabul edilmiş takas. Bu, çevrilemeyen kısmı adıyla ortaya koyar: denetim düşüşün büyüklüğünü ölçebiliyor, kabul edilebilirliğini ölçemiyor, çünkü bu bir yargıdır. Yerine muafiyet kaydı konuyor — kabul edilen her düşüş için hangi niteliğin uğruna kabul edildiği yazılıyor ve denetim kayda bakıyor. Beş kayıttan sonra yanlış alarm sıfıra iniyor. Bedeli belli: beş kayıt karar her değiştiğinde gözden geçirilmek zorunda, kayıt eskirse denetim susar ve susması artık doğru değildir.
Son ölçüm denetimin yapısal körlüğünü gösteriyor. Tekil karar denetimi on iki kararda yalnız bir (karar, yaprak) ikilisinde eşik aşımı görüyor; kararlar birlikte uygulandığında dört yaprak eşiği aşıyor, üç ayrı nitelikte. Dahası tekil denetimin gördüğü tek aşım birikimde kapanıyor — sonraki bir karar o yaprağı eşiğin üstüne geri taşıyor. Tekil karar denetimi ile birikimli denetim aynı küme üzerinde birbirinin tersini buluyor; biri seçilirse öteki tamamen kaçar. Maliyet iki kalemdir: her karardan sonra on dört yaprağın yeniden ölçülmesi (168 ölçüm) ve beş muafiyet kaydının bakımı; koşum 74 karşılaştırma, ölçümün yanında yok sayılır.
Özet
- Gerilim matrisi, bir niteliği yükselten kararın ötekilerde ölçülen düşüşünü sayar; yirmi sıralı çiftin 11’i çelişiyor, ikisi karşılıklı.
- En çok bastırılan nitelik sürdürülebilirlik: altı kararda, üç ayrı nitelik uğruna, toplam 53,3 pay puanı; hiçbir karar onu hedeflemediği halde bedelini her eklemede o ödüyor.
- Hiçbir karar taşınabilirliği yükseltmiyor, dördü düşürüyor; eşiği yazılı bir nitelik, onu savunan karar önerilmediği sürece yalnız düşer.
- Eşik taraması hiçbir eşikte beş ihlali birden yakalamıyor: sekiz puanda 4/1/0, altı puanda 4/1/5 (yakalanan / kaçan / yanlış alarm); kaçan, denetimin baktığı büyüklüğün dışındadır.
- Denetim düşüşü ölçer, kabul edilebilirliğini ölçemez; yerine beş muafiyet kaydı konuyor ve yanlış alarm sıfıra iniyor — tekil denetim bir aşım görürken birikimli denetim dört başka aşım buluyor.
Sonraki Adım
Matriste güvenlik üç kararla yükseldi, karşılığında başarımı ve sürdürülebilirliği üçer kararda bastırdı. Ama bu hesapta güvenlik tek bir skordu: üç yaprağın payının ortalaması. Sonraki ders o skoru açar, çünkü güvenlik kararının bedeli tek bir sayıya sığmıyor. Sistem, veriyi bir yerden başkasına geçiren sınırlardan oluşur; kaç sınır olduğu, hangi verinin hangi sınırı geçtiği ve her sınırda kaç denetim durduğu sayılabilir. Sayıldığında iki şey çıkar: hiçbir denetimden geçmeyen geçişler ve bir sınır kaldırıldığında açılan yeni yollar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.