İçeriğe geç
academia.sh

Ders 19 / 27

Modül Kayıtları

Paylaşılan bir modül kaydından çekilen üç modül, dokuz tanım ve dokuz yayınla on haftalık bir dönem iki düzende koşturulur; sürümü sabitlenmiş ve sabitlenmemiş düzenler beklenmeyen değişiklik, kırılan tanım ve düzeltme satırı sayısıyla karşılaştırılır. Sabitlemenin kendi bedeli de sayılır.

İçindekiler

Bir önceki ders modülü tek elin altında tuttu: yazan da kullanan da aynı taraftı, sürüm yükseltmesi bir dosya düzenlemesiydi. Modül kaydı bu ilişkiyi keser. Kayıt, sürümlenmiş modül metinlerini tanımların dışında tutan paylaşılan bir depodur; burada bir ürün ya da hizmet olarak değil, tür olarak anılır. Modülü yazan taraf yayın yapar, kullanan taraf çeker, ve aradaki tek bağ tanımda yazılı bir addır.

O adın yanında bir sürüm yazıp yazmamak bu dersin ölçü ikilisidir. Sabitlenmemiş düzende tanım yalnız modülün adını yazar ve uygulama anında kayıttaki en yeni sürüm çekilir. Sabitlenmiş düzende tanım sürümü de yazar ve o sürüm birileri eliyle değiştirene kadar durur. Aynı yayın akışı ve aynı uygulama takvimi iki düzende de koşturulur; ölçülen şey aradaki farktır.

Ölçüm yine bölgesel ölçüm ağı üzerindedir: su sayacı okumalarını toplayan kurgu bir yazılım. Gerçek altyapı sağlanmaz, gerçek bir kayıt hizmetine bağlanılmaz; ölçülen şey node ile kurulmuş bir modeldir.

DM31. Kayıtta üç modül ve on iki sürüm vardır; her sürüm zorunlu girdileri, varsayılanlı girdileri ve gövdesiyle tek satırda yazılıdır. DM32. Dönem on haftadır ve dokuz yayın önceden yazılıdır: dört yama, iki küçük, üç kırıcı. Rastgelelik yoktur. DM33. Dokuz tanım birer modül çağırır; uygulama haftaları önceden yazılıdır ve dönem boyunca on sekiz uygulama koşar. DM34. Sabitlenmemiş düzen uygulama anındaki en yeni sürümü, sabitlenmiş düzen tanımda yazılı sürümü çeker. DM35. Kırıcı yayın uygulamayı durdurur; eksik zorunlu girdi o anda tanıma yazılır ve satır sayılır. Düzeltme kuralı DUZELTME içinde yazılıdır. DM36. Beklenmeyen değişiklik, tanım metnine o uygulamada dokunulmadığı hâlde çıktının bir öncekinden farklı olmasıdır. Sabitlenmiş düzende iki tanım dönem içinde elle yükseltilir.

Kayıt, Yayın Akışı ve Tanımlar

// kayit.mjs — modul kaydi (tur olarak): uc modul, on iki surum, dokuz yayin ve dokuz tuketici tanim.
export const MODUL = {                                 // surum -> "zorunlu | varsayilanli | govde"
  "toplama-noktasi": {
    "1.0.0": "kaynak-blok | sayi=6 | kume sayi=$sayi; ag blok=$kaynak-blok",
    "1.1.0": "kaynak-blok | sayi=6,izleme=acik | kume sayi=$sayi; ag blok=$kaynak-blok; izleme durum=$izleme",
    "1.1.1": "kaynak-blok | sayi=6,izleme=acik | kume sayi=$sayi; ag blok=$kaynak-blok yon=giris; izleme durum=$izleme",
    "2.0.0": "ag-blogu | sayi=6,izleme=acik | kume sayi=$sayi; ag blok=$ag-blogu yon=giris; izleme durum=$izleme",
    "2.0.1": "ag-blogu | sayi=6,izleme=acik | kume sayi=$sayi tip=toplayici; ag blok=$ag-blogu yon=giris; izleme durum=$izleme" },
  "olcum-kuyrugu": {
    "1.0.0": "ad | bekleme=30 | kuyruk ad=$ad bekleme=$bekleme",
    "1.0.1": "ad | bekleme=30 | kuyruk ad=$ad bekleme=$bekleme; olu-mektup ad=olu-$ad",
    "1.1.0": "ad | bekleme=30,tavan=50000 | kuyruk ad=$ad bekleme=$bekleme tavan=$tavan; olu-mektup ad=olu-$ad",
    "2.0.0": "ad,bolge | bekleme=30,tavan=50000 | kuyruk ad=$ad bekleme=$bekleme tavan=$tavan bolge=$bolge; olu-mektup ad=olu-$ad" },
  "saha-agi": {
    "1.0.0": "kapi |  | ag-kurali kapi=$kapi",
    "2.0.0": "kapi,yon |  | ag-kurali kapi=$kapi yon=$yon",
    "2.0.1": "kapi,yon |  | ag-kurali kapi=$kapi yon=$yon kayit=acik" } };

export const YAYIN = ("1 olcum-kuyrugu 1.0.1 yama|2 toplama-noktasi 1.1.0 kucuk|3 saha-agi 2.0.0 kirici|" +
  "4 toplama-noktasi 1.1.1 yama|5 olcum-kuyrugu 1.1.0 kucuk|6 toplama-noktasi 2.0.0 kirici|" +
  "7 olcum-kuyrugu 2.0.0 kirici|8 toplama-noktasi 2.0.1 yama|9 saha-agi 2.0.1 yama")
  .split("|").map((s) => s.split(" ")).map(([h, m, s, t]) => [+h, m, s, t]);

export const TANIM = {                                 // "modul | gecilen | sabit surum | uygulama haftalari"
  "kuzey-nokta": "toplama-noktasi | kaynak-blok=10.20.0.0/16 sayi=4 | 1.0.0 | 2,6,9",
  "bati-nokta": "toplama-noktasi | kaynak-blok=10.30.0.0/16 | 1.0.0 | 3,7",
  "dogu-nokta": "toplama-noktasi | kaynak-blok=10.40.0.0/16 sayi=8 | 1.0.0 | 1,5,10",
  "guney-nokta": "toplama-noktasi | kaynak-blok=10.50.0.0/16 | 1.0.0 | 8",
  "kuzey-kuyruk": "olcum-kuyrugu | ad=kuzey-okuma | 1.0.0 | 2,8",
  "bati-kuyruk": "olcum-kuyrugu | ad=bati-okuma bekleme=60 | 1.0.0 | 4,9",
  "merkez-kuyruk": "olcum-kuyrugu | ad=merkez-okuma | 1.0.0 | 6,10",
  "saha-giris": "saha-agi | kapi=8080 | 1.0.0 | 4,10",
  "laboratuvar-giris": "saha-agi | kapi=9443 | 1.0.0 | 5" };
export const YUKSELT = [[7, "bati-nokta", "1.1.1"], [9, "kuzey-kuyruk", "1.1.0"]];   // sabit duzende elle
export const DUZELTME = {                              // kirici yayindan sonra tanima yazilan satir
  "ag-blogu": (a) => a["kaynak-blok"], yon: () => "giris", bolge: (a) => a.ad.split("-")[0] };

Üç modülün on iki sürümü yayın akışıyla birlikte okunur. toplama-noktasi altıncı haftada zorunlu girdisinin adını ag-blogu’na çevirir, saha-agi üçüncü haftada yon diye yeni bir zorunlu girdi ister, olcum-kuyrugu yedinci haftada bolge ister. Üçü de kırıcı yayındır ve üçünün de bedeli kaydı kullanan tanımlarda çıkar.

İki Düzen, Aynı On Hafta

// donem.mjs — ayni yayin akisi ve ayni uygulama takvimi iki duzende kosturulur; fark sayilir.
import { MODUL, YAYIN, TANIM, YUKSELT, DUZELTME } from "./kayit.mjs";

const kv = (s) => Object.fromEntries(s.trim() ? s.trim().split(/[ ,]+/).map((x) => x.split("=")) : []);
const T = Object.fromEntries(Object.entries(TANIM).map(([t, s]) => {
  const [m, g, p, h] = s.split(" | ");
  return [t, { m, g: kv(g), p, h: h.split(",").map(Number) }];
}));
const coz = (s) => { const [z, v, b] = s.split(" | ");
  return { zor: z.trim() ? z.trim().split(",") : [], vars: kv(v), govde: b.split("; ") }; };
