İçeriğe geç
academia.sh

Ders 23 / 27

Altyapı Testi

Altyapı değişikliğinin üç seviyede doğrulanması: birim, sözleşme ve uçtan uca doğrulamanın aynı on beş kusurluk kümede koşturulması, her seviyenin tuttuğu, yalnız kendisinin tuttuğu, süresi, yarattığı kaynak ve kurgu birim cinsinden maliyeti, üç seviyenin de kaçırdığı ortak boşluğun adlandırılması ve temizlenmeyen test kaynaklarının bıraktığı artık ile sızan maliyetin sayılması.

İçindekiler

Politika taraması kaydın kabul edilebilirliğini sınadı ve iki katmanda da kararsız kalan bir kural bıraktı: değeri uygulama anında atanan bir alan. O kararsızlık tesadüf değil, sınırdır — tarama kaydı okur, koşan altyapıyı görmez. Kaynak gerçekten açılıyor mu, diski bağlanıyor mu, kuyruğa yazılan ileti veri deposuna ulaşıyor mu: bunların hiçbiri metinde yazmaz.

Altyapı testi bu soruları sorar ve yazılım tarafındaki test seviyeleriyle aynı adları taşır — birim, sözleşme, uçtan uca — ama hizalama adlarda değil, neyin yaratıldığındadır: burada en üst seviye gerçek kaynak açar, gerçek ücret işletir ve arkasında iz bırakır. Bu ders üç seviyeyi aynı kusur kümesinde koşturur ve her biri için üç şey sayar: tuttuğu kusur, süresi ve maliyeti. Sonra iki sayı daha gelir: üç seviyenin birden kaçırdığı ortak boşluk ve testin arkasında bıraktığı temizlenmemiş kaynak. Through-line bölgesel ölçüm ağıdır ve kurgudur.

Kusur Kümesi ve Üç Seviye

AD13 — bilinen kusur kümesi on beş kusurdur, elle işaretlenmiştir ve her kusur bir katmana bağlıdır: tanim (tek kaynağın tanımında görünür), iliski (ancak iki kaynak karşılaştırılınca görünür), kosum (ancak kaynak koşarken görünür), degisim (ancak var olan altyapı üzerine uygulanınca görünür). AD14 — birim doğrulaması tek kaynağın ya da modülün tanımını kaynak yaratmadan sınar; sözleşme doğrulaması plan üzerinde koşar ve yalnız arayüz alanlarına bakar. AD15 — uçtan uca doğrulama gerçek kaynak yaratır ama yalnız ana akışı koşturur; yan akışta kalan kusur ona görünmez.

// seviye.mjs — ayni kusur kumesi uc dogrulama seviyesinde kosturulur (model)

// [kod, kusur, katman (nerede gorunur), alan, yol (uctan uca akisinda ana mi yan mi)]
const KUSUR = [
  ["D01", "makine diski 10 GB, toplayici yaziyor", "tanim", "disk_gb", "ana"],
  ["D02", "kuyruk saklamasi 0 saat", "tanim", "saklama", "yan"],
  ["D03", "arsiv sinifi sicak birakilmis", "tanim", "sinif", "yan"],
  ["D04", "toplayici boyutu kucuk", "tanim", "boyut", "ana"],
  ["D05", "sahip etiketi yazilmamis", "tanim", "sahip", "yan"],
  ["D06", "makine bolgesi ag bolgesiyle uyusmuyor", "iliski", "bolge", "ana"],
  ["D07", "kuyruk ile veri deposu ayri bolgede", "iliski", "bolge", "yan"],
  ["D08", "modul cikti adi tuketicinin bekledigi degil", "iliski", "cikti", "ana"],
  ["D09", "yedek penceresi bakim penceresiyle cakisiyor", "iliski", "pencere", "yan"],
  ["D10", "guvenlik kurali toplayici trafigini kesiyor", "kosum", "kural", "ana"],
  ["D11", "disk baglanmiyor, baglama noktasi yok", "kosum", "baglama", "ana"],
  ["D12", "kimlik yetkisi eksik, depoya yazilamiyor", "kosum", "yetki", "ana"],
  ["D13", "alan degisikligi kaynagi yeniden olusturuyor, veri gidiyor", "degisim", "disk_gb", "ana"],
  ["D14", "yerinde guncelleme sirasinda kesinti oluyor", "degisim", "boyut", "ana"],
  ["D15", "kayit disi elle degisikligin uzerine yaziliyor", "degisim", "kural", "ana"],
].map(([kod, ne, katman, alan, yol]) => ({ kod, ne, katman, alan, yol }));

// AD16: uctan uca dogrulama gercek kaynak yaratir; adet, yaratma suresi ve saatlik ucret kurgudur
const KAYNAK = [["ag", 2, 20, 0], ["makine", 3, 45, 4], ["kuyruk", 1, 30, 1],
  ["veri_deposu", 1, 180, 12], ["nesne_deposu", 1, 15, 1]];
const ADET = KAYNAK.reduce((s, [, n]) => s + n, 0);
const YARATMA = KAYNAK.reduce((s, [, n, y]) => s + n * y, 0);
const SAATLIK = KAYNAK.reduce((s, [, n, , u]) => s + n * u, 0);
const UCTAN_UCA_SURE = YARATMA + 60 + YARATMA / 2; // yaratma + akis dogrulamasi + silme

// AD17: sozlesme dogrulamasi yalniz arayuz alanlarina bakar
const SOZLESME_ALANI = ["bolge", "cikti", "disk_gb"];
const SEVIYE = [
  ["birim", (k) => k.katman === "tanim", 12, 0, 0],
  ["sozlesme", (k) => k.katman === "iliski" ||
    (k.katman === "tanim" && SOZLESME_ALANI.includes(k.alan)), 45, 0, 0],
  ["uctan uca", (k) => k.katman !== "degisim" && k.yol === "ana",
    UCTAN_UCA_SURE, ADET, (SAATLIK * UCTAN_UCA_SURE) / 3600],
];

const tuttugu = SEVIYE.map(([, f]) => KUSUR.filter(f).map((k) => k.kod));
console.log(`${"seviye".padEnd(11)}${"tuttugu".padStart(9)}${"yalniz kendisi".padStart(16)}` +
  `${"kacirdigi".padStart(11)}${"yaratilan kaynak".padStart(18)}${"sure".padStart(9)}` +
  `${"maliyet (kurgu birim)".padStart(23)}`);
SEVIYE.forEach(([ad, , sure, kaynak, ucret], j) => {
  const yalniz = tuttugu[j].filter((k) => tuttugu.every((t, o) => o === j || !t.includes(k)));
  console.log(`${ad.padEnd(11)}${`${tuttugu[j].length}/${KUSUR.length}`.padStart(9)}` +
    `${String(yalniz.length).padStart(16)}${String(KUSUR.length - tuttugu[j].length).padStart(11)}` +
    `${String(kaynak).padStart(18)}${`${sure} sn`.padStart(9)}${ucret.toFixed(2).padStart(23)}`);
});

const hepsi = new Set(tuttugu.flat());
const kacan = KUSUR.filter((k) => !hepsi.has(k.kod));
console.log(`\nuc seviye birlikte ${KUSUR.length} kusurun ${hepsi.size} tanesini tutar; ` +
  `toplam sure ${SEVIYE.reduce((s, [, , t]) => s + t, 0)} sn, ` +
  `maliyet ${SEVIYE.reduce((s, [, , , , u]) => s + u, 0).toFixed(2)} kurgu birim`);
console.log(`\nuc seviyenin de kacirdigi ${kacan.length} kusur (katman: ${kacan[0].katman}):`);
for (const k of kacan) console.log(`  ${k.kod}  ${k.ne}`);
console.log(`\nseviye basina kusur maliyeti: ` + SEVIYE.map(([ad, , sure, , ucret], j) =>
  `${ad} ${(sure / tuttugu[j].length).toFixed(1)} sn/kusur` +
  (ucret ? ` ve ${(ucret / tuttugu[j].length).toFixed(2)} birim/kusur` : "")).join("; "));
seviye       tuttugu  yalniz kendisi  kacirdigi  yaratilan kaynak     sure  maliyet (kurgu birim)
birim           5/15               3         10                 0    12 sn                   0.00
sozlesme        5/15               2         10                 0    45 sn                   0.00
uctan uca       7/15               3          8                 8   660 sn                   4.77

uc seviye birlikte 15 kusurun 12 tanesini tutar; toplam sure 717 sn, maliyet 4.77 kurgu birim

uc seviyenin de kacirdigi 3 kusur (katman: degisim):
  D13  alan degisikligi kaynagi yeniden olusturuyor, veri gidiyor
  D14  yerinde guncelleme sirasinda kesinti oluyor
  D15  kayit disi elle degisikligin uzerine yaziliyor

seviye basina kusur maliyeti: birim 2.4 sn/kusur; sozlesme 9.0 sn/kusur; uctan uca 94.3 sn/kusur ve 0.68 birim/kusur

Kimin Neyi Tuttuğu

Üç seviye birlikte on beş kusurun on ikisini tutar. Tek başına bakıldığında hiçbiri yarıyı geçmez: birim beş, sözleşme beş, uçtan uca yedi. Asıl bilgi “yalnız kendisi” sütunundadır, çünkü bir seviyeyi hattan çıkarmanın bedeli orada yazar. Birim doğrulaması çıkarılırsa üç kusur kimsesiz kalır — kuyruğun sıfır saklaması, arşivin yanlış sınıfı, yazılmamış sahip etiketi. Üçü de tek bir kaynağın tanımında, göz önünde durur ve üçü de yan akıştadır; uçtan uca doğrulama gerçek kaynağı yaratır ama o yollardan hiç geçmez.

Sözleşme doğrulamasının yalnız kendisine ait iki kusuru da aynı nedenle oradadır: kuyruk ile veri deposunun ayrı bölgede olması ve yedek penceresinin bakım penceresiyle çakışması ancak iki kaynak yan yana konunca görünür, ve ikisi de ana akışta değildir. Sözleşme doğrulamasının değeri karşılaştırmadadır, koşumda değil; bu yüzden kaynak yaratmadan bir uçtan uca testin göremeyeceğini görür.

Örtüşme de sayılabilir. Yakalanan on iki kusurdan biri — makinenin on gigabaytlık diski — üç seviyenin üçüne birden takılır: tanımda yazılıdır, sözleşme alanlarından biridir ve ana akışta koşarken de kendini gösterir. Üçü de aynı kusuru raporlar, ekip aynı şeyi üç kez okur. Üç kusur iki seviyeye takılır, geri kalan sekizi tek bir seviyenin işidir. Bir hattın kapı sırasını belirleyen şey tam da bu dağılımdır.

Uçtan uca doğrulamanın üç kusuru ise ancak koşum katmanında vardır: kesen bir güvenlik kuralı, bağlanmayan bir disk, eksik bir yetki. Bunların hiçbiri kayıtta yanlış yazılmamıştır — kayıt doğrudur, gerçek farklıdır. Bu, kursun ölçü ekseninin en açık hâlidir: metin ile gerçek arasındaki fark ancak gerçek çalıştırılınca ölçülür.

Süre ve Maliyet

Son üç sütun aynı kapsamın fiyatıdır. Birim doğrulaması on iki saniyede biter, hiç kaynak yaratmaz, ücreti sıfırdır. Sözleşme doğrulaması kırk beş saniye sürer — plan üretimini bekler — ama yine hiçbir şey yaratmaz. Uçtan uca doğrulama sekiz gerçek kaynak açar, altı yüz altmış saniye sürer ve 4,77 kurgu birim tutar; süresinin dörtte üçü yaratma ve silmedir, doğrulamanın kendisi altmış saniyedir.

Kusur başına bakıldığında fark daha keskindir: birim 2,4 saniye/kusur, sözleşme 9,0 saniye/kusur, uçtan uca 94,3 saniye ve 0,68 birim/kusur. Uçtan uca doğrulama bir kusuru birim doğrulamasının kırk katı sürede tutar. Bu, “uçtan uca kötüdür” demek değildir — tuttuğu üç kusuru başka hiçbir seviye tutamaz. Söylediği şey, her seviyenin kendi katmanında en ucuz olduğu: aynı kusuru iki seviyede sınamak, kusuru pahalı olanda ikinci kez ödemektir.

Sıra da bu tablodan okunur. Birim doğrulaması on iki saniyede beş kusuru eler; ondan sonra koşan uçtan uca doğrulama o beşini artık aramaz. Ters sıranın bedeli de hesaplanabilir: uçtan uca önce koşarsa, birim doğrulamasının on iki saniyede bulacağı bir kusur için sekiz gerçek kaynak yaratılmış, altı yüz altmış saniye beklenmiş ve 4,77 birim ödenmiş olur. Aynı kusurun bedeli, hangi kapıda yakalandığına göre kırk kata kadar değişir.

Üç Seviyenin Ortak Boşluğu

Kaçan üç kusurun ortak adı çıktıda yazılıdır: değişim katmanı. Üç seviye de doğrulamayı sıfırdan kurulan temiz bir ortamda yapar. Gerçek değişiklik ise sıfırdan kurulmuş bir ortama değil, var olan altyapının üzerine uygulanır — ve kusurlar tam orada doğar: bir alanın değişmesi kaynağı yeniden oluşturur ve içindeki veri gider; yerinde bir güncelleme kesinti üretir; kayıt dışı yapılmış elle bir değişikliğin üzerine yazılır.

