Ders 09 / 11
Raporlama
Bir koşum sonucunun ekip için okunur kılınması: aynı gecelik koşumun dört raporlama düzeninde okunan satır, açılan adım ve gürültü kalemi cinsinden ölçülmesi, karara dönüşme süresinin dikkat bütçesiyle karşılaştırılması, karara bağlanamayan kökün kaçan hataya dönüşmesi ve kırılgan bölümünün ayıklama eşiğinin kaynağıyla birlikte taranması.
İçindekiler
Önceki dersler hattı, ortamı ve gizli değeri düzene soktu. Hat artık her değişiklikte ve her gece bir sonuç üretiyor. Bu dersin sorusu o sonucun kendisi değil, kime ne söylediğidir: bir koşum sonucu bir karara dönüşmediği sürece koşulmamış sayılır, çünkü kimse ona dayanarak bir şey yapmaz.
Bu bir yazım işi değil, bir dağıtım işidir. Dağıtılan kaynak dikkattir: sonuç karara dönüşene kadar kaç satır okunuyor, neden kaç adımda bulunuyor, kaç kalem karşılığında hiçbir şey yapılmıyor. Aynı koşum sonucu dört düzende sunulur ve bu üç sayı ölçülür.
Bir Koşumun Ham Sonucu
Ölçülecek sonuç gecelik bir koşumdan gelir: günün beş değişikliği birlikte alınır ve sürüm kapısındaki iki takım dışında yedi takım koşar. Sonucun içindeki kırmızı kalemler dört kaynaktan gelir ve raporun asıl işi bunları ayırmaktır — kök (bir kusurun ilk düşürdüğü test), türev (aynı kökün düşürdüğü öteki testler), ortam (sınanan koda değil düzeneğe ait arıza) ve kırılgan (kod değişmeden düşen test).
// kosum.mjs — bir gecelik kosumun ham sonucu: test durumlari, kirmizi kalemler, kokler let s = 20260731; // tohum const rast = () => ((s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32); // TS16: yedi takimin test sayisi; kirilgan testler `adim` araligiyla dagilir ve `oran` ile // duser, `gecmis` GERCEK bir kusur yuzunden dusme olasiligidir. Surum kapisi bu kosumda yok. export const takimlar = [ { ad: 'birim', test: 240, adim: 0, oran: 0.00, gecmis: 0.010 }, { ad: 'sozlesme', test: 42, adim: 21, oran: 0.03, gecmis: 0.008 }, { ad: 'tumlesim', test: 96, adim: 12, oran: 0.06, gecmis: 0.015 }, { ad: 'uctan-uca', test: 34, adim: 3, oran: 0.15, gecmis: 0.012 }, { ad: 'basarim-kosum', test: 12, adim: 6, oran: 0.10, gecmis: 0.010 }, { ad: 'guvenlik-otomatik', test: 58, adim: 19, oran: 0.04, gecmis: 0.006 }, { ad: 'dayaniklilik', test: 14, adim: 7, oran: 0.05, gecmis: 0.010 }, ]; // M21/K03: karar 200 kosumda OLCULEN orana bakar; olculen oran iki kaynagin toplamidir. export const testler = []; for (const t of takimlar) { for (let i = 0; i < t.test; i += 1) { const kirilgan = t.adim > 0 && i % t.adim === 0 ? t.oran : 0; let dK = 0, dG = 0; for (let k = 0; k < 200; k += 1) { if (rast() < kirilgan) dK += 1; if (rast() < t.gecmis) dG += 1; } testler.push({ id: `${t.ad}/${i + 1}`, takim: t.ad, kirilgan, dK, dG, olculen: (dK + dG) / 200, kirmizi: false, kok: null }); } } // TS17: bu kosumun kirmizi kokleri. Sinif adi ve yakalayan takim otomasyon-altyapisi/01'in // kusur kumesinden; etkilenen test sayisi kusurun dokundugu ortak yuzeyden gelir. export const kokler = [ { ad: 'sema uyusmazligi', takim: 'tumlesim', etkilenen: 23, gercek: true }, { ad: 'sinir karsilastirmasi', takim: 'birim', etkilenen: 3, gercek: true }, { ad: 'durum kodu eslemesi', takim: 'uctan-uca', etkilenen: 5, gercek: true }, { ad: 'bagimli servis ayaga kalkmadi', takim: 'dayaniklilik', etkilenen: 14, gercek: false }, ]; for (const t of testler) if (t.kirilgan > 0 && rast() < t.kirilgan) { t.kirmizi = true; t.kok = 'kirilgan'; } for (const k of kokler) { for (const t of testler.filter((x) => x.takim === k.takim).slice(0, k.etkilenen)) { t.kirmizi = true; t.kok = k.ad; } } export const kirmizilar = testler.filter((t) => t.kirmizi); export const gercekKok = kokler.filter((k) => k.gercek);
Bu koşumda üç gerçek kusur ve bir ortam arızası var; düşen kalem sayısı çok daha büyüktür, çünkü paylaşılan bir şemaya dokunan tek kusur o şemayı kullanan yirmi üç testi birden düşürür. Rapor bunu bilmez; gördüğü şey yalnızca kırmızı kalemlerdir.
Dört Raporlama Düzeni
Aşağıdaki düzenek okumayı maliyet olarak modeller (TS18). Bir satır üç saniye, bir adım üç dakikadır; adım, satırı okumakla bitmeyen her iştir — ayrıntıyı açmak, yeniden koşturmak, sahibini bulmak. Öbeklenmemiş raporda okuyucu aynı imzayı ancak üçüncü kalemde birleştirir.
TS19 — bir kişinin bir koşum sonucuna ayırdığı dikkat 30 dakikadır, yani bir iş gününün on altıda biri; duyarlılığı tablonun ikinci bölümünde taranır. Karara bağlanamayan kök bir sonraki gecelik koşuma kalır ve TS8 gereği 240 dakika ekler; hiç bağlanamayan kök kaçar.
// rapor.mjs — ayni kosum sonucunun dort raporlama duzeninde karara donusme suresi import { takimlar, testler, kirmizilar, kokler, gercekKok } from './kosum.mjs'; // TS18: satir 3 sn, adim 3 dk, ham gunlukte kirmizi basina 12 ayrinti satiri, ayni imza // ucuncu kalemde birlesir. TS19: bir kosum sonucuna ayrilan dikkat 30 dk. const SN = 3, ADIM = 3, AYRINTI = 12, TANIMA = 3, BUTCE = 30; const BEKLEME = 240; // otomasyon-altyapisi/01 TS8: gecelik bekleme // Bir duzenin okuma akisi: sirayla {satir, adim, biten kok} olaylari. function akis(duzen, kalan) { const canli = (t) => t.kirmizi && (t.kok === 'kirilgan' || kalan.includes(t.kok)); const o = [], say = {}; const ham = (hepsi) => { for (const tk of takimlar) { if (hepsi) o.push({ satir: 2, adim: 0 }); for (const t of testler.filter((x) => x.takim === tk.ad)) { if (canli(t) === false) { if (hepsi) o.push({ satir: 1, adim: 0 }); continue; } const n = (say[t.kok] = (say[t.kok] ?? 0) + 1); const grup = testler.filter((x) => canli(x) && x.kok === t.kok).length; o.push({ satir: hepsi ? 1 + AYRINTI : 1, adim: n <= TANIMA ? 1 : 0, biten: n === Math.min(TANIMA, grup) ? t.kok : null }); } } }; if (duzen === 'ham gunluk') { o.push({ satir: 1, adim: 1 }); ham(true); } if (duzen === 'duz liste') { o.push({ satir: 1, adim: 0 }); ham(false); o.push({ satir: 1, adim: 0 }); } if (duzen === 'obeklenmis') { for (const k of kokler.filter((x) => x.gercek && kalan.includes(x.ad))) o.push({ satir: 3, adim: 1, biten: k.ad }); // baslik + kok test + "n kalem daha" o.push({ satir: 1, adim: 1 }, { satir: 1, adim: 1 }, { satir: 2, adim: 0 }); // ortam, kirilgan, ozet } if (duzen === 'yalniz ozet') { o.push({ satir: 3, adim: 2 }); ham(true); } return o; } const oku = (duzen, kalan, butce) => { let dk = 0, satir = 0, adim = 0; const biten = []; for (const e of akis(duzen, kalan)) { const y = dk + (e.satir * SN) / 60 + e.adim * ADIM; if (y > butce) break; dk = y; satir += e.satir; adim += e.adim; if (e.biten && kalan.includes(e.biten)) biten.push(e.biten); } return { dk, satir, adim, biten }; }; // Karara baglanmayan kok bir sonraki kosuma kalir (+240 dk); hic baglanamayan kok kacar. function olc(duzen, butce = BUTCE) { let kalan = gercekKok.map((k) => k.ad), dongu = 0, ilk = null; const geri = []; while (kalan.length > 0 && dongu < 20) { dongu += 1; const r = oku(duzen, kalan, butce); ilk ??= r; if (r.biten.length === 0) break; for (const _ of r.biten) geri.push(BEKLEME * dongu + r.dk); kalan = kalan.filter((a) => r.biten.includes(a) === false); } const ort = geri.length ? geri.reduce((a, c) => a + c, 0) / geri.length : NaN; return { ...ilk, ilkDongu: ilk.biten.length, dongu, kacan: kalan.length, geri: ort }; } const D = ['ham gunluk', 'duz liste', 'obeklenmis', 'yalniz ozet']; const gurultu = { 'ham gunluk': testler.length - 3, 'duz liste': kirmizilar.length - 3, obeklenmis: 2, 'yalniz ozet': testler.length - 3 }; const p = (x, n) => String(x).padStart(n); const tam = akis('ham gunluk', gercekKok.map((k) => k.ad)).reduce((a, e) => a + e.satir, 0); console.log(`${testler.length} test, ${kirmizilar.length} kirmizi kalem, ${kokler.length} kok ` + `(${gercekKok.length} gercek kusur + 1 ortam), ${kirmizilar.filter((t) => t.kok === 'kirilgan').length} bagimsiz kirilgan dusus`); console.log(`ham gunluk ${tam} satir = ${((tam * SN) / 60).toFixed(1)} dk, butcenin ` + `${((tam * SN) / 60 / BUTCE).toFixed(1)} kati\n`); console.log(`${'duzen'.padEnd(14)}${p('satir', 7)}${p('adim', 6)}${p('dakika', 8)}${p('gurultu', 9)}` + `${p('ilk dongu', 11)}${p('dongu', 7)}${p('kacan kok', 11)}${p('ort geri', 10)}`); for (const d of D) { const r = olc(d); console.log(`${d.padEnd(14)}${p(r.satir, 7)}${p(r.adim, 6)}${p(r.dk.toFixed(1), 8)}` + `${p(gurultu[d], 9)}${p(`${r.ilkDongu}/3`, 11)}${p(r.dongu, 7)}${p(r.kacan, 11)}` + `${p(Number.isNaN(r.geri) ? '-' : r.geri.toFixed(1), 10)}`); } console.log(`\nTS19 duyarliligi (ilk donguda karara baglanan kok / kacan kok)`); console.log(`${'butce'.padEnd(8)}${D.map((d) => p(d, 14)).join('')}`); for (const b of [15, 30, 60]) console.log(`${`${b} dk`.padEnd(8)}${D.map((d) => { const r = olc(d, b); return p(`${r.ilkDongu} / ${r.kacan}`, 14); }).join('')}`);
496 test, 46 kirmizi kalem, 4 kok (3 gercek kusur + 1 ortam), 1 bagimsiz kirilgan dusus ham gunluk 895 satir = 44.8 dk, butcenin 1.5 kati duzen satir adim dakika gurultu ilk dongu dongu kacan kok ort geri ham gunluk 325 4 28.3 493 1/3 3 1 389.0 duz liste 32 9 28.6 43 3/3 1 0 268.6 obeklenmis 13 5 15.7 2 3/3 1 0 255.7 yalniz ozet 299 5 30.0 493 1/3 2 2 270.0 TS19 duyarliligi (ilk donguda karara baglanan kok / kacan kok) butce ham gunluk duz liste obeklenmis yalniz ozet 15 dk 1 / 2 1 / 0 3 / 0 0 / 3 30 dk 1 / 1 3 / 0 3 / 0 1 / 2 60 dk 2 / 0 3 / 0 3 / 0 2 / 0
Ham günlük 895 satırdır; tamamını okumak bütçenin bir buçuk katıdır. Okuyucu 325 satırda bütçeyi bitiriyor ve o gece yalnız bir kökü karara bağlıyor. Üç gece üst üste okunduğunda bile üçüncü kök görünmüyor: uçtan uca takımı günlüğün sonunda, kırk altı kırmızının ayrıntı satırlarının ardındadır. Bir kusurun raporda bulunması, raporda yer alması demek değildir.
Düz kırmızı listesi ile öbeklenmiş rapor aynı kararı veriyor: üç kökün üçü de ilk gecede kapanıyor, kaçan yok. Fark bedeldedir. Düz liste 32 satır okutuyor, öbeklenmiş 13; ama düz liste 9 adım açtırıyor, öbeklenmiş 5. Sayılar burada ayrışır: 32 satır 1,6 dakika, 9 adım 27 dakikadır. Raporun bedeli okuma bedeli değil, açma bedelidir — ve açma bedeli yalnızca öbeklemeyle düşer, kısaltmayla değil. Düz liste bütçenin yüzde doksan beşini tüketiyor; öbeklenmiş rapor yarısını.
Bu payın önemi duyarlılık tablosunda görünür. On beş dakikalık bir bütçede öbeklenmiş rapor yine üç kökü de çıkarıyor, düz liste yalnız birini. Ters yönde de simetri yoktur: bütçe altmış dakikaya çıkarıldığında ham günlük ilk döngüde iki kök veriyor, öbeklenmiş rapor bunu on beş dakikada üç yapıyor. Dikkati artırmak öbeklemenin yaptığını yapmıyor, çünkü harcanan dikkatin çoğu kararın kendisine değil, aynı kökü tekrar tekrar tanımaya gidiyor.
Gürültü sütunu farkın kaynağını veriyor: ham günlükte 493 kalem hiçbir karara bağlanmaz, düz listede 43, öbeklenmiş raporda 2 — ortam ve kırılgan bölümleri. Yalnız özet düzeninde rapor üç satırdır ve hiçbir şey söylemez; okuyucu ham günlüğe döner, iki kök kaçar. Kısa bir rapor okunur bir rapor değildir.
Kırılgan Bölümünün Eşiği
Öbeklenmiş raporun kazancının bir bölümü kırılgan kalemleri ayrı bölüme almasından gelir. Bu bir eşik kararıdır: ölçülen düşme oranı eşiği aşan test kırılgan sayılır ve ana bölümden çıkarılır. Eşiğin kaynağı Kırılganlık Yönetimi dersidir; orada aynı sayı karantina eşiği olarak tarandı ve testi hattan çıkardı. Buradaki karar daha hafiftir — test koşmayı sürdürür — ama bedeli aynı biçimde ölçülür.
// esik.mjs — kirilgan bolumunun ayiklama esigi: kesilen gurultu ile gizlenen gercek kirmizi import { testler, kirmizilar, gercekKok } from './kosum.mjs'; const p = (x, n) => String(x).padStart(n); const toplam = (f) => testler.reduce((a, t) => a + f(t), 0); console.log(`${'esik'.padStart(6)}${p('ayrilan test', 14)}${p('bolume dusen', 14)}` + `${p('gizlenen kalem', 16)}${p('gizlenen kok', 14)}` + `${p('kesilen gurultu', 17)}${p('gizlenen gercek', 17)}`); for (const e of [0.005, 0.01, 0.015, 0.025, 0.05, 0.1]) { const ayri = new Set(testler.filter((t) => t.olculen >= e).map((t) => t.id)); const dusen = kirmizilar.filter((t) => ayri.has(t.id)); const kalem = dusen.filter((t) => gercekKok.some((k) => k.ad === t.kok)).length; const kok = gercekKok.filter((k) => kirmizilar.filter((t) => t.kok === k.ad).every((t) => ayri.has(t.id))).length; console.log(`${`%${(e * 100).toFixed(1)}`.padStart(6)}${p(ayri.size, 14)}${p(dusen.length, 14)}` + `${p(kalem, 16)}${p(kok, 14)}` + `${p(toplam((t) => (ayri.has(t.id) ? t.dK : 0)), 17)}` + `${p(toplam((t) => (ayri.has(t.id) ? t.dG : 0)), 17)}`); } console.log(`\nsutunlar: ilk dordu BU kosumun ${kirmizilar.length} kirmizi kalemi uzerinde, ` + `son ikisi 200 kosumluk gecmis uzerinde`); console.log(`gecmisteki ${toplam((t) => t.dK + t.dG)} dususun ` + `${toplam((t) => t.dK)}'i kirilganliktan, ${toplam((t) => t.dG)}'i gercek kusurdandir; ` + `rapor ikisini ayirt edemez, yalnizca toplam orani gorur`);
esik ayrilan test bolume dusen gizlenen kalem gizlenen kok kesilen gurultu gizlenen gercek %0.5 431 45 31 3 541 1013 %1.0 296 35 23 0 541 878 %1.5 187 26 18 0 541 660 %2.5 61 14 9 0 541 241 %5.0 25 7 4 0 508 59 %10.0 13 3 2 0 364 26 sutunlar: ilk dordu BU kosumun 46 kirmizi kalemi uzerinde, son ikisi 200 kosumluk gecmis uzerinde gecmisteki 1554 dususun 541'i kirilganliktan, 1013'i gercek kusurdandir; rapor ikisini ayirt edemez, yalnizca toplam orani gorur
İlk satır eşiğin nereye varabileceğini gösteriyor. Yüzde 0,5’te 496 testin 431’i kırılgan sayılıyor, 46 kırmızının 45’i ikinci bölüme düşüyor ve üç gerçek kökün üçü birden gizleniyor. Rapor tertemiz görünür ve hiçbir şey söylemez: gürültüyü sıfırlayan bir rapor sinyali de sıfırlamış olabilir.
Nedeni son iki sütunda yazılı. Geçmişteki 1554 düşüşün 541’i kırılganlıktan, 1013’ü gerçek kusurdan gelir; rapor ikisini ayırt edemez, yalnız toplam oranı görür. Bu yüzden düşük bir eşik, en çok kusur çıkarmış testleri gizler.
Yüzde 2,5 eşiği ayrımı yapabildiği en düşük noktadır: 61 test ayrılıyor, 14 kalem ikinci bölüme iniyor, dokuzu gerçek kusurdan geliyor, ama hiçbir kök tamamen gizlenmiyor — her kökün en az bir kalemi ana bölümde kalıyor. Karşılığında geçmişteki 541 kırılgan düşüşün tamamı kesiliyor. Eşiği yükseltmek buradan sonra yalnız kaybettirir: yüzde 5’te kesilen gürültü 508’e, yüzde 10’da 364’e iner, yani gürültü ana bölüme geri döner.
Kararın Geri Dönüşü
Bir raporun her bölümü bir eylemin karşılığıdır; karşılığı olmayan bölüm çıkarılır. Kök bölümü bir kaydı açar ve sahibi o kusura dokunan değişikliğin sahibidir; gecelik koşumun sahibi tek bir kişi olmadığı için bu bölüm kökü göstermek zorundadır, kalem saymak yetmez. Ortam bölümü hattı işletenin işine girer ve sınanan kod hakkında hiçbir şey söylemez. Kırılgan bölümü kimseyi durdurmaz; bir bakım listesidir ve karantina kararının girdisidir.
Türev kalemlerin gösterilmemesi de bir karardır, saklama değil: yirmi üç test tek kusurdan düştüğü için tek kayıt açılır. Ayrı ayrı gösterilselerdi kayıt sayısı değişmez, harcanan dikkat yirmi üç katına çıkardı.
Özet
- Aynı koşum sonucu dört düzende sunuldu: 496 test, 46 kırmızı kalem, 3 gerçek kök, 1 ortam arızası, 1 bağımsız kırılgan düşüş.
- Öbeklenmiş rapor üç kökü 13 satır, 5 adım ve 15,7 dakikada karara bağladı; düz liste aynı kararı 32 satır, 9 adım ve 28,6 dakikada verdi — fark açılan adımlardan gelir (9 adım 27 dakika, 32 satır 1,6 dakikadır).
- Ham günlükte bir kök hiçbir gece karara bağlanmadı ve kaçtı; yalnız özet düzeninde iki kök kaçtı. Ortalama geri bildirim süresi öbeklenmiş raporda 255,7, ham günlükte 389,0 dakikadır.
- Dikkat bütçesini artırmak öbeklemenin yerini tutmadı: 60 dakikada ham günlük iki kök, öbeklenmiş rapor 15 dakikada üç kök çıkardı.
- Kırılgan bölümünün eşiği yüzde 0,5’e indirildiğinde üç kökün üçü de gizlendi; yüzde 2,5’te kırılgan düşüşlerin tamamı kesilirken hiçbir kök gizlenmedi.
Sonraki Adım
Buradaki bütün ölçüler tek bir koşuma aittir ve tek bir gecenin kararını verir. Bir rapor, kendi koşumundaki kökü ne kadar iyi gösterirse göstersin, şu soruya yanıt veremez: bu ekip zaman içinde daha mı iyi sınıyor, yoksa aynı hatalar başka adlarla mı geliyor. Şema uyuşmazlığının bu gece çıkması bir olaydır; her hafta çıkması bir süreç kusurudur ve tek koşumun raporunda ikisi aynı görünür. Sonraki ders ölçüyü dönem düzeyine taşır: kaçan hata, geri dönüş ve döngü süresi aynı veri üzerinden hesaplanır ve her birinin hangi kararı değiştirdiği sorulur.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.