const enYeni = (m, h) => (YAYIN.filter((y) => y[1] === m && y[0] <= h).at(-1) ?? [, , "1.0.0"])[2];
const uret = (mv, a) => mv.govde.map((l) => l.replace(/\$([\w-]+)/g, (_, x) => a[x])).join("; ");
const fark = (a, b) => {                               // iki cikti arasinda eklenen/degisen kelime
  const x = a.split(/[ ;]+/), y = b.split(/[ ;]+/);
  return y.filter((w) => !x.includes(w)).join(" ") || "(cikarildi)";
};

const kos = (sabit) => {
  const arg = {}, pin = {}, once = {}, kosan = {}, son = {}, oncekiS = {}, bek = [];
  let beklenmeyen = 0, kirikTanim = new Set(), kirikSatir = 0, degisen = 0;
  for (const t in T) { arg[t] = { ...T[t].g }; pin[t] = T[t].p; kosan[t] = new Set(); }
  for (let h = 1; h <= 10; h++) {
    if (sabit) for (const [hy, t, s] of YUKSELT) if (hy === h) { pin[t] = s; arg[t].$duzeltildi = 1; }
    for (const t in T) {
      if (!T[t].h.includes(h)) continue;
      const s = sabit ? pin[t] : enYeni(T[t].m, h);
      const mv = coz(MODUL[T[t].m][s]), tam = { ...mv.vars, ...arg[t] };
      const eksik = mv.zor.filter((a) => !(a in tam));
      let duzeltildi = arg[t].$duzeltildi;
      if (eksik.length) {                              // kirici yayin: tanim o anda duzeltilir
        for (const e of eksik) { arg[t][e] = DUZELTME[e](tam); tam[e] = arg[t][e]; }
        kirikTanim.add(t); kirikSatir += eksik.length; duzeltildi = 1;
      }
      const c = uret(mv, tam);
      kosan[t].add(s);
      if (once[t] !== undefined && once[t] !== c) {
        degisen++;
        if (!duzeltildi) { beklenmeyen++; bek.push([h, t, oncekiS[t], s, fark(once[t], c)]); }
      }
      once[t] = c; son[t] = s; oncekiS[t] = s; delete arg[t].$duzeltildi;
    }
  }
  return { beklenmeyen, kirikTanim, kirikSatir, degisen, pin, kosan, son, bek };
};

const A = kos(false), S = kos(true), TS = Object.keys(T).length;
const surumler = (m) => YAYIN.filter((y) => y[1] === m);
console.log(`donem 10 hafta | yayin ${YAYIN.length}: ` + ["yama", "kucuk", "kirici"]
  .map((k) => `${k} ${YAYIN.filter((y) => y[3] === k).length}`).join(", ") +
  ` | tanim ${TS} | uygulama ${Object.values(T).reduce((a, b) => a + b.h.length, 0)}`);
const yanlis = Object.keys(T).filter((t) => S.pin[t] !== S.son[t]).length;   // yazilan surum kosmuyor
for (const [ad, r, y] of [["sabitlenmemis", A, TS], ["sabitlenmis  ", S, yanlis]])
  console.log(`${ad} | cikti degisimi ${r.degisen} | beklenmeyen degisiklik ${r.beklenmeyen}` +
    ` | kirilan tanim ${r.kirikTanim.size} | duzeltme satiri ${r.kirikSatir} | kosan farkli surum ` +
    `${Object.values(r.kosan).reduce((a, b) => a + b.size, 0)} | kaydin kosani soylemedigi tanim ${y}/${TS}`);

for (const [h, t, e, s, d] of A.bek)                   // tanima dokunulmadan degisen ciktilar
  console.log(`  beklenmeyen  h${String(h).padEnd(2)} ${t.padEnd(12)} ${e} -> ${s}  eklenen: ${d}`);
