İçeriğe geç
academia.sh

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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat