Ders 09 / 21
Dal Stratejisi ve Hat İlişkisi
Uzun ömürlü dal düzeni ile gövde tabanlı geliştirme aynı doksan değişikliklik akışta koşturulur: dal ömrü, çatışan dosya, tümleştirme başına kapı koşumu ve tümleştirme kapısının hangi düzende ne zaman koştuğu sayılır. Gövde tabanlının bedeli olan gizleme kaydı ayrıca ölçülür.
İçindekiler
Hat kuruldu: aşamaları sıralandı, her aşamanın kapısı tanımlandı ve her kapının tuttuğu, kaçırdığı, beklettiği sayıldı. Bu, değişikliğin üretime nasıl gireceğini söylemez. Hattın varlığı bir akış düzeni değildir; akış düzenini, değişikliğin ortak gövdeye ne zaman katıldığı ve oradan üretime hangi adımlarla ilerlediği belirler. Bu konu o kararları ölçer, ilkinden başlayarak.
İlk karar şudur: bir geliştiricinin yazdığı değişiklik ortak gövdeye ne zaman girer. İki uç düzen var. Uzun ömürlü dal düzeninde iş kendi dalında birikir ve haftalar sonra bir kerede birleşir. Gövde tabanlı düzende her değişiklik yazıldığı gün gövdeye katılır. Bu iki düzen aynı işi, aynı kişilerle, aynı kusur kümesiyle taşır — ama üzerlerindeki tümleştirme kapısı farklı anlarda, farklı büyüklükte parçalar üzerinde koşar. Kapı burada bir kabul kararıdır: değişikliğin ortak gövdeye alınmasına izin verir ya da vermez. Zincirdeki ilk terfi kararıdır.
- YS1. Kurgusal bölgesel ölçüm ağının doğrulayıcı servisi tek depoda tutulur. Altı geliştirici, altmış iş günü, doksan değişiklik, kırk kaynak dosyası. Ağ da rakamlar da kurgudur.
- YS2. Bir özellik tek yazarınındır ve ardışık günlerde bir ile beş parça hâlinde yazılır. Devredilen iş, birlikte yazılan özellik ve eşli çalışma modelin dışındadır.
- YS3. Kusur kümesi üç sınıftır: yalıtılmış kusur (dal üstünde de görünür), etkileşim kusuru (yalnız iki değişiklik de gövdeye girdikten sonra görünür), üretim verisine bağlı kusur (hiçbir tümleştirme kapısında görünmez).
- YS4. Dal üstünde koşan yerel kapı yalıtılmış kusurların tamamını yakalar. Tümleştirme kapısının marjinal katkısı bu yüzden etkileşim kusurlarıdır.
- YS5. Kapının bir koşumu on dört dakikadır; kırmızı parti düzeltilip bir kez daha koşar. Düzeltmenin insan süresi ve sıra bekleme modelin dışındadır.
- YS6. Çatışma dosya düzeyinde sayılır. Satır düzeyinde çakışma, yeniden adlandırma ve dosya taşıma modellenmiyor. Kararsız kırmızı olasılığı yüzde altıdır ve yalnız gerçek kusur yokken ayırt edilebilir.
Ölçüm Düzeneği
Ölçülen şey gerçek bir depo değil, node ile kurulan bir modeldir. Model bir değişiklik akışı
üretir, bu akışı iki farklı birleşme düzeninde tüketir ve her düzende kapının ne zaman, kaç
değişiklik üzerinde koştuğunu sayar. Rastgelelik üreteci kendi yazılmıştır, tohumu görünürdür.
// dal.mjs — iki dal duzeninin ayni degisiklik akisindaki modeli; gercek depo degil, bir modeldir export const TOHUM = 20260901; export const GUN = 60, DEGISIKLIK = 90, GELISTIRICI = 6, DOSYA = 40; export const KAPI_DK = 14, YEREL = 0.10, URETIM = 0.08, CIFT = 0.06, KARARSIZ = 0.06; export function uretec(tohum) { // dogrusal eslesik uretec, tohum gorunur let x = tohum >>> 0; return () => { x = (Math.imul(x, 1664525) + 1013904223) >>> 0; return x / 4294967296; }; } // Akis bir kez uretilir: iki duzen de ayni degisiklikleri ve ayni kusur kumesini tuketir. // Bir ozellik tek yazarindir ve ardisik gunlerde birkac parca halinde yazilir. export function akis() { const rnd = uretec(TOHUM), l = []; while (l.length < DEGISIKLIK) { const yazar = Math.floor(rnd() * GELISTIRICI), bas = 1 + Math.floor(rnd() * (GUN - 5)); const parca = 1 + Math.floor(rnd() * 5), oz = l.length && l[l.length - 1].ozellik + 1 || 0; for (let j = 0; j < parca && l.length < DEGISIKLIK; j += 1) { const d = new Set(); // sicak dosya egilimi: kare, kucuk indisi siklestirir for (let k = 0, n = 1 + Math.floor(rnd() * 3); k < n; k += 1) d.add(Math.floor(rnd() ** 2 * DOSYA)); l.push({ no: l.length, yazar, gun: bas + j, dosya: [...d], ozellik: oz, yerel: rnd() < YEREL, uretim: rnd() < URETIM }); } } return l.sort((a, b) => a.gun - b.gun || a.no - b.no); } // Etkilesim kusuru bir cifte aittir: ayni dosyaya dokunan, farkli yazarlardan iki degisiklik. // Yalitilmis dalda gorunmez; ancak ikisi de govdeye girdikten sonra ortaya cikar. export function ciftler(l) { const c = []; for (let i = 0; i < l.length; i += 1) for (let j = i + 1; j < l.length; j += 1) { if (l[i].yazar === l[j].yazar || !l[i].dosya.some((f) => l[j].dosya.includes(f))) continue; let h = Math.imul(l[i].no + 1, 2654435761) ^ Math.imul(l[j].no + 1, 40503); if ((Math.imul(h ^ (h >>> 13), 1274126177) >>> 0) / 4294967296 < CIFT) c.push([l[i].no, l[j].no]); } return c; } // aralik 0: govde tabanli, her degisiklik tek basina tumlesir. aralik k: yazar dali k gunde bir birlesir. export function kostur(l, cift, aralik) { const rnd = uretec(TOHUM + 7), birlesim = new Map(), parti = new Map(); for (const c of l) { const gun = aralik === 0 ? c.gun : Math.ceil(c.gun / aralik) * aralik; const anahtar = aralik === 0 ? `t${c.no}` : `${c.yazar}:${gun}`; birlesim.set(c.no, gun); if (!parti.has(anahtar)) parti.set(anahtar, { gun, yazar: c.yazar, uye: [] }); parti.get(anahtar).uye.push(c); } const s = { parti: parti.size, kosum: 0, kirmizi: 0, temizDur: 0, kararsizDur: 0, catisan: 0, yerel: 0, etkilesim: 0, kacan: 0, yas: 0 }; const govde = new Map(); for (const p of [...parti.values()].sort((a, b) => a.gun - b.gun)) { const taban = p.gun - (aralik || 1), suclu = new Set(); for (const f of new Set(p.uye.flatMap((c) => c.dosya))) { const iz = govde.get(f); if (iz && iz.yazar !== p.yazar && iz.gun > taban) s.catisan += 1; govde.set(f, { yazar: p.yazar, gun: p.gun }); } for (const c of p.uye) { s.yas += p.gun - c.gun; if (c.uretim) s.kacan += 1; if (c.yerel) { suclu.add(c.no); s.yerel += 1; } } for (const [a, b] of cift) { // gec gelen uyenin partisinde gorunur if (Math.max(birlesim.get(a), birlesim.get(b)) !== p.gun) continue; const gec = p.uye.find((c) => c.no === b) || p.uye.find((c) => c.no === a); if (!gec || birlesim.get(a) === birlesim.get(b) && !p.uye.some((c) => c.no === a)) continue; suclu.add(gec.no); s.etkilesim += 1; } s.kosum += 1; const kararsiz = suclu.size === 0 && rnd() < KARARSIZ; if (suclu.size || kararsiz) { // kirmizi parti duzeltilir ve yeniden kosar s.kirmizi += 1; s.kosum += 1; s.temizDur += p.uye.length - suclu.size; if (kararsiz) s.kararsizDur += p.uye.length; } } return { ...s, yas: s.yas / l.length, buyukluk: l.length / parti.size, dk: s.kosum * KAPI_DK }; }
Modelin tek ayarı aralik. Sıfır olduğunda her değişiklik kendi başına tümleşir; bu gövde
tabanlı düzendir. On olduğunda bir yazarın on gün içinde yazdığı ne varsa tek partide birleşir;
bu uzun ömürlü dal düzenidir. Kusur kümesi ise aralik ne olursa olsun aynıdır — etkileşim
kusuru bir çifte aittir ve o çiftin iki üyesi de er geç gövdeye girer.
İki Düzen, Aynı Akış
// kosum1.mjs — ayni akis iki dal duzeninde kosturulur import { akis, ciftler, kostur, TOHUM, DEGISIKLIK, GELISTIRICI, KAPI_DK } from './dal.mjs'; const l = akis(), c = ciftler(l); console.log(`tohum ${TOHUM} | ${DEGISIKLIK} degisiklik, ${GELISTIRICI} gelistirici, 60 is gunu`); console.log(`kusur kumesi: ${l.filter((x) => x.yerel).length} yalitilmis kusur, ${c.length} etkilesim kusuru, ` + `${l.filter((x) => x.uretim).length} uretim verisine bagli kusur`); console.log(`tumlestirme kapisi kosumu ${KAPI_DK} dk\n`); console.log('duzen tumlestirme parti dal omru catisan kapi yalniz bosuna kapi'); console.log(' sayisi boyu (gun) dosya kosumu kapida duran dakikasi'); for (const [ad, aralik] of [['govde tabanli', 0], ['uzun omurlu dal', 10]]) { const s = kostur(l, c, aralik); console.log(`${ad.padEnd(18)} ${String(s.parti).padEnd(12)} ${s.buyukluk.toFixed(2).padEnd(6)} ` + `${s.yas.toFixed(2).padEnd(9)} ${String(s.catisan).padEnd(8)} ${String(s.kosum).padEnd(8)} ` + `${String(s.etkilesim).padEnd(7)} ${String(s.temizDur).padEnd(8)} ${s.dk}`); }
tohum 20260901 | 90 degisiklik, 6 gelistirici, 60 is gunu
kusur kumesi: 10 yalitilmis kusur, 24 etkilesim kusuru, 8 uretim verisine bagli kusur
tumlestirme kapisi kosumu 14 dk
duzen tumlestirme parti dal omru catisan kapi yalniz bosuna kapi
sayisi boyu (gun) dosya kosumu kapida duran dakikasi
govde tabanli 90 1.00 0.00 8 117 24 2 1638
uzun omurlu dal 20 4.50 4.47 44 35 24 54 490
İki düzen de aynı yirmi dört etkileşim kusurunu yakaladı. Kapının tuttuğu sayı değişmiyor; değişen, o sayıyı ne zaman ve ne kadar temiz işi durdurarak tuttuğu.
Zamanı dal ömrü sütunu veriyor. Gövde tabanlı düzende bir değişiklik yazıldığı gün kapıya giriyor; ortalama yaş sıfır. Dal düzeninde ortalama dört buçuk gün bekliyor, çünkü kapı yalnız birleşme anında koşuyor. Dal üstündeki yerel kapı bu süre boyunca çalışıyor ama on yalıtılmış kusurdan başkasını göremiyor: etkileşim kusuru tanım gereği iki değişikliğin buluşmasını bekliyor. Yani dal düzeninde kapıların yarısı erken, ayırt edici olanı geç koşuyor.
Bedeli boşuna duran sütunu gösteriyor. Gövde tabanlı düzende bir parti tek değişikliktir; kapı kırmızı olduğunda duran şey yalnız suçlu değişikliktir, boşuna duran iki tanedir ve ikisi de kararsız kırmızıdan gelir. Dal düzeninde parti ortalama dört buçuk değişikliktir; kapı kırmızı olduğunda partinin tamamı durur ve elli dört temiz değişiklik kendi kusuru olmayan bir şey yüzünden bekler. Aynı yirmi dört kusuru yakalamanın bedeli bir düzende iki, ötekinde elli dört gereksiz duruştur.
Süre sütunu tersine dönüyor. Gövde tabanlı düzen bin altı yüz otuz sekiz kapı dakikası harcadı, dal düzeni dört yüz doksan. Kapı koşumu başına makine süresi aynı; fark koşum sayısında. Dal düzeninde tümleştirme başına yirmi dört buçuk dakika kapı süresi düşüyor, gövde tabanlıda on sekiz — ama gövde tabanlı bunu doksan kez ödüyor. Kapıyı seyrek koşturmak makine süresini üçte bire indirir; kapının ayırt ettiği kusuru bulmasını da geciktirir.
Birleşme Aralığı Taraması
İki uç arasında ne olduğunu görmek için aralık taranır. Aynı tarama, gövde tabanlı düzenin faturasını da çıkarır: yarım kalan iş gövdededir ve üretime sızmaması için ayrı bir düzen ister.
// kosum2.mjs — birlesme araligi taranir; govde tabanlinin bedeli olan yarim is ayrica sayilir import { akis, ciftler, kostur } from './dal.mjs'; // Govdede yarim duran ozellik: ilk parcasi girmis, son parcasi girmemis ozellik. function yarimIs(l, aralik) { const gun = (c) => (aralik === 0 ? c.gun : Math.ceil(c.gun / aralik) * aralik); const oz = new Map(); for (const c of l) { if (!oz.has(c.ozellik)) oz.set(c.ozellik, []); oz.get(c.ozellik).push({ g: gun(c), yazar: c.yazar }); } let kayit = 0, ozSayi = 0; for (const p of oz.values()) { const son = Math.max(...p.map((x) => x.g)); // son parcadan once giren her parca gizlenmeli const erken = p.filter((x) => x.g < son).length; kayit += erken; ozSayi += erken > 0 ? 1 : 0; } return { kayit, ozSayi, ozellik: oz.size }; } const l = akis(), c = ciftler(l); console.log(`${l.length} degisiklik ${yarimIs(l, 0).ozellik} ozellige ait; parca sayisi 1-5 arasi\n`); console.log('aralik parti dal omru catisan kapi kirmizi bosuna kararsiz kapi gizleme gizleyen'); console.log('(gun) boyu (gun) dosya kosumu parti duran durdurdu dakikasi kaydi ozellik'); for (const a of [0, 1, 2, 3, 5, 10, 20]) { const s = kostur(l, c, a), y = yarimIs(l, a); console.log(`${String(a || 'govde').padEnd(7)} ${s.buyukluk.toFixed(2).padEnd(6)} ${s.yas.toFixed(2).padEnd(9)} ` + `${String(s.catisan).padEnd(8)} ${String(s.kosum).padEnd(7)} ${String(s.kirmizi).padEnd(8)} ` + `${String(s.temizDur).padEnd(7)} ${String(s.kararsizDur).padEnd(9)} ${String(s.dk).padEnd(9)} ` + `${String(y.kayit).padEnd(8)} ${y.ozSayi}`); }
90 degisiklik 30 ozellige ait; parca sayisi 1-5 arasi aralik parti dal omru catisan kapi kirmizi bosuna kararsiz kapi gizleme gizleyen (gun) boyu (gun) dosya kosumu parti duran durdurdu dakikasi kaydi ozellik govde 1.00 0.00 8 117 27 2 2 1638 60 23 1 1.30 0.00 8 95 26 9 2 1330 60 23 2 2.09 0.47 18 67 24 31 2 938 46 20 3 2.73 0.98 24 55 22 43 1 770 38 16 5 3.33 2.08 37 46 19 48 0 644 25 12 10 4.50 4.47 44 35 15 54 0 490 13 6 20 6.43 9.80 59 25 11 56 0 350 1 1
Tarama iki eğriyi karşı karşıya getiriyor. Aralık büyüdükçe kapı dakikası bin altı yüz otuz sekizden üç yüz elliye iniyor, çatışan dosya sekizden elli dokuza çıkıyor, boşuna duran değişiklik ikiden elli altıya. Üç günlük aralık ilginç bir orta nokta: kapı dakikası yarıya inmiş, ama boşuna duran değişiklik iki katından fazlasına çıkmış. Değiş tokuş doğrusal değil — makine süresinden kazanılan her dakika, bir noktadan sonra kendi kusuru olmayan işlerin bekleme süresine dönüşüyor.
Kırılgan sütunu sessiz bir bulgu taşıyor. Aralık beş günü geçtiğinde kırılgan koşumun boşuna durdurduğu değişiklik sıfıra iniyor. Kırılganlık azalmadı; partilerin neredeyse hepsi zaten gerçek bir kusur taşıdığı için kırılgan koşum ayırt edilemez oldu. Bir kapının yanlış tuttuğunu sayabilmek, o kapının çoğu zaman yeşil olmasını gerektirir. Kırmızının olağan olduğu düzende kapının yanlış tutması ölçülemez hâle gelir — ve ölçülemeyen yanlış tutma, ekipte kapıyı atlama alışkanlığına dönüşür.
Son iki sütun gövde tabanlının faturasıdır. Doksan değişiklik otuz özelliğin parçasıdır; gövde tabanlı düzende bunların altmışı, ait olduğu özellik tamamlanmadan gövdeye girer. Yirmi üç özellik yarım hâlde gövdede durur. Bu değişikliklerin üretime sızmaması için her birinin gizleme kaydı taşıması gerekir: kod gövdede olacak, davranış kapalı kalacak. On günlük dal düzeninde bu sayı on üçe, yirmi günlük düzende bire iner — çünkü yarım iş dalda saklıdır.
Gövde tabanlı düzenin bedeli buradadır ve kapı dakikası kadar somuttur: altmış gizleme kaydı, yirmi üç özellik için açılıp kapanacak birer anahtar, ve özellik bittikten sonra o anahtarları kaldıracak yirmi üç ayrı temizlik işi. Bu, gövde tabanlı düzenin bir yan etkisi değil, giriş koşuludur. Gizleme düzeni kurulmadan gövde tabanlıya geçen ekip, yarım işi üretime sızdıran bir düzen kurmuş olur.
Kapının Üç Sayısı
Tümleştirme kapısının hesabı bu ölçümle kapanıyor. Tuttuğu: doksan değişikliklik akışta on yalıtılmış ve yirmi dört etkileşim kusuru, toplam otuz dört. Yalnız kendisinin tuttuğu: yirmi dört — yalıtılmış kusurları dal üstündeki yerel kapı da yakalardı, etkileşim kusurunu yalnız tümleştirme kapısı görebilir. Kapının marjinal değeri bu yirmi dörttür ve iki düzende de aynıdır.
Kaçırdığı: sekiz üretim verisine bağlı kusur, iki düzende de. Bu sayı dal stratejisiyle değişmiyor; kapının göremediği şeyi birleşme sıklığı görünür kılmıyor. Yanlış tuttuğu: gövde tabanlıda iki, on günlük dal düzeninde elli dört temiz değişiklik. Eklediği süre: tümleştirme başına on sekiz ile yirmi dört buçuk dakika arasında; toplamda dört yüz doksan ile bin altı yüz otuz sekiz dakika arasında.
Bu sayılarla bakıldığında karar “hangi düzen daha iyi” değil. Kapının değeri sabit; seçilen şey, o sabit değeri hangi para birimiyle ödeyeceğidir — makine dakikasıyla mı, yoksa temiz işin bekleme süresi ve çatışma çözümüyle mi.
Özet
- Aynı akış iki düzende koşturuldu: tümleştirme kapısı iki düzende de yirmi dört etkileşim kusurunu tuttu, sekiz üretim verisine bağlı kusuru ikisinde de kaçırdı.
- Ayrılık kapının ne zaman koştuğunda: gövde tabanlıda değişiklik sıfır günlükken, on günlük dal düzeninde ortalama dört buçuk günlükken. Dal üstündeki yerel kapı erken koşar ama etkileşim kusurunu göremez.
- Parti büyüdükçe yanlış tutmanın bedeli büyür: boşuna durdurulan temiz değişiklik gövde tabanlıda iki, on günlük aralıkta elli dört. Çatışan dosya sekizden kırk dörde çıkar.
- Kapı dakikası ters yönde çalışır: gövde tabanlı bin altı yüz otuz sekiz, on günlük aralık dört yüz doksan dakika. Seyrek koşan kapı ucuzdur ve geç konuşur.
- Aralık beş günü geçtiğinde kırılgan koşum ayırt edilemez olur, çünkü partilerin çoğu zaten kırmızıdır; ölçülemeyen yanlış tutma kapıyı atlama alışkanlığına dönüşür.
- Gövde tabanlının bedeli sayıldı: altmış gizleme kaydı, yirmi üç özellik ve sonrasında yirmi üç temizlik işi. Bu düzen kurulmadan gövde tabanlıya geçmek yarım işi üretime açar.
Sonraki Adım
Bu ölçüm değişikliğin gövdeye girdiği anda bitiyor. Gövdeye giren şey henüz üretimde değil: arada en az bir yapı çıktısı ve birkaç ortam var. Bir sonraki soru, o çıktının ortamlar arasında nasıl ilerlediğidir. Aynı yapı çıktısı mı terfi ediyor, yoksa her ortam kendi derlemesini mi yapıyor. Sonraki ders iki düzeni aynı aday dizisinde koşturur: ortama özgü kusur sayısı, terfi kapısının tuttuğu, çıktının kimliğinin ortamlar arasında korunup korunmadığı ve terfi kapısında bekleyen çıktının bekleme süresi ölçülür.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.