for (const [h, m, s, tur] of YAYIN) {                  // bir yayin kac kullaniciya ulasti
  const u = Object.keys(T).filter((t) => T[t].m === m && A.kosan[t].has(s));
  const b = Object.keys(T).filter((t) => T[t].m === m && S.kosan[t].has(s));
  console.log(`  h${String(h).padEnd(2)} ${m.padEnd(16)} ${s} ${tur.padEnd(7)} kullanan tanim ${Object.keys(T)
    .filter((t) => T[t].m === m).length} | ulastigi: sabitlenmemis ${u.length}, sabitlenmis ${b.length}`);
}

let geri = 0, kacan = 0, eski = 0;                     // sabitlemenin bedeli: donem sonunda
for (const t in T) {
  const l = surumler(T[t].m), sonrasi = l.slice(l.findIndex((y) => y[2] === S.pin[t]) + 1);
  geri += sonrasi.length; kacan += sonrasi.filter((y) => y[3] === "yama").length;
  if (sonrasi.length) eski++;
  console.log(`  ${t.padEnd(18)} kayitli ${S.pin[t]}  kosan ${S.son[t]}  en yeni ${l.at(-1)[2]}` +
    `  geride ${sonrasi.length}  alinmayan yama ${sonrasi.filter((y) => y[3] === "yama").length}`);
}
const kullanilan = new Set(Object.keys(T).map((t) => `${T[t].m} ${S.pin[t]}`));
const disSatir = [...kullanilan].reduce((a, k) => {
  const [m, s] = k.split(" "), v = coz(MODUL[m][s]);
  return a + v.zor.length + Object.keys(v.vars).length + v.govde.length;
}, 0);
console.log(`eski surumde kalan tanim ${eski}/${TS} | toplam geride ${geri} surum | alinmayan yama ${kacan}` +
  ` | depodaki tanim ${Object.values(T).reduce((a, d) => a + 3 + Object.keys(d.g).length, 0)} satir` +
  ` | bagli olunan ${kullanilan.size} modul surumu, ${disSatir} satir depo disinda`);
donem 10 hafta | yayin 9: yama 4, kucuk 2, kirici 3 | tanim 9 | uygulama 18
sabitlenmemis | cikti degisimi 9 | beklenmeyen degisiklik 3 | kirilan tanim 9 | duzeltme satiri 9 | kosan farkli surum 18 | kaydin kosani soylemedigi tanim 9/9
sabitlenmis   | cikti degisimi 1 | beklenmeyen degisiklik 0 | kirilan tanim 0 | duzeltme satiri 0 | kosan farkli surum 10 | kaydin kosani soylemedigi tanim 1/9
  beklenmeyen  h5  dogu-nokta   1.0.0 -> 1.1.1  eklenen: yon=giris izleme durum=acik
  beklenmeyen  h9  kuzey-nokta  2.0.0 -> 2.0.1  eklenen: tip=toplayici
  beklenmeyen  h10 saha-giris   2.0.0 -> 2.0.1  eklenen: kayit=acik
  h1  olcum-kuyrugu    1.0.1 yama    kullanan tanim 3 | ulastigi: sabitlenmemis 2, sabitlenmis 0
  h2  toplama-noktasi  1.1.0 kucuk   kullanan tanim 4 | ulastigi: sabitlenmemis 2, sabitlenmis 0
  h3  saha-agi         2.0.0 kirici  kullanan tanim 2 | ulastigi: sabitlenmemis 2, sabitlenmis 0
  h4  toplama-noktasi  1.1.1 yama    kullanan tanim 4 | ulastigi: sabitlenmemis 1, sabitlenmis 1
  h5  olcum-kuyrugu    1.1.0 kucuk   kullanan tanim 3 | ulastigi: sabitlenmemis 1, sabitlenmis 0
  h6  toplama-noktasi  2.0.0 kirici  kullanan tanim 4 | ulastigi: sabitlenmemis 2, sabitlenmis 0
  h7  olcum-kuyrugu    2.0.0 kirici  kullanan tanim 3 | ulastigi: sabitlenmemis 3, sabitlenmis 0
  h8  toplama-noktasi  2.0.1 yama    kullanan tanim 4 | ulastigi: sabitlenmemis 3, sabitlenmis 0
  h9  saha-agi         2.0.1 yama    kullanan tanim 2 | ulastigi: sabitlenmemis 1, sabitlenmis 0
  kuzey-nokta        kayitli 1.0.0  kosan 1.0.0  en yeni 2.0.1  geride 4  alinmayan yama 2
  bati-nokta         kayitli 1.1.1  kosan 1.1.1  en yeni 2.0.1  geride 2  alinmayan yama 1
  dogu-nokta         kayitli 1.0.0  kosan 1.0.0  en yeni 2.0.1  geride 4  alinmayan yama 2
  guney-nokta        kayitli 1.0.0  kosan 1.0.0  en yeni 2.0.1  geride 4  alinmayan yama 2
  kuzey-kuyruk       kayitli 1.1.0  kosan 1.0.0  en yeni 2.0.0  geride 1  alinmayan yama 0
  bati-kuyruk        kayitli 1.0.0  kosan 1.0.0  en yeni 2.0.0  geride 3  alinmayan yama 1
  merkez-kuyruk      kayitli 1.0.0  kosan 1.0.0  en yeni 2.0.0  geride 3  alinmayan yama 1
  saha-giris         kayitli 1.0.0  kosan 1.0.0  en yeni 2.0.1  geride 2  alinmayan yama 1
  laboratuvar-giris  kayitli 1.0.0  kosan 1.0.0  en yeni 2.0.1  geride 2  alinmayan yama 1
