Ders 25 / 25
Çerçeve Seçimi
Ölçütlerin nereden okunacağı, ağırlıkların açık yazılması, sıralamanın duyarlılık çözümlemesiyle sınanması, kararın geri alınabilirliğinin satır düzeyinde ölçülmesi ve kararın yazılı hâle getirilmesi.
İçindekiler
Dört ailenin de özellikleri, maliyetleri ve bedelleri ortaya kondu. Geriye tek bir soru kalıyor ve bu sorunun yanıtı ailelerin özelliklerinde değil, projenin kendisindedir.
Bu ders bir karşılaştırma tablosu değildir. Böyle bir tablo, yazıldığı ay için bile eksiktir; bir yıl sonra yanıltıcı olur. Yerine kurulan şey, ölçütleri açık yazan, ağırlıkları görünür kılan ve kararın hangi varsayıma dayandığını söyleyen bir çerçevedir. Çerçeve değişmez; girdileri her projede yeniden doldurulur.
Ölçütler Nereden Okunur
Seçim tartışmalarının çoğu, farklı türden bilgileri aynı listeye koymaktan çıkmaz hâle gelir. Ölçütler üç kaynaktan gelir ve her birinin güvenilirliği farklıdır.
Aileden türetilebilen ölçütler, bu konudaki dört derste ölçüldü: güncelleme tanesi, çalışma zamanına inen kodun niteliği, derleme adımı gereksinimi, elle belleme yükü, dinamik yapılara uyum, güncellemenin bölünebilirliği, karar yüzeyinin genişliği. Bunlar ailenin tanımından çıkar ve bir ürünün belgesine bakmadan bilinir.
Adaydan okunan ölçütler belirli bir çerçevenin kendisine bakılarak ölçülür: belgelendirmenin niteliği, kırıcı değişiklik geçmişi, yayın düzeni, sorunların kapanma süresi, erişilebilirlik desteğinin durumu. Bunlar aileden çıkmaz ve zamanla değişir; karar anında ölçülmeleri gerekir.
Ekipten okunan ölçütler ne aileye ne adaya aittir: ekibin önceki deneyimi, öğrenme bütçesi, işe alım kolaylığı, projenin beklenen ömrü, bakımı kimin üstleneceği. Bunlar çoğu zaman en ağır basan ölçütlerdir ve teknik tartışmada en az konuşulanlardır.
Aşağıdaki model yalnızca birinci gruptaki ölçütleri puanlar; ikinci ve üçüncü gruptakiler ağırlık olarak değil, kararın kendisine giren bağımsız girdiler olarak ele alınır.
Ağırlıkları Açık Yazmak
// secim.mjs — karar cercevesi: acik agirliklar ve duyarlilik cozumlemesi // Puanlar (0-3) onceki derslerde olculen ozelliklerden gelir; urun degerlendirmesi degildir. const GUNCELLEME_MODELI = { "sanal ağaç tutan": { "ince taneli güncelleme": 1, "çalışma zamanı kodunun azlığı": 1, "derleme adımı gerektirmemesi": 3, "elle belleme gerektirmemesi": 0, "dinamik yapılara uyum": 3, "güncellemenin bölünebilirliği": 3, }, "çalışma zamanında bağımlılık izleyen": { "ince taneli güncelleme": 3, "çalışma zamanı kodunun azlığı": 2, "derleme adımı gerektirmemesi": 2, "elle belleme gerektirmemesi": 3, "dinamik yapılara uyum": 3, "güncellemenin bölünebilirliği": 1, }, "derleme zamanında tepkiselleştiren": { "ince taneli güncelleme": 3, "çalışma zamanı kodunun azlığı": 3, "derleme adımı gerektirmemesi": 0, "elle belleme gerektirmemesi": 3, "dinamik yapılara uyum": 1, "güncellemenin bölünebilirliği": 1, }, }; const KAPSAM = { "dar kapsamlı": { "karar yüzeyinin küçüklüğü": 0, "yükseltmenin bölünebilirliği": 3, "çıkışın kademeli olması": 3, "tek sözleşme": 1 }, "bütünleşik": { "karar yüzeyinin küçüklüğü": 3, "yükseltmenin bölünebilirliği": 0, "çıkışın kademeli olması": 0, "tek sözleşme": 3 }, }; const PROJELER = { "kamuya açık istasyon sayfası": { "ince taneli güncelleme": 1, "çalışma zamanı kodunun azlığı": 5, "derleme adımı gerektirmemesi": 1, "elle belleme gerektirmemesi": 2, "dinamik yapılara uyum": 1, "güncellemenin bölünebilirliği": 1, "karar yüzeyinin küçüklüğü": 2, "yükseltmenin bölünebilirliği": 2, "çıkışın kademeli olması": 3, "tek sözleşme": 1, }, "iç gözlem panosu": { "ince taneli güncelleme": 5, "çalışma zamanı kodunun azlığı": 1, "derleme adımı gerektirmemesi": 1, "elle belleme gerektirmemesi": 3, "dinamik yapılara uyum": 3, "güncellemenin bölünebilirliği": 2, "karar yüzeyinin küçüklüğü": 4, "yükseltmenin bölünebilirliği": 1, "çıkışın kademeli olması": 1, "tek sözleşme": 4, }, }; const puan = (adaylar, agirlik) => Object.entries(adaylar).map(([ad, ozellikler]) => [ ad, Object.entries(ozellikler).reduce((t, [olcut, p]) => t + (agirlik[olcut] ?? 0) * p, 0), ]).sort((a, b) => b[1] - a[1]); for (const [proje, agirlik] of Object.entries(PROJELER)) { console.log(`\n=== ${proje} ===`); for (const [baslik, adaylar] of [["güncelleme modeli", GUNCELLEME_MODELI], ["kapsam", KAPSAM]]) { const siralama = puan(adaylar, agirlik); console.log(` ${baslik}:`); for (const [ad, p] of siralama) console.log(` ${ad.padEnd(38)} ${String(p).padStart(4)}`); console.log(` fark (birinci − ikinci): ${siralama[0][1] - siralama[1][1]}`); } } // Duyarlilik: bir olcutun agirligi kac olursa siralamanin basi degisir? console.log("\n=== duyarlılık: güncelleme modeli, iç gözlem panosu ==="); const taban = { ...PROJELER["iç gözlem panosu"] }; const kazanan = (a) => puan(GUNCELLEME_MODELI, a)[0][0]; const tabanKazanan = kazanan(taban); console.log(`taban ağırlıklarla ilk sıra: ${tabanKazanan}`); console.log("ölçüt taban dönüş ağırlığı yeni ilk sıra"); for (const olcut of Object.keys(GUNCELLEME_MODELI["sanal ağaç tutan"])) { let donus = null, yeni = null; for (let w = 0; w <= 20; w++) { const deneme = { ...taban, [olcut]: w }; if (kazanan(deneme) !== tabanKazanan) { donus = w; yeni = kazanan(deneme); break; } } console.log( `${olcut.padEnd(36)} ${String(taban[olcut]).padStart(5)} ` + `${(donus === null ? "dönmüyor" : String(donus)).padStart(15)} ${yeni ?? "-"}` ); }
=== kamuya açık istasyon sayfası ===
güncelleme modeli:
derleme zamanında tepkiselleştiren 26
çalışma zamanında bağımlılık izleyen 25
sanal ağaç tutan 15
fark (birinci − ikinci): 1
kapsam:
dar kapsamlı 16
bütünleşik 9
fark (birinci − ikinci): 7
=== iç gözlem panosu ===
güncelleme modeli:
çalışma zamanında bağımlılık izleyen 39
derleme zamanında tepkiselleştiren 32
sanal ağaç tutan 24
fark (birinci − ikinci): 7
kapsam:
bütünleşik 24
dar kapsamlı 10
fark (birinci − ikinci): 14
=== duyarlılık: güncelleme modeli, iç gözlem panosu ===
taban ağırlıklarla ilk sıra: çalışma zamanında bağımlılık izleyen
ölçüt taban dönüş ağırlığı yeni ilk sıra
ince taneli güncelleme 5 dönmüyor -
çalışma zamanı kodunun azlığı 1 9 derleme zamanında tepkiselleştiren
derleme adımı gerektirmemesi 1 16 sanal ağaç tutan
elle belleme gerektirmemesi 3 dönmüyor -
dinamik yapılara uyum 3 dönmüyor -
güncellemenin bölünebilirliği 2 10 sanal ağaç tutan
İki proje aynı puan tablosundan farklı sıralamalar üretiyor. Ayrım ailelerden değil, ağırlıklardan geliyor: kamuya açık sayfada indirilen kodun azlığı beş kat ağırlıkta, gözlem panosunda ince tanelilik beş kat ağırlıkta.
Kapsam ekseninde sıralama daha keskin ayrılıyor. Kamuya açık sayfada uzun ömür ve kademeli çıkış öne çıktığı için dar kapsam önde; iç panoda karar yüzeyinin küçüklüğü ve tek sözleşme ağır bastığı için bütünleşik profil önde. İki eksen bağımsızdır ve ayrı ayrı kararlaştırılır.
Sıralama Değil, Fark Önemlidir
Birinci projede birinci ile ikinci arasındaki fark 1 puan. Bu, modelin o proje için bir yanıt vermediği anlamına gelir. Puanların girdisi tahminî ağırlıklardır; bir puanlık fark, ağırlıklardaki en küçük değişiklikle kaybolur. Böyle bir sonuçta doğru okuma “birinci kazandı” değil, “bu iki seçenek bu ölçütlerle ayrılmıyor” olmalıdır. Karar, modelin kapsamadığı ölçütlere — adaydan ve ekipten okunanlara — bırakılır.
İkinci projede fark 7 puan ve duyarlılık tablosu bunun ne kadar sağlam olduğunu gösteriyor. En ağır ölçütün ağırlığı yirmiye kadar çıkarıldığında bile ilk sıra değişmiyor; buna karşılık çalışma zamanı kodunun azlığı 1’den 9’a çıkarsa sıralama dönüyor. Bu, kararın hangi varsayıma dayandığını söyler: “indirilen kod miktarı bu proje için ikincil” varsayımı düşerse karar da düşer.
Duyarlılık çözümlemesinin asıl işlevi budur. Bir sayı üretmez; kararın kırılma noktasını yazılı hâle getirir. Kırılma noktası bilindiğinde, proje koşulları değiştiğinde kararın gözden geçirilmesi gerekip gerekmediği tartışmasız olur.
Kararın Geri Alınabilirliği
Seçimin son ölçütü, seçimin yanlış çıkması durumunda ne olacağıdır. Bu da sayılabilir.
// goc.mjs — kararin ne kadarinin geri alinabilir kaldigini olcmek // Baglilik: 0 = catidan bagimsiz, 1 = arayuz uzerinden, 2 = dogrudan bagli. const AYRIM_YAPILMIS = [ { ad: "eşik ve tarih doğrulama kuralları", satir: 180, baglilik: 0 }, { ad: "ölçüm biçimlendirme ve birim çevrimi", satir: 120, baglilik: 0 }, { ad: "seçenek listesi durum makinesi", satir: 260, baglilik: 0 }, { ad: "erişilebilirlik öznitelik türetimi", satir: 90, baglilik: 0 }, { ad: "veri erişim katmanı", satir: 310, baglilik: 1 }, { ad: "sunum bileşenleri (işaretleme)", satir: 940, baglilik: 1 }, { ad: "konteynerler ve kancalar", satir: 380, baglilik: 2 }, { ad: "yönlendirme ve form bağlama", satir: 360, baglilik: 2 }, ]; // Ayni uygulama, ayrimlar yapilmadan: mantik bilesenlerin govdesinde. const AYRIM_YAPILMAMIS = [ { ad: "bileşenler (mantık gövdede)", satir: 2210, baglilik: 2 }, { ad: "veri erişim katmanı", satir: 310, baglilik: 1 }, { ad: "yönlendirme ve form bağlama", satir: 360, baglilik: 2 }, ]; function olc(ad, moduller) { const toplam = moduller.reduce((t, m) => t + m.satir, 0); const grup = (b) => moduller.filter((m) => m.baglilik === b).reduce((t, m) => t + m.satir, 0); const bagimsiz = grup(0), arayuz = grup(1), dogrudan = grup(2); // Gocte yeniden yazilacak: dogrudan bagli olanin tamami, arayuz uzerinden baglinin yarisi. const yenidenYazilacak = dogrudan + Math.round(arayuz / 2); console.log(`\n--- ${ad} ---`); console.log("modül satır bağlılık"); for (const m of moduller) console.log(`${m.ad.padEnd(40)} ${String(m.satir).padStart(6)} ${m.baglilik}`); console.log(`toplam ${toplam} satır | bağımsız ${bagimsiz} (%${((bagimsiz / toplam) * 100).toFixed(1)})` + ` | arayüz üzerinden ${arayuz} | doğrudan bağlı ${dogrudan}`); console.log(`göçte yeniden yazılacak: ${yenidenYazilacak} satır (%${((yenidenYazilacak / toplam) * 100).toFixed(1)})`); return yenidenYazilacak; } const a = olc("ayrımlar yapılmış", AYRIM_YAPILMIS); const b = olc("ayrımlar yapılmamış", AYRIM_YAPILMAMIS); console.log(`\nayrımların göçte kazandırdığı: ${b - a} satır`);
--- ayrımlar yapılmış --- modül satır bağlılık eşik ve tarih doğrulama kuralları 180 0 ölçüm biçimlendirme ve birim çevrimi 120 0 seçenek listesi durum makinesi 260 0 erişilebilirlik öznitelik türetimi 90 0 veri erişim katmanı 310 1 sunum bileşenleri (işaretleme) 940 1 konteynerler ve kancalar 380 2 yönlendirme ve form bağlama 360 2 toplam 2640 satır | bağımsız 650 (%24.6) | arayüz üzerinden 1250 | doğrudan bağlı 740 göçte yeniden yazılacak: 1365 satır (%51.7) --- ayrımlar yapılmamış --- modül satır bağlılık bileşenler (mantık gövdede) 2210 2 veri erişim katmanı 310 1 yönlendirme ve form bağlama 360 2 toplam 2880 satır | bağımsız 0 (%0.0) | arayüz üzerinden 310 | doğrudan bağlı 2570 göçte yeniden yazılacak: 2725 satır (%94.6) ayrımların göçte kazandırdığı: 1360 satır
Aynı uygulama, iki farklı iç düzenle. Ayrımlar yapıldığında kodun dörtte biri çatıdan tümüyle bağımsız; göçte yeniden yazılacak bölüm yarıya iniyor. Ayrımlar yapılmadığında bağımsız kod sıfır ve uygulamanın neredeyse tamamı yeniden yazılıyor.
Bağımsız kalan dört modül tesadüf değil: doğrulama kuralları, biçimlendirme, durum makinesi ve erişilebilirlik öznitelik türetimi. Dördü de önceki konudaki ayrımların ürünü — sunum ile konteynerin ayrılması, davranışın başsız bir çekirdeğe alınması, mantığın kancalara taşınması. Bu ayrımların değeri okunabilirlikle sınırlı değildir; çerçeve kararını geri alınabilir tutan şey de onlardır.
Buradan seçim tartışmasını yumuşatan bir sonuç çıkar. Bağımsız kod oranı yüksek tutulduğunda, çerçeve kararı bir kader değil bir tercihtir. Kararın ağırlığı, kararın geri alınabilirliğiyle ters orantılıdır.
Kararın Yazılı Hâli
Karar çerçevesinin çıktısı bir çerçeve adı değil, bir kayıttır. Kaydın taşıması gereken beş şey vardır.
Bağlam: uygulamanın ne olduğu, beklenen ömrü, ekibin büyüklüğü ve deneyimi. Ölçütler ve ağırlıklar: hangi ölçütün neden ağır bastığı, sayıyla. Değerlendirilen adaylar ve elenme gerekçeleri. Kararın dayandığı varsayımlar ve duyarlılık çözümlemesinden çıkan kırılma noktaları. Gözden geçirme koşulu: hangi olay olursa kararın yeniden ele alınacağı.
Bu kaydın en çok işe yarayan bölümü sonuncusudur. “Şu koşul değişirse yeniden bakılacak” cümlesi, kararı hem savunulabilir hem de değiştirilebilir kılar; kaydı olmayan bir karar zamanla gerekçesini yitirir ve yalnızca alışkanlık olarak sürer.
Özet
- Ölçütler üç kaynaktan gelir: aileden türetilebilenler, adaydan okunanlar ve ekipten okunanlar. Yalnızca birincisi ailenin tanımından çıkar.
- Ağırlıklar açık yazıldığında aynı puan tablosu farklı projelerde farklı sıralama üretir; ayrım ailelerden değil ağırlıklardan gelir.
- Güncelleme modeli ile kapsam iki bağımsız eksendir ve ayrı ayrı kararlaştırılır.
- Sıralamanın kendisi değil, birinci ile ikinci arasındaki fark anlamlıdır; bir puanlık fark “ayrılmıyor” demektir ve duyarlılık çözümlemesi kararın kırılma noktasını yazılı hâle getirir.
- Kararın geri alınabilirliği ölçülebilir; ayrımlar yapıldığında göçte yeniden yazılacak bölüm %94,6’dan %51,7’ye indi.
- Çıktı bir çerçeve adı değil, gözden geçirme koşulunu da içeren yazılı bir karar kaydıdır.
Kurs Kapanışı
Bu kurs, elle DOM yönetiminin ölçek sorunlarıyla başladı ve durumdan görünüme tek yönlü bir akış kurdu. Bileşen, girdi özellikleri, çıktı olayları ve yerel durumdan oluşan üç kanallı bir sözleşme olarak tanımlandı; yaşam döngüsü, yan etkiler, türetilmiş değerler, bağlam ve hata sınırlarıyla tek bir bileşen sonuna kadar götürüldü.
İkinci yarıda bileşenler birleştirildi. Sarmalama ile yuva tabanlı bileşim arasındaki seçim, özellik zinciri ve seçenek patlaması sayılarak gerekçelendirildi. Mantık kancalara ve birleştirilebilir işlevlere taşındı; birlikte çalışan bileşen aileleri kuruldu; veri, davranış ve görünüm üç ayrı katmana ayrıldı. Bileşenin dış yüzeyi — özellik yayılması, varsayılan birleştirmesi ve denetim sahipliği — bir sözleşme olarak tasarlandı.
Son konu, bu bileşenlerin altındaki güncelleme düzeneklerini ele aldı. Aynı iki yüz satırlık ölçüm tablosunda aynı değişiklik, ailelere göre bin altı yüz karşılaştırmadan tek bir yazma işlemine kadar değişen iş miktarları üretti. Dört ailenin özellikleri, bedelleri ve karar yüzeyleri sayılarla ortaya kondu ve bu ölçümler, ürün adı geçmeyen bir karar çerçevesine dönüştürüldü.
Kursun bıraktığı yerde bir eksik var. Buraya kadar her şey tek bir bileşen ağacının içindeydi: durum bir bileşende doğuyor, ağaç boyunca aşağı akıyor ve orada tüketiliyor. Oysa istasyon uygulaması tek bir ekran değil. Ölçüm tablosu bir adreste, arşiv görünümü başka bir adreste; süzgeç tercihi iki ekran arasında korunmalı; ölçüm verisi sunucudan geliyor ve tarayıcıdaki kopyası ne zaman tazeleneceğini bilmiyor. Bunların hiçbiri bileşen bileşimiyle çözülmez; bileşenlerin üstündeki katmana aittir.
Bir sonraki kurs — Uygulama Mimarisi: Yönlendirme, Durum ve Veri — bu katmanı kurar. Adresin bir görünüme nasıl eşlendiğini ve iç içe düzenlerin ortak kabuğu nasıl paylaştığını, yerel durum ile paylaşılan durumun ve sunucu durumunun neden ayrı yönetildiğini, sunucudan gelen verinin önbelleklenmesini ve geçersizleştirilmesini, form durumunun ve doğrulama şemalarının paylaşılmasını, tarayıcıda kimlik doğrulamanın seçeneklerini ve risklerini ele alır. Bu kursta kurulan bileşim ve yüzey tasarımı alışkanlıkları orada da geçerlidir: durumun sahibi, sözleşmenin sınırı ve kararın geri alınabilirliği aynı sorulardır, yalnızca ölçek büyür.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.