İçeriğe geç
academia.sh

Ders 14 / 15

Kırılganlık Yönetimi

Uçtan uca takım ölçeğinde kırılganlığın nedenlerine göre dağılımının ölçülmesi, tek tek küçük düşme oranlarının takım düzeyinde nasıl büyüdüğü ve karantina eşiğinin kırmızı koşum ile kaçan gerçek hata arasında kurduğu takas.

İçindekiler

Son üç ders aynı gerçeği ayrı yüzlerinden gördü: bekleme politikası düşme oranını değiştiriyordu, aygıt seçimi kusur kapsamasını, eşik seçimi yanlış alarmı. Üçü de tek bir sorunun parçalarıdır — uçtan uca test, alt seviyelerdeki testlerin taşımadığı bir kararsızlık taşır.

Kırılgan testin tanımı, düşme oranı ve karantina Birim Testi ve Test Odaklı Geliştirme kursunda kurulmuştu. Burada ölçek değişiyor. Orada tek bir testin düşme oranı ölçülüyordu; burada kırk testlik bir takımın koşumu ölçülür ve iki yeni soru çıkar: düşüşler hangi nedene ne oranda dağılıyor, ve kırılgan testleri karantinaya almak kaçan hatayı ne kadar artırıyor.

Takım Ölçeğinde Dağılım

Model girdisi açıkça yazılır. KY1 — kırk uçtan uca test. On ikisi dar zaman aşımlı beklemeye açık (koşum başına 0,02), altısı önceki testin bıraktığı duruma bağlı (0,01), sekizi aynı üye ve kitap kaydını paylaşıyor (0,015), beşi ağ üzerinden çok sayıda çağrı yapıyor (çağrı başına 0,005 takılma olasılığı ve altı çağrı, yani 0,0296), dokuzu kararlı. Gerçek bir gerileme koşumların dörtte birinde bulunur ve kırk koruma sınıfından birine düşer. Nedenlerin oranları mekanizmadan gelir: ağ nedeni çağrı sayısıyla büyür, paylaşılan veri nedeni aynı kaydı kullanan test sayısıyla.

// takim.mjs — kirk uctan uca testin iki yuz kosumu ve karantina taramasi
function uretec(tohum) {
  let durum = (tohum * 2654435761) % 2147483647;
  return () => {
    durum = (durum * 48271) % 2147483647;
    return durum / 2147483647;
  };
}

const testler = [];
const ekle = (adet, neden, oran) => {
  for (let i = 0; i < adet; i += 1) testler.push({ neden, oran, dusus: 0 });
};
ekle(12, 'bekleme', 0.02);
ekle(6, 'sira', 0.01);
ekle(8, 'paylasilan veri', 0.015);
ekle(5, 'ag', 1 - (1 - 0.005) ** 6);
ekle(9, 'kararli', 0);

const KOSUM = 200;
const rastgele = uretec(47);
for (let k = 0; k < KOSUM; k += 1) {
  for (const t of testler) if (rastgele() < t.oran) t.dusus += 1;
}

const s = (n, g) => String(n).padStart(g);
console.log(`${'neden'.padEnd(17)}${s('test', 6)}${s('dusus', 7)}${s('test basina oran', 18)}`);
for (const neden of ['bekleme', 'sira', 'paylasilan veri', 'ag', 'kararli']) {
  const grup = testler.filter((t) => t.neden === neden);
  const dusus = grup.reduce((a, t) => a + t.dusus, 0);
  const oran = ((dusus / (grup.length * KOSUM)) * 100).toFixed(2);
  console.log(`${neden.padEnd(17)}${s(grup.length, 6)}${s(dusus, 7)}${s(`%${oran}`, 18)}`);
}