eski surumde kalan tanim 9/9 | toplam geride 25 surum | alinmayan yama 11 | depodaki tanim 39 satir | bagli olunan 5 modul surumu, 20 satir depo disinda

On sekiz uygulamanın on sekizi iki düzende de koştu; fark neyin koştuğundadır. Sabitlenmemiş düzende çıktı dokuz kez değişti, sabitlenmiş düzende bir kez. O bir kez de elle yapılmış bir yükseltmedir; kimse istemeden hiçbir çıktı değişmedi.

Dokuz değişimin üçü beklenmeyen değişikliktir: tanım metnine o uygulamada hiç dokunulmadı, gene de üretilen kaynak bir öncekinden farklı çıktı. Kalan altısı kırıcı yayınların hemen ardından geldi ve tanım o sırada zaten düzeltilmişti. Beklenmeyen üçün dökümü ortak yanlarını gösterir: dogu-nokta beşinci haftada iki sürüm birden atlayıp bir ağ alanı ile bir izleme satırı kazandı, kuzey-nokta dokuzuncu haftada makine kümesine tip=toplayici aldı, saha-giris onuncu haftada ağ kuralına kayit=acik aldı. Üçü de kayıtta görünmeyen bir yayının sonucudur, üçü de sessizce uygulandı ve hiçbiri hata vermedi.

Kırıcı yayınların yayılması ikinci sayıdır. Üç kırıcı yayın sabitlenmemiş düzende dokuz tanımın dokuzunu kırdı ve dokuz satır düzeltme istedi. Yayın sayısı üç, düzeltme sayısı dokuz: bir kırıcı yayının maliyeti, onu yayınlayan tarafta bir kez, kullanan tarafta kullanıcı sayısı kadar ödenir. Sabitlenmiş düzende aynı üç yayın hiçbir tanımı kırmadı ve sıfır satır düzeltme istedi — ama bu maliyetin silindiği anlamına gelmez, ertelendiği anlamına gelir.

Yayın başına döküm bir yayının kaç kullanıcıya ulaştığını verir. Dokuz yayının hiçbiri o modülü kullanan tanımların tamamına ulaşmadı: en geniş yayılım üçte üç, en darı dörtte bir. Bir yayının kime ulaştığına yayını yapan taraf değil, kullanan tarafın uygulama takvimi karar veriyor. Sabitlenmiş düzende aynı dokuz yayının sekizi hiçbir kullanıcıya ulaşmadı; ulaşan tek yayın, elle yükseltilen tanımın çektiği yamadır. Sabitlenmemiş düzende dokuz tanım dönem boyunca on sekiz farklı sürüm koşturdu, sabitlenmişte on: tanım başına ikiye karşı 1,1.

Sabitlemenin Bedeli

Dönem sonunda tablo tersine döner. Sabitlenmiş düzende dokuz tanımın dokuzu eski sürümdedir; toplamda yirmi beş sürüm geride kalmışlardır ve on bir yama onlara hiç ulaşmamıştır. Yama bir hata düzeltmesidir; sabitleme yalnız istenmeyen değişikliği durdurmaz, istenen düzeltmeyi de durdurur.

