Ders 09 / 27
Değişkenler, Yerel Değerler ve Çıktılar
Aynı tanım üç ortama uygulanır ve parametreleştirmenin bilançosu sayılır: kaç değer ortama göre gerçekten değişiyor, kaçı her ortamda aynı yazılıyor, kaç değişken hiç kullanılmıyor. Girdi yüzeyi büyüdükçe yanlış değer verme olasılığı, doğrulamanın yakaladığı ile yakalayamadığı yanlış sayısıyla ölçülür ve çıktıların başka tanımlarda yarattığı bağımlılık sayılır.
İçindekiler
Önceki dersler tek bir ortamın kaydını ele aldı. Aynı tanım üç ortamda koşacaksa iki soru doğar: hangi değer ortama göre değişmeli, hangisi her ortamda aynı kalmalı. Bunu yazan yapı üç parçalıdır — dışarıdan değer alan değişkenler, değişkenlerden türetilen yerel değerler, ve tanımın dışarıya verdiği çıktılar. Bu ders üçünü de sayar: girdi yüzeyinin ne kadarının gerçekten ortama özgü olduğunu, yüzey büyüdükçe yanlış değer verme olasılığının nereye gittiğini, ve çıktıların başka tanımlarda kaç bağımlılık yarattığını.
Ölçüm bölgesel ölçüm ağının üç ortamı üzerindedir ve kurgudur; tanım, doğrulama ve tüketen
tanımlar node ile kurulmuş bir modeldir.
BS19. Tanım on dört değişken, üç yerel değer, dört kaynak ve beş çıktı taşır. BS20. Varsayılanı olmayan değişken zorunludur; bir ortam değer vermezse varsayılan sessizce kullanılır. BS21. Doğrulama yalnız türü ve değer aralığını ya da sıralı küme üyeliğini sınar; değerin o ortam için doğru olup olmadığını sınamaz. BS22. Bir değişken, doğrudan ya da bir yerel değer üzerinden okunuyorsa kullanılmış sayılır; hiç okunmayan değişken ölüdür. BS23. On yanlış girdi önceden seçilmiştir; her biri gerçekte sık yapılan bir yazım ya da birim karışıklığıdır. BS24. Bir çıktı değişirse onu okuyan her tanım yeniden planlanır.
Tanım ve Üç Ortam
// tanim.mjs — uc ortama uygulanan kurgu tanim: degiskenler, yerel degerler, kaynaklar, ciktilar. const D = (tur, dogrula, varsayilan) => ({ tur, dogrula, varsayilan }); const kume = (...k) => (v) => k.includes(v); const arasi = (a, b) => (v) => v >= a && v <= b; export const DEGISKEN = { // varsayilani olmayan degisken zorunludur bolge: D("dize", kume("bati", "dogu", "merkez")), toplayici: D("sayi", arasi(1, 64)), kuyruk_bolme: D("sayi", arasi(1, 128)), disk_gb: D("sayi", arasi(20, 4000)), saklama_gn: D("sayi", arasi(1, 365), 30), esik_ms: D("sayi", arasi(50, 5000), 900), cekirdek: D("sayi", arasi(1, 64), 4), bellek_gb: D("sayi", arasi(1, 256), 8), bicim: D("dize", kume("ikili", "metin"), "ikili"), izleme: D("dize", kume("acik", "kapali"), "acik"), yedek_gn: D("sayi", arasi(0, 35), 1), etiket_sahip: D("dize", kume("olcum-ekibi", "ag-ekibi"), "olcum-ekibi"), sertifika_gun: D("sayi", arasi(1, 365), 90), eski_bayrak: D("dize", kume("acik", "kapali"), "kapali"), }; export const YEREL = { // degiskenlerden turetilen ara degerler ad_onek: { girdi: ["bolge"], hesap: (d) => `${d.bolge}-olcum` }, toplam_cekirdek: { girdi: ["toplayici", "cekirdek"], hesap: (d) => d.toplayici * d.cekirdek }, kuyruk_adi: { girdi: ["bolge"], hesap: (d) => `${d.bolge}-sayac-kuyrugu` }, }; export const KAYNAK = { // her kaynagin okudugu degisken ve yerel deger "makine.toplayici": ["bolge", "toplayici", "cekirdek", "bellek_gb", "disk_gb", "izleme", "etiket_sahip", "yerel.toplam_cekirdek"], "kuyruk.sayac": ["kuyruk_bolme", "saklama_gn", "bicim", "etiket_sahip", "yerel.kuyruk_adi"], "veri_deposu.olcum": ["esik_ms", "yedek_gn", "disk_gb", "yerel.ad_onek"], "nesne_deposu.arsiv": ["saklama_gn", "yerel.ad_onek"], }; export const ORTAM = { // uc ortamin verdigi degerler bati: { bolge: "bati", toplayici: 6, kuyruk_bolme: 12, disk_gb: 200, saklama_gn: 30, esik_ms: 900, cekirdek: 4, bellek_gb: 8 }, dogu: { bolge: "dogu", toplayici: 6, kuyruk_bolme: 12, disk_gb: 200, saklama_gn: 30, esik_ms: 900, cekirdek: 4, bellek_gb: 8 }, merkez: { bolge: "merkez", toplayici: 2, kuyruk_bolme: 4, disk_gb: 60, saklama_gn: 7, esik_ms: 900, cekirdek: 4, bellek_gb: 8 }, }; export const CIKTI = { // baska tanimlarin okudugu degerler kuyruk_adi: "yerel.kuyruk_adi", depo_onek: "yerel.ad_onek", toplam_cekirdek: "yerel.toplam_cekirdek", sahip: "etiket_sahip", arsiv_gun: "saklama_gn", }; export const TUKETEN = { // hangi tanim hangi ciktiyi okuyor "hat-tanimi": ["kuyruk_adi", "depo_onek"], "uyari-tanimi": ["kuyruk_adi", "arsiv_gun"], "rapor-tanimi": ["depo_onek", "sahip"], }; export function coz(veren) { // etkin deger: verilen ya da varsayilan const d = {}; for (const [ad, t] of Object.entries(DEGISKEN)) d[ad] = ad in veren ? veren[ad] : t.varsayilan; for (const [ad, y] of Object.entries(YEREL)) d[`yerel.${ad}`] = y.hesap(d); return d; }
Değişken bildirimi üç şey taşır: tür, doğrulama ve varsayılan. Yerel değer bir hesaptır ve girdisini adıyla yazar; kaynaklar hem değişkenleri hem yerel değerleri okur. Çıktı ise yalnız bir yönlendirme tablosudur — tanımın içindeki bir değeri dışarıya adlandırarak açar.
Girdi Yüzeyinin Bilançosu
// olc.mjs — girdi yuzeyi, ortama gore degisen ve degismeyen degerler, olu degisken, cikti bagimliligi. import { DEGISKEN, YEREL, KAYNAK, ORTAM, CIKTI, TUKETEN, coz } from "./tanim.mjs"; const ORT = Object.keys(ORTAM), cozum = Object.fromEntries(ORT.map((o) => [o, coz(ORTAM[o])])); const zorunlu = Object.entries(DEGISKEN).filter(([, t]) => t.varsayilan === undefined).map(([a]) => a); const kullanilan = new Set([...Object.values(KAYNAK).flat(), ...Object.values(YEREL).flatMap((y) => y.girdi)]); const olu = Object.keys(DEGISKEN).filter((a) => !kullanilan.has(a)); const verilen = Object.keys(DEGISKEN).filter((a) => ORT.every((o) => a in ORTAM[o])); const farkli = verilen.filter((a) => new Set(ORT.map((o) => ORTAM[o][a])).size > 1); console.log(`degisken ${Object.keys(DEGISKEN).length}: ${zorunlu.length} zorunlu, ` + `${Object.keys(DEGISKEN).length - zorunlu.length} varsayilanli, ${olu.length} olu (${olu.join(", ")})`); console.log(`uc ortam ${verilen.length * ORT.length} deger yaziyor: ` + `${farkli.length * ORT.length} tanesi ortama gore farkli (${farkli.join(", ")}), ` + `${(verilen.length - farkli.length) * ORT.length} tanesi uc ortamda ayni ` + `(${verilen.filter((a) => !farkli.includes(a)).join(", ")})`); console.log(`hic verilmeyip varsayilanda kalan degisken: ` + `${Object.keys(DEGISKEN).length - verilen.length}\n`); const yaz = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 15 : 20)).join("").trimEnd()); yaz("kaynak", "girdi", "ortama gore", "hep ayni"); for (const [k, girdiler] of Object.entries(KAYNAK)) { const degisen = girdiler.filter((g) => new Set(ORT.map((o) => cozum[o][g])).size > 1); yaz(k, girdiler.length, degisen.length, girdiler.length - degisen.length); } const girdiler = [...new Set(Object.values(KAYNAK).flat())]; const degisenGirdi = girdiler.filter((g) => new Set(ORT.map((o) => cozum[o][g])).size > 1); console.log(` toplam ${girdiler.length} benzersiz girdi, ${degisenGirdi.length} tanesi ortama gore degisiyor`); const eksik = { ...ORTAM.merkez }; // merkez ortami bir degeri vermeyi unutursa delete eksik.saklama_gn; const c2 = coz(eksik), kayan = Object.keys(cozum.merkez).filter((k) => cozum.merkez[k] !== c2[k]); console.log(`\nmerkez saklama_gn vermezse varsayilan ${DEGISKEN.saklama_gn.varsayilan} gecerli olur ` + `(ortamin degeri ${ORTAM.merkez.saklama_gn}): ${kayan.length} deger kayar, ` + `${Object.entries(KAYNAK).filter(([, g]) => g.some((x) => kayan.includes(x))).length} kaynak etkilenir, ` + `dogrulama hicbir sey soylemez`); console.log(`\ncikti ${Object.keys(CIKTI).length}, tuketen tanim ${Object.keys(TUKETEN).length}`); for (const c of Object.keys(CIKTI)) { const t = Object.entries(TUKETEN).filter(([, l]) => l.includes(c)).map(([a]) => a); console.log(` ${c.padEnd(17)}${t.length} tuketen ${t.join(", ") || "(olu cikti)"}`); } const bagli = Object.values(TUKETEN).flat().length; console.log(`toplam bagimlilik ${bagli}; bir ciktinin degeri degisirse ortalama ` + `${(bagli / Object.keys(CIKTI).length).toFixed(1)} tanim yeniden planlanir`);
degisken 14: 4 zorunlu, 10 varsayilanli, 2 olu (sertifika_gun, eski_bayrak) uc ortam 24 deger yaziyor: 15 tanesi ortama gore farkli (bolge, toplayici, kuyruk_bolme, disk_gb, saklama_gn), 9 tanesi uc ortamda ayni (esik_ms, cekirdek, bellek_gb) hic verilmeyip varsayilanda kalan degisken: 6 kaynak girdi ortama gore hep ayni makine.toplayici 8 4 4 kuyruk.sayac 5 3 2 veri_deposu.olcum 4 2 2 nesne_deposu.arsiv 2 2 0 toplam 15 benzersiz girdi, 8 tanesi ortama gore degisiyor merkez saklama_gn vermezse varsayilan 30 gecerli olur (ortamin degeri 7): 1 deger kayar, 2 kaynak etkilenir, dogrulama hicbir sey soylemez cikti 5, tuketen tanim 3 kuyruk_adi 2 tuketen hat-tanimi, uyari-tanimi depo_onek 2 tuketen hat-tanimi, rapor-tanimi toplam_cekirdek 0 tuketen (olu cikti) sahip 1 tuketen rapor-tanimi arsiv_gun 1 tuketen uyari-tanimi toplam bagimlilik 6; bir ciktinin degeri degisirse ortalama 1.2 tanim yeniden planlanir
İlk satır parametreleştirmenin sessiz maliyetini verir. On dört değişkenin dördü zorunlu, onunun varsayılanı var; ikisi ise ölü — hiçbir kaynak ve hiçbir yerel değer onları okumuyor. Ölü değişken zararsız görünür ama girdi yüzeyinin bir parçasıdır: belgede durur, gözden geçirmede okunur, yeni bir ortam eklenirken doldurulup doldurulmayacağı tartışılır ve hiçbir şeyi değiştirmez.
İkinci satır dersin ana ölçüsüdür. Üç ortam toplam yirmi dört değer yazar. Bunların on beşi ortama göre gerçekten farklıdır — bölge, toplayıcı sayısı, kuyruk bölmesi, disk boyutu, saklama süresi. Kalan dokuzu üç ortamda da aynıdır: eşik süresi, çekirdek ve bellek her ortamda aynı değerle yazılmıştır. Bu dokuz değer değişken olmak zorunda değildir; tanımın içinde sabit ya da varsayılan olarak durabilirdi. Aralarındaki fark tek bir şeyde görünür: her biri üç kez elle yazılmıştır ve üçünün de yanlış yazılma ihtimali vardır. Altı değişken ise hiçbir ortamda verilmez ve varsayılanında kalır; bu altısı zaten sabittir, ama kayıtta değişken olarak görünürler.
Üçüncü tablo yükün kaynaklara dağılımını verir. Toplayıcı makinelerin sekiz girdisinin dördü ortama göre değişir, dördü hep aynıdır; arşiv nesne deposunun iki girdisinin ikisi de ortama göre değişir. Bir kaynağın ortamlar arasında ne kadar farklılaştığı, okuduğu girdilerin kaçının gerçekten değiştiğine bağlıdır — kaynak sayısına değil. Toplamda dört kaynak on beş benzersiz girdi okur ve bunların sekizi ortama göre değişir; yani üç ortam arasındaki bütün fark sekiz noktada toplanmıştır. Parametreleştirmenin gerçek genişliği budur, on dört değişken değil.
Sonraki satır varsayılanın sessiz yüzünü gösterir. Merkez ortamı saklama süresini vermeyi unutursa değer boş kalmaz: tanımdaki varsayılan otuz gün sessizce yürürlüğe girer, oysa o ortamın istediği yedi gündür. Bir değer kayar, iki kaynak yanlış kurulur ve doğrulama hiçbir şey söylemez, çünkü otuz gün tür ve aralık bakımından kusursuzdur. Varsayılan, eksik girdiyi hataya çevirmek yerine sessiz bir karara çevirir; bu yüzden ortama göre değişmesi gereken bir değişkene varsayılan vermek, o değişkeni zorunlu olmaktan çıkarmakla aynı şeydir.
Son bölüm çıktıları sayar. Beş çıktıdan dördü tüketiliyor, biri ölü çıktı: toplam çekirdek sayısını hiçbir tanım okumuyor. Üç tüketen tanım toplam altı bağımlılık kuruyor; kuyruk adı ile depo öneki ikişer tanım tarafından okunuyor. Bunun anlamı şudur: kuyruk adını değiştiren bir değişiklik kendi tanımını değil, iki başka tanımı da yeniden planlanmaya zorlar. Çıktı, tanımın dışarıya verdiği bir söz haline gelir ve sözün maliyeti onu okuyan tanım sayısı kadardır.
Yanlış Değer Verme
// girdi.mjs — girdi yuzeyi buyudukce yanlis deger verme: on kurgu yanlis, dogrulamadan kacı geciyor. import { DEGISKEN, YEREL, KAYNAK, ORTAM } from "./tanim.mjs"; const YANLIS = [ // onceden secilmis, rastgele degil ["bolge yazimi", "bolge", "bat"], ["sayi yerine dize", "toplayici", "6"], ["fazla sifir", "toplayici", 600], ["gun yerine saat", "saklama_gn", 720], ["eksik hane", "kuyruk_bolme", 2], ["eksik sifir", "esik_ms", 90], ["birim karisikligi", "disk_gb", 20], ["fazla hane", "cekirdek", 40], ["kume disi bicim", "bicim", "ham"], ["isaret", "bellek_gb", -8], ]; const dogrula = (ad, v) => { // tip ve deger dogrulamasi const t = DEGISKEN[ad]; if (typeof v !== (t.tur === "sayi" ? "number" : "string")) return `${t.tur} bekleniyordu`; return t.dogrula(v) ? null : "deger kabul edilmiyor"; }; const etkilenen = (ad) => Object.entries(KAYNAK).filter(([, g]) => g.includes(ad) || g.some((x) => x.startsWith("yerel.") && YEREL[x.slice(6)].girdi.includes(ad))).map(([k]) => k); console.log(`girdi yuzeyi: ${Object.keys(ORTAM).length} ortam x ` + `${Object.keys(ORTAM.bati).length} verilen degisken = ` + `${Object.keys(ORTAM).length * Object.keys(ORTAM.bati).length} elle yazilan deger\n`); console.log("yanlis degisken deger dogrulama etkilenen kaynak"); let gecen = 0; for (const [ad, degisken, deger] of YANLIS) { const h = dogrula(degisken, deger); if (!h) gecen++; console.log(` ${ad.padEnd(20)}${degisken.padEnd(15)}${String(deger).padEnd(9)}` + `${(h ?? "gecti").padEnd(23)}${h ? "" : etkilenen(degisken).length}`); } console.log(`\n${YANLIS.length} yanlisin ${YANLIS.length - gecen} tanesi dogrulamada yakalandi, ` + `${gecen} tanesi uygulamaya indi`); const zorunlu = Object.entries(DEGISKEN).filter(([, t]) => t.varsayilan === undefined).length; console.log(`yakalanmayanlarin hepsi tur ve araliga uygun; yanlis olduklari yalnizca ortamin ` + `beklentisinden anlasilir`); console.log(`girdi yuzeyi ${Object.keys(ORTAM).length} ortamdan ${Object.keys(ORTAM).length * 2} ortama ` + `cikarsa elle yazilan deger ${Object.keys(ORTAM.bati).length * Object.keys(ORTAM).length} yerine ` + `${Object.keys(ORTAM.bati).length * Object.keys(ORTAM).length * 2}, zorunlu deger ` + `${zorunlu * Object.keys(ORTAM).length} yerine ${zorunlu * Object.keys(ORTAM).length * 2} olur`);
girdi yuzeyi: 3 ortam x 8 verilen degisken = 24 elle yazilan deger yanlis degisken deger dogrulama etkilenen kaynak bolge yazimi bolge bat deger kabul edilmiyor sayi yerine dize toplayici 6 sayi bekleniyordu fazla sifir toplayici 600 deger kabul edilmiyor gun yerine saat saklama_gn 720 deger kabul edilmiyor eksik hane kuyruk_bolme 2 gecti 1 eksik sifir esik_ms 90 gecti 1 birim karisikligi disk_gb 20 gecti 2 fazla hane cekirdek 40 gecti 1 kume disi bicim bicim ham deger kabul edilmiyor isaret bellek_gb -8 deger kabul edilmiyor 10 yanlisin 6 tanesi dogrulamada yakalandi, 4 tanesi uygulamaya indi yakalanmayanlarin hepsi tur ve araliga uygun; yanlis olduklari yalnizca ortamin beklentisinden anlasilir girdi yuzeyi 3 ortamdan 6 ortama cikarsa elle yazilan deger 24 yerine 48, zorunlu deger 12 yerine 24 olur
Girdi yüzeyi üç ortam için yirmi dört elle yazılan değerdir. On kurgu yanlıştan altısı doğrulamada yakalanır: bölge adının yanlış yazılması, sayı yerine dize verilmesi, altı yerine altı yüz yazılması, gün yerine saat girilmesi, küme dışı bir biçim, eksi bellek. Dördü ise geçer — kuyruk bölmesinin on iki yerine iki, eşiğin dokuz yüz yerine doksan, diskin iki yüz yerine yirmi, çekirdeğin dört yerine kırk yazılması. Dördünün ortak yanı, tür ve aralık bakımından kusursuz olmalarıdır. Doğrulama bir değerin biçimini sınar, o ortam için doğru olup olmadığını sınayamaz; çünkü doğruluk ölçütü tanımın içinde değil, ortamın beklentisindedir.
Geçen dördünün etkisi de sayılıdır: üçü birer kaynağı, biri iki kaynağı yanlış değerle kurar. Bir girdinin kaç kaynağa dokunduğu, o girdinin doğrudan okunduğu kaynaklara ve onu okuyan yerel değerlerin geçtiği kaynaklara bağlıdır — disk boyutu iki kaynağa birden girdiği için tek bir yanlış hane iki kaynağı birlikte kaydırır.
Son satır yüzeyin nasıl büyüdüğünü gösterir. Ortam sayısı üçten altıya çıkarsa elle yazılan değer yirmi dörtten kırk sekize, zorunlu değer on ikiden yirmi dörde çıkar. Yanlış yazma fırsatı ortam sayısıyla doğrusal artar ve bu artışın dokuzda üçü, üç ortamda da aynı yazılan değerlerdendir — yani gereksiz yere yüzeyde duran değerlerden. Girdi yüzeyini küçültmenin en ucuz yolu yeni bir doğrulama yazmak değil, ortama göre değişmeyen değeri değişken olmaktan çıkarmaktır.
Özet
- Tanım 14 değişken taşıdı: 4 zorunlu, 10 varsayılanlı, 2 ölü. 6 değişken hiçbir ortamda verilmedi ve varsayılanında kaldı.
- Üç ortam 24 değer yazdı; 15’i ortama göre gerçekten farklı, 9’u üç ortamda da aynıydı. O 9 değer değişken olmak zorunda değildi ama üç kez elle yazıldı.
- Dört kaynak 15 benzersiz girdi okudu; üç ortam arasındaki bütün fark bu girdilerin 8’inde toplandı. Merkez ortamı tek bir değeri vermeyi unuttuğunda varsayılan sessizce devreye girdi ve 2 kaynağı yanlış kurdu.
- 10 yanlış girdiden 6’sı doğrulamada yakalandı, 4’ü geçti; geçenlerin hepsi tür ve aralık bakımından kusursuzdu ve 5 kaynağı yanlış değerle kurdu.
- 5 çıktının 4’ü tüketildi, 1’i ölü çıktıydı; 3 tüketen tanım 6 bağımlılık kurdu ve iki çıktı ikişer tanım tarafından okundu.
- Ortam sayısı 3’ten 6’ya çıkarsa elle yazılan değer 24’ten 48’e, zorunlu değer 12’den 24’e çıkar.
Sonraki Adım
Değişkenler tanıma dışarıdan değer verdi, yerel değerler onları türetti, çıktılar sonucu başka tanımlara açtı. Ama bu üç yapı bir şeyi hiç söylemedi: hangi kaynak hangisinden önce yaratılmalı. Kuyruk adı bir makineye, uç nokta bir veri deposuna, ağ kuralı bir alt ağa bağlıysa, uygulama bunları rastgele bir sırayla deneyemez. Bir sonraki ders bu sıralamayı ele alır: bir kaynağın başka bir kaynağın değerini okumasından doğan örtük bağımlılık ile elle yazılan açık bağımlılığın farkı, sıralamanın nasıl çözüldüğü, ve sıra yanlış olduğunda uygulamanın nerede durduğu.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.