const GERCEK_HATA = 0.25;
const senaryo = (esik) => {
  const karantinada = testler.map((t) => (t.dusus / KOSUM) * 100 > esik);
  const rastgele2 = uretec(53);
  let kirmizi = 0;
  let kacan = 0;
  for (let k = 0; k < KOSUM; k += 1) {
    let dusen = false;
    testler.forEach((t, i) => {
      if (karantinada[i] === false && rastgele2() < t.oran) dusen = true;
    });
    if (dusen) kirmizi += 1;
    if (rastgele2() < GERCEK_HATA) {
      const koruyan = Math.floor(rastgele2() * testler.length);
      if (karantinada[koruyan]) kacan += 1;
    }
  }
  return { adet: karantinada.filter(Boolean).length, kirmizi, kacan };
};

console.log(`${'karantina esigi'.padEnd(17)}${s('karantinada', 13)}${s('kirmizi kosum', 15)}${s('kacan gercek hata', 19)}`);
for (const esik of [100, 2.5, 1.5, 0.5]) {
  const r = senaryo(esik);
  const ad = esik === 100 ? 'yok' : `%${esik.toFixed(1)}`;
  console.log(`${ad.padEnd(17)}${s(r.adet, 13)}${s(`%${((r.kirmizi / KOSUM) * 100).toFixed(1)}`, 15)}`
    + `${s(`%${((r.kacan / KOSUM) * 100).toFixed(1)}`, 19)}`);
}
neden              test  dusus  test basina oran
bekleme              12     37             %1.54
sira                  6     10             %0.83
paylasilan veri       8     32             %2.00
ag                    5     28             %2.80
kararli               9      0             %0.00
karantina esigi    karantinada  kirmizi kosum  kacan gercek hata
yok                          0          %47.5               %0.0
%2.5                         8          %36.0               %4.5
%1.5                        13          %26.5               %9.5
%0.5                        25           %9.0              %16.5

Birinci tablonun tek tek satırları zararsız görünür: en kırılgan grup bile yüz koşumda üç kez düşüyor. İkinci tablonun ilk satırı bu izlenimi bozar — karantina yokken koşumların yüzde kırk yedi virgül beşi kırılganlık yüzünden kırmızı. Aradaki büyüme çarpımdan gelir: bir koşumun temiz geçmesi için kırk testin kırkının da geçmesi gerekir, ve tek tek geçme olasılıkları çarpılınca yüzde kırk üç virgül altı yedilik bir kırmızı beklentisi çıkar. İki yüz koşumda ölçülen yüzde kırk yedi virgül beş bu beklentinin örnekleme dalgalanmasıdır.

Bu, uçtan uca ölçeğin birim ölçekten ayrıldığı yerdir. Yüzde iki düşme oranı tek bir birim testinde katlanılabilir bir kusurdur; kırk testlik bir uçtan uca takımda ise her ikinci koşumu kırmızıya çeviren bir sistem özelliğidir. Ve düşüşlerin nedenleri sabit değildir: ölçümdeki en büyük pay ağ ve paylaşılan veridir, ikisi de tek bir testin içinde düzeltilemez — biri çağrı sayısıyla, öteki düzeneğin ortaklığıyla ilgilidir.

Karantinanın İki Yüzü

İkinci tablonun kalan satırları karantina eşiğini tarar. Eşik düştükçe karantinaya alınan test sayısı artar, kırmızı koşum oranı düşer ve kaçan gerçek hata oranı yükselir. Yüzde iki buçuk eşiği sekiz testi ana koşumdan çıkarıyor: kırmızı koşum yüzde kırk yedi virgül beşten yüzde otuz altıya iniyor, buna karşılık koşumların yüzde dört buçuğunda gerçek bir gerileme kimseye görünmeden geçiyor. Yarım yüzde eşiği takımın dörtte birini karantinaya alıyor; sinyal neredeyse temiz — kırmızı koşum yüzde dokuz — ama koşumların yüzde on altı buçuğu bir gerilemeyi taşıyıp yeşil dönüyor.

Karantina bu yüzden bir çözüm değil, bir takastır: gürültüyü kapsama karşılığında satın alır. Kararın ölçüsü de tabloda görünür — hangi eşik seçilirse seçilsin, kaçan hata oranı karantinaya alınan testlerin payına yaklaşır.