Üçünü de sınamak boş ortamda kurulan bir testle olanaksızdır, çünkü sınanacak şey geçmişin kendisidir: kaynağın hâlihazırda taşıdığı veri, hâlihazırda aldığı trafik, hâlihazırda üzerinde yapılmış kayıt dışı değişiklik. Bu boşluğu kapatan şey bir test seviyesi değil, uygulamadan önce okunan plandır — hangi kalemin yeniden oluşturulacağını orada yazar. Kaydın kapsamadığı elle değişiklik ise ne testte ne planda görünür; onun tek karşılığı sapmanın ayrıca ölçülmesidir.

Temizlenmeyen Kaynak

Uçtan uca doğrulamanın tablodaki 4,77 birimlik maliyeti, temizleme adımının her koşumda başarılı olduğunu varsayar. Silme de yaratma gibi bir uygulama adımıdır ve o da başarısız olabilir: hat zaman aşımına uğrar, bir kaynak başka bir kaynağa bağlı olduğu için silinemez, koşum yarıda kesilir.

// artik.mjs — uctan uca dogrulamanin biraktigi artik kaynak ve sizan maliyet (model)

// AD18: otuz gun boyunca gunde bir uctan uca kosum; temizleme adimi bes kosumdan birinde
// basarisiz olur ve basarisiz kosumda her kaynak yarim olasilikla ayakta kalir (kurgu)
const TOHUM = 20260215;
let durum = TOHUM;
const rast = () => (durum = (durum * 48271) % 2147483647) / 2147483647; // carpim 2^53 altinda kalir

const KAYNAK = [["ag", 2, 0], ["makine", 3, 4], ["kuyruk", 1, 1], ["veri_deposu", 1, 12],
  ["nesne_deposu", 1, 1]]; // tur, adet, saatlik kurgu birim
const ORNEK = KAYNAK.flatMap(([t, n, u]) => Array.from({ length: n }, (_, i) => [`${t}-${i + 1}`, u]));
const GUN = 30, HATA = 0.2, KOSUM_UCRETI = 4.77; // 4.77: onceki blokta hesaplanan kosum maliyeti

const kalan = [];
let hatali = 0, sizan = 0;
for (let g = 1; g <= GUN; g += 1) {
  if (rast() < HATA) {
    hatali += 1;
    for (const [ad, u] of ORNEK) if (rast() < 0.5) kalan.push({ ad: `${ad}#k${g}`, u, gun: g });
  }
  sizan += kalan.reduce((s, k) => s + k.u, 0) * 24; // birikmis artik gun boyu ucret isletir
}

const amaclanan = GUN * KOSUM_UCRETI;
console.log(`${GUN} gun, ${GUN} kosum, tohum ${TOHUM}: temizleme ${hatali} kosumda basarisiz, ` +
  `${kalan.length} artik kaynak birikti`);
console.log(`\n${"artik kaynak".padEnd(20)}${"birakildigi gun".padStart(16)}` +
  `${"saatlik ucret".padStart(14)}${"ay sonuna dek ucret".padStart(21)}`);
for (const k of kalan) {
  console.log(`${k.ad.padEnd(20)}${String(k.gun).padStart(16)}${String(k.u).padStart(14)}` +
    `${String(k.u * 24 * (GUN - k.gun + 1)).padStart(21)}`);
}
console.log(`\namaclanan maliyet (${GUN} kosum x ${KOSUM_UCRETI}) ${amaclanan.toFixed(2)} birim; ` +
  `sizan maliyet ${sizan.toFixed(2)} birim; oran ${(sizan / amaclanan).toFixed(1)}x`);
const pahali = [...kalan].sort((a, b) => b.u - a.u)[0];
console.log(`ay sonundaki artik saatlik ucret ${kalan.reduce((s, k) => s + k.u, 0)} birim; ` +
  `en pahali artik ${pahali.ad} (${pahali.u} birim/saat); ` +
  `kayitta gorunen artik kaynak sayisi 0`);
30 gun, 30 kosum, tohum 20260215: temizleme 4 kosumda basarisiz, 11 artik kaynak birikti

artik kaynak         birakildigi gun saatlik ucret  ay sonuna dek ucret
ag-1#k3                            3             0                    0
kuyruk-1#k3                        3             1                  672
veri_deposu-1#k3                   3            12                 8064
nesne_deposu-1#k3                  3             1                  672
ag-2#k12                          12             0                    0
makine-3#k12                      12             4                 1824
veri_deposu-1#k12                 12            12                 5472
makine-1#k24                      24             4                  672
ag-1#k29                          29             0                    0
kuyruk-1#k29                      29             1                   48
veri_deposu-1#k29                 29            12                  576

