Ders 13 / 21
Özellik Bayrakları
Aynı değişiklik dizisi bayraklı ve bayraksız iki düzende yayınlanır; geri alma biriminin kod mu davranış mı olduğu tur ve etkilenen fatura sayısıyla ölçülür. Üç bayrağın açtığı sekiz kod yolu sayılır, sınanan yol oranı çıkarılır ve bir dönemin bayrak borcu ölü kod yoluyla birlikte yazılır.
İçindekiler
Önceki dersin iki ortamlı düzeninde geri alma tek anahtara indi: trafik eski ortama çevrilir ve dakikalar içinde önceki davranışa dönülür. O anahtarın geri aldığı şey kodun tamamıydı. Yayın bir sürümü taşır; sürüm içindeki her değişiklik aynı anda gider ve aynı anda geri gelir. Oysa geri alınması gereken çoğu zaman tek bir davranıştır.
Özellik bayrağı bu birimi ayırır: kod üretime dağıtılır, davranış ayrı bir anahtarla açılır. Bu dersin ölçüsü bayrağın var olup olmadığı değil, bu ayrılığın hangi sayıyı değiştirdiğidir. Aynı değişiklik dizisi iki düzende koşturulur, geri alma birimi ve turu sayılır, bayrağın açtığı kod yolları sayılır ve bir dönemin sonunda geriye kalan bayrak borcu yazılır.
- YS25. Bayrak değeri hat dışında, çalışan sürecin okuduğu bir ayar kaydında durur; değiştirilmesi yeni bir yayın gerektirmez. Ayarın bütün düğümlere yayılması bir tur sürer.
- YS26. Bayraklar birbirinden bağımsızdır: herhangi bir kombinasyon geçerli bir kod yoludur.
- YS27. Üretimdeki sapma, doğrulayıcı servisin uyuşmazlık raporundan görülür; rapor iki dağıtım turunda bir üretilir. Fark etme süresi iki düzende de aynıdır.
- YS28. Bayraksız düzende geri alma birimi bir sürümdür: sürüm içindeki bütün değişiklikler birlikte geri gider.
- YS29. Bayrak okuma noktası, koşulun kodda yazıldığı yerdir; bir bayrak birden çok noktada okunabilir ve temizleme maliyeti bu sayıyla orantılıdır.
- YS30. Kurgu, bölgesel ölçüm ağının faturalama servisidir: sayaç okumasından fatura tutarı üretilir. Servis de, defter de, aşağıdaki sayılar da kurgudur.
Geri Alma Birimi
Altı değişiklikten oluşan bir dönem yayınlanır. Üçüncüsü — gecikme faizi — kusurludur ve kusur ancak sonraki değişiklikler de üretime çıktıktan sonra görülür. Bayraksız düzende değişiklikler ikişerli üç yayına bölünür. Bayraklı düzende her değişiklik ayrı yayınlanır, kusurlu olan bayrak arkasında dağıtılıp sonra açılır.
// duzen.mjs — ayni degisiklik dizisi iki duzende yayinlanir; yayin duzeni MODELDIR const DEGISIKLIK = ['tarife tablosu', 'kademeli tarife', 'gecikme faizi', 'fatura ozet alani', 'is emri baglantisi', 'toplu is raporu']; const KUSURLU = 2; // gecikme faizi, kademe acikken sapiyor const FATURA_TURU = 40; // bir dagitim turunda hesaplanan fatura const AYAR_TURU = 4; // bir ayar yayilma turunda hesaplanan fatura const FARK_ETME = 2; // uyusmazlik raporunun kusuru gostermesi: iki dagitim turu function bayraksiz() { const yayin = [[0, 1], [2, 3], [4, 5]]; // uc yayin, her yayin bir surum let surum = yayin.length, tur = 0; while (yayin.slice(0, surum).flat().includes(KUSURLU)) { surum -= 1; tur += 1; } const kalan = yayin.slice(0, surum).flat(); const cikan = yayin.flat().filter((i) => !kalan.includes(i)); return { ad: 'bayraksiz', birim: 'kod', tur, cikan, etkilenen: (FARK_ETME + tur) * FATURA_TURU }; } function bayrakli() { // her degisiklik ayri yayinlandi; kusurlu olan bayrak arkasinda dagitilip acildi const bayrak = { 'gecikme faizi': 'acik' }; let tur = 0; bayrak['gecikme faizi'] = 'kapali'; tur += 1; const cikan = Object.entries(bayrak).filter(([, d]) => d === 'kapali') .map(([ad]) => DEGISIKLIK.indexOf(ad)); return { ad: 'bayrakli', birim: 'davranis', tur, cikan, etkilenen: FARK_ETME * FATURA_TURU + tur * AYAR_TURU }; } console.log('duzen geri alma birimi tur cikan bunlardan saglam etkilenen fatura'); for (const d of [bayraksiz(), bayrakli()]) { const saglam = d.cikan.filter((i) => i !== KUSURLU); console.log(`${d.ad.padEnd(10)} ${d.birim.padEnd(17)} ${String(d.tur).padEnd(4)} ` + `${String(d.cikan.length).padEnd(6)} ${String(saglam.length).padEnd(17)} ${d.etkilenen}`); console.log(` uretimden cikan: ${d.cikan.map((i) => DEGISIKLIK[i]).join(', ')}`); }
duzen geri alma birimi tur cikan bunlardan saglam etkilenen fatura bayraksiz kod 2 4 3 160 uretimden cikan: gecikme faizi, fatura ozet alani, is emri baglantisi, toplu is raporu bayrakli davranis 1 1 0 84 uretimden cikan: gecikme faizi
Bayraksız düzende iki tur geri sarma gerekti, çünkü kusurlu değişiklik ortadaki sürümdeydi ve ondan sonra bir sürüm daha yayınlanmıştı. Üretimden dört değişiklik çıktı; üçü sağlamdı. O üç değişikliğin sahipleri kusurla ilgisiz kişilerdir ve işleri, kendi hataları olmayan bir nedenle üretimden geri alınmıştır. Bayraklı düzende geri alınan tek şey bir davranıştır: sağlam değişikliklerin hiçbiri üretimden çıkmadı.
Etkilenen fatura sayısındaki fark ise geri alma turunun uzunluğundan gelir. İki düzende de fark etme aynı sürüyor — seksen fatura. Ayrılık ondan sonrasında: sürüm geri sarma iki dağıtım turu, bayrak kapatma bir ayar yayılma turudur. Yüz altmışa karşı seksen dört. Bu farkın tamamı geri alma yolunun kısalmasından gelir, kusurun daha erken görülmesinden değil.
Bayrağın Açtığı Kod Yolları
Bayrak bir koşuldur ve her koşul kodu ikiye ayırır. Üç bayrak sekiz kod yolu açar. Aşağıdaki hesap gerçekten koşar: fatura tutarı üç bayrağın her kombinasyonu için ayrı ayrı hesaplanır ve o kombinasyon için ayrı yazılmış beklenen davranışla karşılaştırılır.
// bayrak.mjs — uc bayragin actigi kod yollari sayilir; faturalama hesabi MODELDIR // Bolgesel olcum agi kurgusu: sayac okumasindan fatura tutari uretilir. const TABAN = 12.4; const KADEME = [[10, 12.4], [25, 18.6], [Infinity, 27.9]]; const OKUMA = [ { no: 'S-0431', m3: 8, gecikmeAy: 0 }, { no: 'S-0432', m3: 8, gecikmeAy: 2 }, { no: 'S-0433', m3: 17, gecikmeAy: 0 }, { no: 'S-0434', m3: 17, gecikmeAy: 1 }, { no: 'S-0435', m3: 34, gecikmeAy: 3 }, { no: 'S-0436', m3: 52, gecikmeAy: 0 }, ]; const BAYRAK = ['kademe', 'gecikme', 'ozet']; const kurus = (x) => Math.round(x * 100) / 100; function kademeli(m3) { let kalan = m3, alt = 0, tutar = 0; for (const [ust, birim] of KADEME) { const dilim = Math.min(kalan, ust - alt); tutar += dilim * birim; kalan -= dilim; alt = ust; if (kalan <= 0) break; } return tutar; } // Uretimdeki kod: her bayrak bir dallanma noktasi. function uretim(o, b) { let tutar = b.kademe ? kademeli(o.m3) : o.m3 * TABAN; const taban = o.m3 * TABAN; if (b.gecikme && o.gecikmeAy > 0) tutar += taban * 0.015 * o.gecikmeAy; const f = { tutar: kurus(tutar) }; if (b.ozet) f.ozet = { m3: o.m3, gecikmeAy: o.gecikmeAy }; return f; } // Her kombinasyonun beklenen davranisi ayri yazilir: faiz kendi tutari uzerinden isler. function beklenen(o, b) { let tutar = b.kademe ? kademeli(o.m3) : o.m3 * TABAN; if (b.gecikme && o.gecikmeAy > 0) tutar += tutar * 0.015 * o.gecikmeAy; return kurus(tutar); } const yollar = []; for (let m = 0; m < 2 ** BAYRAK.length; m += 1) { const b = Object.fromEntries(BAYRAK.map((ad, i) => [ad, Boolean(m & (1 << i))])); const sapan = OKUMA.filter((o) => uretim(o, b).tutar !== beklenen(o, b)); yollar.push({ maske: BAYRAK.map((ad) => (b[ad] ? '1' : '0')).join(''), b, sapan }); } // Sinama kumesi: uretimin bugunku hali ve her bayrak tek basina. const SINANAN = new Set(['000', '100', '010', '001']); console.log('yol kademe gecikme ozet sapan fatura sinandi'); for (const y of yollar) { console.log(`${y.maske} ${BAYRAK.map((a) => (y.b[a] ? 'acik ' : 'kapali')).join(' ')}` + ` ${String(y.sapan.length).padEnd(13)} ${SINANAN.has(y.maske) ? 'evet' : 'hayir'}`); } const kusurlu = yollar.filter((y) => y.sapan.length > 0); console.log(''); console.log(`toplam kod yolu : ${yollar.length}`); console.log(`sinanan yol : ${SINANAN.size} (oran ${(SINANAN.size / yollar.length * 100).toFixed(0)} yuzde)`); console.log(`sapan davranis ureten yol : ${kusurlu.length} — ${kusurlu.map((y) => y.maske).join(', ')}`); console.log(`bunlardan sinanani : ${kusurlu.filter((y) => SINANAN.has(y.maske)).length}`); console.log(''); console.log('kusurun gorundugu ilk yolda fatura basina fark'); for (const o of kusurlu[0].sapan) { const y = kusurlu[0]; console.log(` ${o.no} ${String(o.m3).padStart(3)} m3 ${o.gecikmeAy} ay gecikme` + ` uretim=${uretim(o, y.b).tutar} beklenen=${beklenen(o, y.b)}`); }
yol kademe gecikme ozet sapan fatura sinandi 000 kapali kapali kapali 0 evet 100 acik kapali kapali 0 evet 010 kapali acik kapali 0 evet 110 acik acik kapali 2 hayir 001 kapali kapali acik 0 evet 101 acik kapali acik 0 hayir 011 kapali acik acik 0 hayir 111 acik acik acik 2 hayir toplam kod yolu : 8 sinanan yol : 4 (oran 50 yuzde) sapan davranis ureten yol : 2 — 110, 111 bunlardan sinanani : 0 kusurun gorundugu ilk yolda fatura basina fark S-0434 17 m3 1 ay gecikme uretim=257.36 beklenen=258.01 S-0435 34 m3 3 ay gecikme uretim=673.07 beklenen=683.53
Kusur tek bir bayrakta değil, iki bayrağın kesişiminde duruyor: gecikme faizi kademeli tutar yerine taban tutar üzerinden işliyor. Kademe kapalıyken iki değer eşit olduğu için hesap doğru çıkıyor; kademe açıldığında sapıyor. Sınama kümesi her bayrağı tek başına denediği için sekiz yolun dördünü hiç görmüyor ve kusurlu iki yolun ikisi de o dördün içinde.
Sapmanın büyüklüğü ayrıca kayda değer: fatura başına altmış beş kuruş ile on lira arasında. Bu, bir hata mesajı üretmeyen, oran olarak yüzde birin altında kalan ve yalnız gecikmesi olan abonelerde görünen bir sapmadır. Sekiz yolun kaçının sınandığı sorusu bu yüzden sorulur: bayrak eklemek sınama yükümlülüğünü toplamaz, ikiyle çarpar.
Kapının Üç Sayısı
Bayrak koşulu bir kapıdır ve öteki kapılar gibi üç sayıyla değerlendirilir. Birincisi tuttuğu. Bayrak koşulunun tuttuğu kusur sayısı sıfırdır: koşul iki dalı da geçirir, hiçbir şeyi sınamaz. Tuttuğu tek şey maruziyettir — yüz altmış yerine seksen dört fatura, yani yetmiş altı faturalık fark. Bu farkın tamamı geri alma yolundan gelir ve bu kapının yalnız kendisinin sağladığı şeydir: hat kapılarının hiçbiri geri alma birimini değiştiremez.
İkincisi kaçırdığı ve yanlış tuttuğu. Bayrak kapısı kaçırdığı kusuru kendisi üretmiştir: sınanmayan dört yol, üç bayrak eklenmeden önce var olmayan yollardır. Yanlış tutmanın ölçüsü ise kapalı bekleyen sağlam davranıştır — aşağıdaki defterde on iki haftalık dönemin sonunda hâlâ kapalı duran, kusurla ilgisi olmayan, tamamlanmış ve dağıtılmış bir değişiklik vardır.
Üçüncüsü eklediği süre. Bu kapı öncü süreye dakika eklemez: kod yine tek yayında gider, hat aşamaları değişmez. Eklediği şey ertelenmiş turdur — okuma noktalarının yazılması ve sonra silinmesi. Erteleme bedava göründüğü için ödenmez ve borç olarak birikir. Kapının üçüncü sayısı bu derste dakika değil, temizlenmemiş okuma noktası sayısıdır.
Bayrak Borcu
Bayrağın maliyeti eklendiği anda değil, kaldırılmadığı sürece ödenir. On iki haftalık bir dönemin defteri sayılır: hangi bayrak ne zaman eklendi, temizlendi mi, kaç noktada okunuyor.
// borc.mjs — bir donemin bayrak defteri sayilir; defter MODELDIR // [ad, eklendigi hafta, temizlendigi hafta (null: duruyor), okuma noktasi, bugunku deger] const DONEM = 12; const DEFTER = [ ['kademeli-tarife', 1, 6, 3, 'acik'], ['gecikme-faizi', 2, null, 2, 'kapali'], ['fatura-ozeti', 2, 7, 1, 'acik'], ['is-emri-baglantisi', 3, null, 4, 'acik'], ['toplu-is-raporu', 4, null, 2, 'acik'], ['dogrulayici-ikinci-gecis', 5, 9, 2, 'acik'], ['okuma-yeniden-deneme', 7, null, 5, 'acik'], ['sozlesme-uyarisi', 8, null, 3, 'kapali'], ['ozet-yeni-alan', 10, null, 2, 'acik'], ]; const temiz = DEFTER.filter(([, , t]) => t !== null); const kalan = DEFTER.filter(([, , t]) => t === null); const nokta = kalan.reduce((t, [, , , n]) => t + n, 0); const yasli = kalan.reduce((e, k) => (k[1] < e[1] ? k : e)); console.log(`donem : ${DONEM} hafta`); console.log(`eklenen / temizlenen / kalan : ${DEFTER.length} / ${temiz.length} / ${kalan.length}`); console.log(`temizlenenlerin ortalama omru: ` + `${(temiz.reduce((t, [, e, k]) => t + (k - e), 0) / temiz.length).toFixed(1)} hafta`); console.log(`kalan bayraklarin actigi yol : ${2 ** kalan.length}`); console.log(`bugun kosan yol : 1 (kalanlarin degeri sabit)`); console.log(`olu kod yolu : ${2 ** kalan.length - 1}`); console.log(`her bayrak tek basina sinanirsa: ${kalan.length + 1} yol` + ` (yuzde ${((kalan.length + 1) / 2 ** kalan.length * 100).toFixed(0)})`); console.log(`temizlenecek okuma noktasi : ${nokta}`); console.log(`acilmayi bekleyen kapali bayrak: ` + kalan.filter(([, , , , d]) => d === 'kapali').map(([a, e]) => `${a} (${DONEM - e} hafta)`).join(', ')); console.log(`en yasli temizlenmemis bayrak: ${yasli[0]} — ${DONEM - yasli[1]} hafta`);
donem : 12 hafta eklenen / temizlenen / kalan : 9 / 3 / 6 temizlenenlerin ortalama omru: 4.7 hafta kalan bayraklarin actigi yol : 64 bugun kosan yol : 1 (kalanlarin degeri sabit) olu kod yolu : 63 her bayrak tek basina sinanirsa: 7 yol (yuzde 11) temizlenecek okuma noktasi : 18 acilmayi bekleyen kapali bayrak: gecikme-faizi (10 hafta), sozlesme-uyarisi (4 hafta) en yasli temizlenmemis bayrak: gecikme-faizi — 10 hafta
Altı bayrak kaldı ve altmış dört kod yolu açtı. Bugün bu yollardan yalnız biri koşuyor, çünkü altı bayrağın da değeri sabit. Kalan altmış üçü ölü kod yoludur: hiçbiri çalışmıyor, hepsi kodda duruyor ve her biri sınanabilir bir davranış olarak var sayılıyor. Sınama kümesi aynı kalıpla — her bayrak tek başına — genişletilirse altmış dört yolun yedisini örter; oran yüzde elliden yüzde on bire düşer. Bayrak sayısı doğrusal artarken kapsama üstel olarak seyrelir.
On sekiz okuma noktası, bu bayrakların temizlenmesi için silinecek koşul sayısıdır. Bu iş ertelendikçe kod okunmaz hâle gelir, ama daha önemlisi, hangi dalın canlı olduğu kodun kendisinden okunamaz olur. Temizlenen üç bayrağın ortalama ömrü dört buçuk haftaydı; kalanlardan biri on haftadır duruyor. İki bayrak kapalı bekliyor: biri kusurlu, biri tamamlanmış ama hiç açılmamış. İkincisi kapının yanlış tuttuğu değişikliktir — dört haftadır üretimde duran ve hiçbir aboneye ulaşmayan bir davranış.
Kaldırılması gereken kapı burada görünür hâle gelir. kademeli-tarife altıncı haftada
temizlendi: bayrak açılmış, davranış kalıcı olmuş, koşul silinmiştir. Kapının kaldırılması
kapının kurulması kadar plana girer; girmediğinde defterdeki tek sayı büyür.
Özet
- Bayrak geri alma birimini kodun tamamından tek davranışa indirdi: bayraksız düzende üretimden dört değişiklik çıktı ve üçü sağlamdı, bayraklı düzende çıkan tek şey kusurlu davranıştı.
- Geri alma turu ikiden bire, etkilenen fatura yüz altmıştan seksen dörde indi; farkın tamamı geri alma yolunun kısalmasından geldi, kusurun daha erken görülmesinden değil.
- Üç bayrak sekiz kod yolu açtı; her bayrağı tek başına sınayan küme dördünü kapsadı ve sapan davranış üreten iki yolun ikisi de kapsam dışında kaldı.
- Bayrak koşulu kusur tutmaz — tuttuğu şey maruziyettir; kaçırdığı yolları ise kendisi üretir.
- On iki haftada dokuz bayrak eklendi, üçü temizlendi; kalan altı bayrak altmış dört yol açtı, bunların altmış üçü ölü kod yolu olarak durdu ve on sekiz okuma noktası temizlenmeyi bekledi.
Sonraki Adım
Bayrak kapatmak, geri alınabilecek şey bir davranışsa işe yarar. Kusur bir bayrağın arkasında durmuyorsa — yapılandırma değişmişse, veri dönüştürülmüşse ya da değişiklik bayraklanmadan yayınlanmışsa — geri dönüş yolu tek anahtar değil, sıralı bir adım listesidir. O listenin kaç adım olduğu, her adımın kaç tur sürdüğü ve hangi adımdan sonra geri dönüşün kapandığı ayrı ayrı ölçülür. Sonraki ders geri almayı bir düğme olarak değil, plan olarak ele alır ve planın prova edilip edilmemesinin ilk koşumda kaç adıma mal olduğunu sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.