Dağılım ertelemenin nasıl biriktiğini gösterir. Hiç yükseltilmeyen altı tanım üçle dört sürüm arası geride; dönem içinde bir kez yükseltilen bati-nokta iki sürüm geride ve bir yama eksik. Yükseltme bir tanımı öne çeker ama yayın akışı durmadığı için mesafe hemen yeniden açılır. Sabitlemenin bedeli tek seferlik bir gecikme değil, sürekli büyüyen bir açıklıktır.

Ertelemenin faizi de sayılıdır: bugün ödenmeyen dokuz satır düzeltme silinmedi, o dokuz tanım bir gün yükseltilecekse aynı üç kırıcı yayınla aynı anda karşılaşacaklar.

Kaydın Söylemediği

Üçüncü sayı kaydın kendisiyle ilgilidir. Sabitlenmemiş düzende tanım hiçbir sürüm yazmaz; dokuz tanımın dokuzunda kayıt, koşan şeyi tarif etmiyor. Tanım dosyası okunarak üretilecek kaynağın ne olduğu bilinemez, çünkü metnin bir kısmı başka bir yerde ve o yer değişebilir.

Sabitlemek bunu bire indirir ama sıfıra indirmez. kuzey-kuyruk satırı farkı gösterir: kayıtlı sürüm 1.1.0, koşan sürüm 1.0.0. Dokuzuncu haftada sürüm yükseltildi, ama o tanımın dönem içinde başka uygulaması olmadı. Kayıt yeni sürümü söylüyor, sahada eski sürüm duruyor. Sabitleme, kayıt ile gerçek arasındaki farkı ortadan kaldırmaz; farkı yayın anından uygulama anına taşır.

Son satır bağımlılığın büyüklüğünü verir. Depodaki dokuz tanım otuz dokuz satırdır ve beş ayrı modül sürümüne, toplam yirmi satır depo dışı metne bağlıdır. Sabitlenmiş düzende o yirmi satırın hangi hâli olduğu tanımda yazılıdır; sabitlenmemişte yazılı değildir ve depoda tek bir kayıt bile değişmeden başkalaşabilir.

Özet

  • Aynı 18 uygulama iki düzende koştu: sabitlenmemiş düzende çıktı 9 kez, sabitlenmiş düzende 1 kez değişti; o 1 değişim de elle yapılan bir yükseltmedir.
  • 9 değişimin 3’ü beklenmeyen değişikliktir — tanım metnine dokunulmadı, çıktı değişti ve hiçbiri hata vermedi.
  • 3 kırıcı yayın sabitlenmemiş düzende 9 tanımı kırdı ve 9 satır düzeltme istedi; sabitlenmiş düzende 0 tanım kırıldı, ama maliyet silinmedi, ertelendi.
  • Sabitlemenin bedeli dönem sonunda görülür: 9 tanımın 9’u eski sürümde, toplam 25 sürüm geride ve 11 yama hiç ulaşmadı.
  • Sabitlenmemiş düzende 9 tanımın 9’unda kayıt koşanı söylemiyor; sabitlenmişte 1’inde söylemiyor — yazılan sürüm uygulanmadığı için kayıt ile gerçek yine ayrıştı.

Sonraki Adım

Modül kaydından gelen metin artık tanımın bir parçası gibi davranıyor: girdileri alıyor, kaynak üretiyor, çıktı veriyor. Bu derste o girdilerin hepsi zararsızdı — bir ağ bloğu, bir kapı numarası, bir kuyruk adı. Aralarında bir veri deposu parolası olsaydı ne olurdu? Değer tanımdan modüle, modülden kaynağa, kaynaktan durum dosyasına geçer; yol boyunca plan çıktısına, günlüğe ve hat kaydına da uğrar. Bir sonraki ders kurgu bir hassas değeri bu yola sokar ve node ile yazılmış bir iz tarayıcısıyla kaç yerde göründüğünü sayar; sonra o değere “hassas” damgası vurulur ve tarama yeniden koşturulur — kaç yerde gizlendiği, kaç yerde hâlâ durduğu sayılır.

İ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