Bir ayrıntı daha var. Karantina kararı, gerçek düşme oranına değil, iki yüz koşumda ölçülen orana bakar. Ölçülen değerler modeldeki gerçek değerlerden sapıyor: bekleme grubunun gerçek oranı yüzde iki, ölçülen yüzde bir virgül elli dört. Örneklem küçüldükçe bu sapma büyür ve karantina listesine kararlı testler girmeye, kırılgan testler girmemeye başlar.

Yeşil Koşum, Duran Kusur

Takasın somut hâli tek bir koşumda görülür. Ödünç akışının dört testi var; ikincisi ödünç sınırı aşıldığında üyeye uyarı gösterildiğini sınıyor. Akışın birinci sürümü reddedilen isteğe doğru durum kodunu veriyor, ama uyarıyı taşımıyor.

// akis.mjs — surum 1: odunc isteginin uctan uca gorunen sonucu
export const SINIR = 5;

export function oduncIste(uye) {
  if (uye.acikOdunc >= SINIR) return { durum: 409, uyari: null };
  return { durum: 201, uyari: null };
}

export const kartDurumu = (sonuc) => (sonuc.durum === 201 ? 'oduncte' : 'rafta');
// karantina.mjs — surum 1: karantinadaki test adlari
export const karantina = new Set();
// takim.test.mjs — uctan uca takimin dort testi, karantina listesine bakar
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { oduncIste, kartDurumu } from './akis.mjs';
import { karantina } from './karantina.mjs';

const sinar = (ad, govde) => test(ad, { skip: karantina.has(ad) }, govde);

sinar('uygun istek onaylanir', () => {
  assert.equal(oduncIste({ acikOdunc: 1 }).durum, 201);
});

sinar('odunc siniri asildiginda uyari gosterilir', () => {
  const sonuc = oduncIste({ acikOdunc: 5 });

  assert.equal(sonuc.durum, 409);
  assert.equal(sonuc.uyari, 'odunc-siniri-asildi');
});

sinar('onaydan sonra kart oduncte gorunur', () => {
  assert.equal(kartDurumu(oduncIste({ acikOdunc: 1 })), 'oduncte');
});

sinar('reddedilen istekte kart rafta kalir', () => {
  assert.equal(kartDurumu(oduncIste({ acikOdunc: 5 })), 'rafta');
});
node --test --test-reporter=tap takim.test.mjs | grep -E '^ *(ok|not ok|# (tests|pass|fail|skipped))'
ok 1 - uygun istek onaylanir
not ok 2 - odunc siniri asildiginda uyari gosterilir
ok 3 - onaydan sonra kart oduncte gorunur
ok 4 - reddedilen istekte kart rafta kalir
# tests 4
# pass 3
# fail 1
# skipped 0

İkinci test kusuru yakaladı. Şimdi bu testin ağ üzerinden çok sayıda çağrı yaptığı ve ölçümde kırılgan çıktığı varsayılsın; kural gereği karantinaya alınır.

// karantina.mjs — surum 2: kirilgan bulunan test karantinaya alindi
export const karantina = new Set(['odunc siniri asildiginda uyari gosterilir']);
node --test --test-reporter=tap takim.test.mjs | grep -E '^ *(ok|not ok|# (tests|pass|fail|skipped))'
ok 1 - uygun istek onaylanir
ok 2 - odunc siniri asildiginda uyari gosterilir # SKIP
ok 3 - onaydan sonra kart oduncte gorunur
ok 4 - reddedilen istekte kart rafta kalir
# tests 4
# pass 3
# fail 0
# skipped 1

Kod değişmedi, kusur duruyor, koşum yeşil. Kaçan sınıf budur ve tabloda ölçülen “kaçan gerçek hata” sütununun tek bir örneğidir: karantinaya alınan her test, koruduğu kusur sınıfını da beraberinde götürür. Atlanan testin çıktıda görünür kalması bu yüzden önemlidir — yeşil koşumun kaç testi atladığı okunmazsa, takas görünmez olur.

