Ders 06 / 27
Başarım Bütçesi
Başarım kararlarının yazılı bir sınıra bağlanması; bütçe türleri, sınırın nereden türetildiği, derleme çıktısını denetleyen bir program ve iki derlemeyi karşılaştırarak gerilemenin yakalanması.
İçindekiler
Önceki beş ders bir dizi iyileştirme kurdu: ölçütler tanımlandı, kritik yol kısaltıldı, varlıklar boyutlandırıldı, ağ katmanı ayarlandı, çalışma zamanı boşaltıldı. Hepsinin ortak açığı aynıdır — bir kez yapılmış olmaları.
Yeni bir özellik eklendiğinde paket büyür, bir kütüphane ortak parçaya girdiğinde tekrar ziyaret kazancı erir. Erimenin bir sonraki yayında fark edilmesi gerekir. Bu ders o mekanizmayı kurar.
Bütçe Bir Hedef Değildir
İkisi karıştırılır ve karıştırıldığında bütçe işlevini yitirir.
Hedef, ulaşılmak istenen değerdir. Yönü vardır, yaptırımı yoktur; aşıldığında bir şey olmaz.
Bütçe, aşılmasına izin verilmeyen sınırdır. Aşıldığında bir şey olur: derleme başarısız sayılır, birleştirme durur, sürüm çıkmaz. Yaptırımı olmayan bir sayı bütçe değildir.
Ayrımın pratik sonucu şudur: bütçe, ulaşılabilir bir yerde çizilir. Şu anki değerin çok altına konan bir sınır ilk günden kırmızı yanar ve kısa sürede yok sayılmaya başlar. Doğru yaklaşım, sınırı bugünkü değerin biraz üstüne koymak ve zamanla indirmektir.
Üç Bütçe Türü
Bütçeler ölçtükleri şeye göre ayrılır ve üçü de gerekir, çünkü her biri diğerinin kaçırdığını yakalar.
Ölçüt bütçesi kullanıcı merkezli ölçütlere sınır koyar: en büyük içerik boyası şu değerin altında kalacak, kümülatif düzen kayması şu puanı aşmayacak. Doğrudan deneyimi ölçtüğü için en anlamlı bütçedir; en gürültülü olanı da budur, çünkü ölçüm koşullarına duyarlıdır.
Nicelik bütçesi sayılabilir büyüklüklere sınır koyar: parça boyutları, istek sayısı, görsel ağırlığı, yazı tipi dosyası sayısı. Belirlenimcidir — aynı derleme her zaman aynı sayıyı üretir — ve bu yüzden yaptırıma en uygun bütçedir. Deneyimle bağı dolaylıdır: küçük bir paket her zaman hızlı bir sayfa demek değildir.
Kural bütçesi sayı değil koşul içerir: ilk ekranda çizimi engelleyen dış biçem bulunmayacak, belgede eşzamanlı betik olmayacak, en büyük içerik boyasına aday görsel gecikmeli yüklenmeyecek. Bir sayıya indirgenemeyen kararları korur.
Sağlam bir düzen üçünü birleştirir: nicelik ve kural bütçeleri her derlemede, ölçüt bütçesi düzenli aralıklarla denetlenir.
Sınır Nereden Gelir
Bir sayının bütçe olabilmesi için gerekçesi olmalıdır. Üç gerekçelendirme yolu vardır.
Ölçütün standart eşiğinden türetme. İlk derste anılan sınıflandırma sınırları — en büyük içerik boyası için iki buçuk saniye, kümülatif düzen kayması için sıfır virgül bir, sonraki boyaya etkileşim için iki yüz milisaniye — doğrudan ölçüt bütçesi olarak yazılabilir. Denetim yetmiş beşinci yüzdeliğe uygulanır.
Ölçütten niceliğe geri hesap. Hedef bir ölçüt değeri seçilir, hedef bir ağ ve aygıt profili varsayılır, aradaki bütçe baytlara çevrilir. Kritik Oluşturma Yolu dersindeki gidiş-dönüş modeli bu hesabın iskeletidir: kaç tur harcanabileceği belirlenince kaç bayt gönderilebileceği çıkar.
Bugünkü değerden pay bırakarak. En pratik ve en az iddialı yol. Ölçülen değerin üzerine küçük bir pay eklenir ve sınır oraya konur. Bu bütçe iyileştirme getirmez; kötüleşmeyi durdurur. Çoğu takım için doğru başlangıç budur.
Hangi yol seçilirse seçilsin bütçe yazılı olmalı ve depoda durmalıdır. Kimsenin göremediği bir sınır, olmayan bir sınırdır.
Denetleyici
Aşağıdaki program bir derleme dökümünü bütçeyle karşılaştırır, sonra iki derlemeyi karşılaştırıp gerilemeyi bildirir.
// butce.mjs — parca boyutlarini butceyle karsilastirir ve iki derleme arasindaki gerilemeyi bulur const KB = 1024; // Butce: her grup icin toplama kurali, ust sinir (bayt) ve buyume toleransi (oran). // "toplam" grubun tamamini olcer; "enBuyuk" gruptaki en agir tek parcayi olcer. const BUTCE = { giris: { toplama: "toplam", sinir: 170 * KB, tolerans: 0.03 }, ortak: { toplama: "toplam", sinir: 120 * KB, tolerans: 0.03 }, rota: { toplama: "enBuyuk", sinir: 45 * KB, tolerans: 0.05 }, bicem: { toplama: "toplam", sinir: 40 * KB, tolerans: 0.05 }, }; const TOPLAM_SINIR = 360 * KB; // Derleme dokumu: her parcanin adi, grubu ve sikistirilmis boyutu. const oncekiDerleme = [ { ad: "giris.4a1c.js", grup: "giris", bayt: 148_112 }, { ad: "ortak.9d02.js", grup: "ortak", bayt: 101_760 }, { ad: "rota-istasyonlar.1f77.js", grup: "rota", bayt: 38_240 }, { ad: "rota-olcum.55be.js", grup: "rota", bayt: 21_904 }, { ad: "istasyon.6b3e.css", grup: "bicem", bayt: 31_648 }, ]; const yeniDerleme = [ { ad: "giris.7e90.js", grup: "giris", bayt: 151_296 }, { ad: "ortak.c214.js", grup: "ortak", bayt: 124_368 }, { ad: "rota-istasyonlar.02ab.js", grup: "rota", bayt: 39_120 }, { ad: "rota-olcum.55be.js", grup: "rota", bayt: 21_904 }, { ad: "rota-rapor.8c4d.js", grup: "rota", bayt: 17_856 }, { ad: "istasyon.a9f1.css", grup: "bicem", bayt: 32_960 }, ]; const kb = (bayt) => `${(bayt / KB).toFixed(1)} KB`; function gruplaraTopla(derleme) { const olcu = new Map(); for (const [grup, { toplama }] of Object.entries(BUTCE)) { const parcalar = derleme.filter((p) => p.grup === grup).map((p) => p.bayt); olcu.set(grup, toplama === "enBuyuk" ? Math.max(0, ...parcalar) : parcalar.reduce((a, b) => a + b, 0)); } return olcu; } const tumToplam = (derleme) => derleme.reduce((t, p) => t + p.bayt, 0); // --- 1. Butce denetimi --- function denetle(derleme, baslik) { const toplamlar = gruplaraTopla(derleme); let gecti = true; console.log(`--- ${baslik} ---`); console.log("grup".padEnd(8) + "kural".padEnd(9) + "boyut".padStart(11) + "sinir".padStart(11) + "kullanim".padStart(10) + " sonuc"); for (const [grup, { sinir, toplama }] of Object.entries(BUTCE)) { const boyut = toplamlar.get(grup); const kullanim = boyut / sinir; const sonuc = boyut <= sinir ? "gecti" : "KALDI"; if (boyut > sinir) gecti = false; console.log(grup.padEnd(8) + toplama.padEnd(9) + kb(boyut).padStart(11) + kb(sinir).padStart(11) + `${(kullanim * 100).toFixed(1)}%`.padStart(10) + " " + sonuc); } const genelToplam = tumToplam(derleme); const toplamSonuc = genelToplam <= TOPLAM_SINIR ? "gecti" : "KALDI"; if (genelToplam > TOPLAM_SINIR) gecti = false; console.log("-".repeat(55)); console.log("TOPLAM".padEnd(8) + "toplam".padEnd(9) + kb(genelToplam).padStart(11) + kb(TOPLAM_SINIR).padStart(11) + `${((genelToplam / TOPLAM_SINIR) * 100).toFixed(1)}%`.padStart(10) + " " + toplamSonuc); console.log(`butce denetimi: ${gecti ? "gecti" : "KALDI"}\n`); return gecti; } denetle(oncekiDerleme, "onceki derleme"); const yeniGecti = denetle(yeniDerleme, "yeni derleme"); // --- 2. Gerileme tespiti: sinirin altinda kalan buyume de bildirilir --- console.log("--- iki derlemenin karsilastirmasi ---"); const eski = gruplaraTopla(oncekiDerleme); const yeni = gruplaraTopla(yeniDerleme); console.log("grup".padEnd(8) + "onceki".padStart(11) + "yeni".padStart(11) + "fark".padStart(11) + "oran".padStart(9) + " uyari"); const uyarilar = []; for (const [grup, { tolerans }] of Object.entries(BUTCE)) { const a = eski.get(grup); const b = yeni.get(grup); const oran = (b - a) / a; const asildi = oran > tolerans; if (asildi) uyarilar.push(`${grup}: %${(oran * 100).toFixed(1)} buyume (tolerans %${tolerans * 100})`); console.log(grup.padEnd(8) + kb(a).padStart(11) + kb(b).padStart(11) + `${b - a >= 0 ? "+" : ""}${((b - a) / KB).toFixed(1)} KB`.padStart(11) + `${oran >= 0 ? "+" : ""}${(oran * 100).toFixed(1)}%`.padStart(9) + " " + (asildi ? "TOLERANS ASILDI" : "-")); } // Yeni gelen parcalar ayrica bildirilir: adres degistigi icin ad karsilastirmasi // icerik karmasi cikarilarak yapilir. const kok = (ad) => ad.replace(/\.[0-9a-f]{4,}\./, "."); const eskiAdlar = new Set(oncekiDerleme.map((p) => kok(p.ad))); const yeniParcalar = yeniDerleme.filter((p) => !eskiAdlar.has(kok(p.ad))); console.log(`\nyeni parcalar: ${yeniParcalar.map((p) => `${kok(p.ad)} (${kb(p.bayt)})`).join(", ") || "(yok)"}`); if (uyarilar.length === 0) console.log("gerileme uyarisi: (yok)"); else { console.log("gerileme uyarisi:"); for (const u of uyarilar) console.log(` ${u}`); } const cikis = yeniGecti && uyarilar.length === 0 ? 0 : 1; console.log(`\ncikis kodu: ${cikis}`); process.exitCode = cikis;
--- onceki derleme --- grup kural boyut sinir kullanim sonuc giris toplam 144.6 KB 170.0 KB 85.1% gecti ortak toplam 99.4 KB 120.0 KB 82.8% gecti rota enBuyuk 37.3 KB 45.0 KB 83.0% gecti bicem toplam 30.9 KB 40.0 KB 77.3% gecti ------------------------------------------------------- TOPLAM toplam 333.7 KB 360.0 KB 92.7% gecti butce denetimi: gecti --- yeni derleme --- grup kural boyut sinir kullanim sonuc giris toplam 147.8 KB 170.0 KB 86.9% gecti ortak toplam 121.5 KB 120.0 KB 101.2% KALDI rota enBuyuk 38.2 KB 45.0 KB 84.9% gecti bicem toplam 32.2 KB 40.0 KB 80.5% gecti ------------------------------------------------------- TOPLAM toplam 378.4 KB 360.0 KB 105.1% KALDI butce denetimi: KALDI --- iki derlemenin karsilastirmasi --- grup onceki yeni fark oran uyari giris 144.6 KB 147.8 KB +3.1 KB +2.1% - ortak 99.4 KB 121.5 KB +22.1 KB +22.2% TOLERANS ASILDI rota 37.3 KB 38.2 KB +0.9 KB +2.3% - bicem 30.9 KB 32.2 KB +1.3 KB +4.1% - yeni parcalar: rota-rapor.js (17.4 KB) gerileme uyarisi: ortak: %22.2 buyume (tolerans %3) cikis kodu: 1
Derleme dökümleri programın girdisidir; ölçülmüş bir projenin çıktısı değil, denetleyicinin davranışını göstermek için yazılmış iki listedir.
Çıktının Söyledikleri
Bütçe tanımındaki toplama alanı önemli bir ayrımı taşır. Giriş, ortak ve biçem grupları
için sınır toplama uygulanır: bu parçaların hepsi her sayfada yüklenir. Rota grubu için
sınır en büyük tek parçaya uygulanır, çünkü kullanıcı bir seferde tek bir rotayı
yükler. Yanlış toplama kuralı, yeni bir rota eklendiğinde bütçeyi haksız yere kırar.
Yeni derleme iki yerde kalıyor. Ortak parça kendi sınırını yüzde bir buçuk aşmış; toplam ise sınırı yüzde beş aşmış. Toplamı aşan asıl neden ortak parçanın büyümesidir, ama yeni eklenen rota parçası da toplama katkı yapar. İki satırın birlikte okunması, sorunun tek bir değişiklikten mi yoksa birikimden mi geldiğini söyler.
Karşılaştırma tablosu bütçenin yakalayamadığını yakalıyor. Giriş parçası yüzde iki virgül bir büyümüş ve sınırın hâlâ çok altında; uyarı üretmiyor. Ortak parça yüzde yirmi iki büyümüş ve tolerans yüzde üç olduğu için uyarı üretiyor — bu parça sınırın altında kalsaydı bile uyarı yine üretilirdi.
Ayrım budur. Bütçe mutlak bir sınırı korur, tolerans değişim hızını korur. Yalnız bütçe denetlenirse, her yayında yüzde iki büyüyen bir paket aylarca sessiz kalır ve sınırı bir gün aniden aşar; o gün hangi değişikliğin sorumlu olduğu artık bulunamaz.
Yeni parçaların ayrıca bildirilmesi de bu yüzdendir. İçerik karmalı adlar her yayında değiştiği için karşılaştırma karma çıkarılarak yapılır; yoksa her parça yeni görünür.
Bütçenin Yayın Hattındaki Yeri
Denetleyicinin çıkış kodu döndürmesi tasarımın parçasıdır: derleme sonrası çalışan doğrulama adımlarında sıfırdan farklı bir çıkış kodu adımı durdurur. Kabuk Programlama kursunda kurulan kural burada yaptırımın taşıyıcısıdır.
İki karar gerekir. Nerede çalışacak? Değişiklik başına çalışan bir denetim, sorunu birleştirmeden önce bulur; yalnız ana dalda çalışan bir denetim, sorunu bulduğunda sorumlu değişikliği aramak gerekir.
Ne yapacak? Bütçe aşımının derlemeyi durdurması ile uyarı üretmesi arasındaki seçim, bütçenin ciddiyetini belirler. Durdurmayan bütçe hedefe dönüşür. Buna karşın bir kaçış kapısı gerekir: sınırın bilinçli olarak yükseltilebilmesi ve yükseltmenin bir kayıt bırakması. Bütçe dosyasında yapılan değişiklik incelemeye tabi olduğunda kaçış deliği da denetlenmiş olur.
Gürültü ve Yanlış Alarm
Nicelik bütçeleri belirlenimcidir; aynı girdiden aynı sayı çıkar. Ölçüt bütçeleri değildir ve doğrudan uygulandıklarında yanlış alarm üretirler.
Üç önlem gerekir. Ölçüm birden çok kez yapılır ve ortanca alınır; tek bir koşu karar için yeterli değildir. Ölçüm koşulları sabitlenir: aynı ağ kısıtlaması, aynı aygıt profili, eklentisiz tarayıcı — Ağ Panelinde Tanı dersindeki yeniden üretilebilirlik koşulları burada bütçenin ön şartıdır. Ve eşik, ölçümün doğal değişkenliğinden belirgin biçimde büyük seçilir; gürültünün içinde kalan bir tolerans, sürekli kırmızı yanan ve bu yüzden yok sayılan bir denetim üretir.
Bir de kapsam kararı vardır. Bütçe her sayfaya değil, temsilci sayfalara uygulanır: istasyon listesi sayfası ve ölçüm ayrıntısı sayfası. İlk ders bu iki sayfanın farklı ölçütlerle değerlendirildiğini göstermişti; bütçeleri de bu yüzden ayrı yazılır.
Özet
- Bütçe, aşıldığında bir şeyin olduğu sınırdır; yaptırımı olmayan sayı hedeftir ve kötüleşmeyi durdurmaz.
- Üç bütçe türü birbirinin açığını kapatır: ölçüt bütçesi deneyimi ölçer ama gürültülüdür, nicelik bütçesi belirlenimcidir ama dolaylıdır, kural bütçesi sayıya inmeyen kararları korur.
- Bütçe grubunun toplama kuralı sonucu değiştirir: her sayfada yüklenen parçalar toplanır, seçenekli parçalarda en büyüğü ölçülür.
- Mutlak sınır ile büyüme toleransı ayrı şeyleri korur; yalnız sınır denetlendiğinde küçük ve düzenli büyümeler sınıra ulaşana kadar görünmez kalır.
- Ölçüt bütçeleri ancak ölçüm koşulları sabitlenip birden çok koşunun ortancası alındığında yaptırıma bağlanabilir.
Sonraki Adım
Başarım artık bir görüş meselesi değil: tanımlı ölçütleri, yazılı sınırları ve her derlemede çalışan bir denetimi var. Kalite ekseninin tamamı bu değildir. Bir sayfa hızlı yüklenip yine de kullanılamaz olabilir — klavyeyle gezilemeyen bir liste, ekran okuyucuya hiçbir şey söylemeyen bir düğme, karşıtlığı yetersiz bir metin. Bu sorunlar da bir görüş meselesi olmak zorunda değildir; onların da tanımlı ölçütleri, ölçülebilir eşikleri ve uygunluk düzeyleri vardır. Sonraki ders erişilebilirlik standartlarını ele alır ve kullanılabilirliği aynı disiplinle — sınanabilir ölçütlerle — tanımlar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.