amaclanan maliyet (30 kosum x 4.77) 143.10 birim; sizan maliyet 18000.00 birim; oran 125.8x
ay sonundaki artik saatlik ucret 47 birim; en pahali artik veri_deposu-1#k3 (12 birim/saat); kayitta gorunen artik kaynak sayisi 0

Otuz koşumun dördünde temizleme başarısız oldu ve on bir kaynak ayakta kaldı. Otuz koşumun amaçlanan maliyeti 143 kurgu birimdi; sızan maliyet 18.000 birim, yani yüz yirmi altı katı. Oranı bu kadar büyüten şey başarısızlık sayısı değil süredir: koşum on bir dakika sürer, artık kaynak ise fark edilene kadar günlerce durur. Üçüncü günün veri deposu tek başına 8.064 birim işletmiştir.

Tabloda okunacak ikinci bir şey daha var. On bir artığın yedisi üçüncü ve on ikinci günde bırakılmıştır ve sızan maliyetin neredeyse tamamını onlar üretir: üçüncü günün dört artığı 9.408 birim, on ikinci günün üç artığı 7.296 birim işletirken yirmi dokuzuncu günün üç artığı yalnız 624 birim işletir. Temizlik başarısızlığının bedeli sabit değildir, fark edilme süresiyle çarpılır; bu yüzden artık kaynağı azaltmanın yolu temizliği yüzde yüz başarılı kılmak değil, artığı erken bulmaktır.

Son satır bu kursun ölçü ekseniyle doğrudan bağlıdır: kayıtta görünen artık kaynak sayısı sıfırdır. Bu kaynakları kayıt yaratmadı, test yarattı; kaydın durumu onları içermez, kayda bakan hiç kimse onları göremez. Testin bıraktığı artık, kaydın kapsamadığı altyapının en sessiz biçimidir — ve onu bulmanın tek yolu sağlayıcıyı kayıtla karşılaştırmaktır.

Özet

  • On beş kusurluk küme üç doğrulama seviyesinde koşturuldu: birim 5, sözleşme 5, uçtan uca 7 kusur tuttu; üçü birlikte 12’sini tuttu, hiçbiri tek başına yarıyı geçmedi.
  • Yalnız kendisinin tuttuğu kusur sayısı 3, 2 ve 3’tür; sözleşme doğrulaması kaynak yaratmadan iki ilişki kusurunu tutar, uçtan uca doğrulama ise üç koşum kusurunu başka hiçbir seviyenin göremeyeceği biçimde tutar.
  • Maliyet katmanla birlikte büyür: birim 12 sn ve 0 kaynak, sözleşme 45 sn ve 0 kaynak, uçtan uca 660 sn, 8 gerçek kaynak ve 4,77 kurgu birim; kusur başına 2,4 / 9,0 / 94,3 saniye.
  • Üç seviyenin ortak boşluğu değişim katmanıdır: üçü de sıfırdan kurulan temiz ortamda koşar, oysa gerçek değişiklik var olan altyapının üzerine uygulanır (yeniden oluşturma ve veri kaybı, yerinde güncelleme kesintisi, kayıt dışı elle değişikliğin üzerine yazılması).
  • Otuz koşumda temizleme 4 kez başarısız oldu, 11 artık kaynak kaldı; amaçlanan 143 birime karşı 18.000 birim sızdı (126 kat) ve bu kaynakların kayıtta görünen sayısı sıfırdır.

Sonraki Adım

Bu dersin son iki sayısı aynı yere bakıyor: uçtan uca doğrulamanın koşum maliyeti ve artık kaynağın sızan maliyeti. İkisi de değişikliğin parasal yüzüdür ve ikisi de ancak olan bitince sayıldı. Oysa aynı soru uygulamadan önce sorulabilir: bu değişiklik uygulanırsa aylık gider ne kadar artar? Sonraki ders plan üzerinden değişiklik başına tahmin üretir ve gerçekleşenle karşılaştırır — hangi kalem sabit birim fiyatlı olduğu için tahmin edilebiliyor, hangi kalem kullanıma bağlı olduğu için edilemiyor, tahmin hatası nasıl dağılıyor ve “tahmin şu kadarı aşarsa dur” biçiminde bir eşik kuralı bilinen değişiklik kümesinde kaç değişikliği gereksiz yere durduruyor.

İ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