Disiplinin iki parçası vardır ve ikisi de bu koşumda tamamlanır: kırılganlığın kaynağı düzeltilir (burada ağ çağrılarının sayısı ve zaman aşımı), sonra test karantinadan çıkarılır. Aşağıda ikisi birlikte yapılıyor: akış uyarıyı taşır hâle getiriliyor ve liste boşaltılıyor.

// akis.mjs — surum 2: reddedilen istek uyariyi da tasiyor
export const SINIR = 5;

export function oduncIste(uye) {
  if (uye.acikOdunc >= SINIR) return { durum: 409, uyari: 'odunc-siniri-asildi' };
  return { durum: 201, uyari: null };
}

export const kartDurumu = (sonuc) => (sonuc.durum === 201 ? 'oduncte' : 'rafta');
// karantina.mjs — surum 3: kirilganlik kaynagi giderildi, liste bosaltildi
export const karantina = new Set();
node --test --test-reporter=tap takim.test.mjs | grep -E '^ *(ok|not ok|# (tests|pass|fail|skipped))'
ok 1 - uygun istek onaylanir
ok 2 - odunc siniri asildiginda uyari gosterilir
ok 3 - onaydan sonra kart oduncte gorunur
ok 4 - reddedilen istekte kart rafta kalir
# tests 4
# pass 4
# fail 0
# skipped 0

Karantina kaydının bir sahibi, bir gerekçesi ve bir çıkış ölçütü olmadığında kalıcılaşır; kalıcı karantina, tabloların son satırındaki duruma — temiz sinyal ve yüzde on altı buçuk kaçan hata — yavaşça yaklaşmaktır.

Bedelin koşuma bağlı yanı bu koşumda küçüktür: dört test 30,7 milisaniye sürdü. Koşumdan bağımsız sayılar ölçümdedir — kırk test iki yüz koşumda sekiz bin test koşumu üretti, ve her karantina kaydı bir bakım borcu, bir kusur sınıfı kaybı demektir.

Özet

  • Uçtan uca ölçekte kırılganlık tek testin değil takımın özelliğidir: koşum başına yüzde iki dolayında düşen kırk test, koşumların yüzde kırk yedi virgül beşini kırmızıya çevirdi.
  • Ölçülen düşüşlerin en büyük payları ağ (%2,80) ve paylaşılan veri (%2,00) nedenlerindeydi; ikisi de tek bir testin içinde düzeltilemez.
  • Karantina eşiği düştükçe kırmızı koşum azalır ve kaçan gerçek hata artar: yüzde iki buçuk eşiğinde %36,0 ve %4,5; yarım yüzde eşiğinde %9,0 ve %16,5.
  • Karantina kararı gerçek orana değil ölçülen orana dayanır; iki yüz koşumluk örneklem bekleme grubunun gerçek yüzde ikilik oranını yüzde bir virgül elli dört gösterdi.
  • Tek koşumluk örnek takası somutlaştırdı: karantinaya alınan test atlandığında kusur yerinde dururken koşum yeşil döndü.

Sonraki Adım

Buradaki bütün testler tek tek koştu: kırk test sırayla, biri bitince öteki. Karantina tartışmasının arkasında hep aynı sayı duruyordu — koşum süresi. Kırılgan bir test karantinaya alınmak yerine yeniden koşturulabilirdi, kaçan hatayı azaltmak için daha çok vaka eklenebilirdi; ikisi de aynı bütçeye, geçen zamana çarpar. Bu da sorunun kendisini değiştirir: testlerin sırayla koşması bir zorunluluk mudur, yoksa bir seçim midir? Sıradaki konu bu soruyu koşum düzeninin kendisi üzerinden ele alır ve süreyi kısaltmanın karşılığında neyin, hangi yalıtım gereksiniminin ödendiğini ölçer.

İ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