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.