Astro ile hızlı web sitesi önceden derlenmiş bir sitedir: sayfanın HTML’i istek gelmeden build sırasında yazılır ve her ziyaretçiye aynı dosya gider. Karar çerçeve adıyla değil yüzey başına verilir; aynı ürünün bir yarısı önceden yazılabilirken öbür yarısı istek anında üretilir. Vipkurum’da hangi kiracının içeriğinin döneceğini isteğin geldiği alan adı belirler; orada önceden yazılabilecek ekran yok.
Sitesini yenilemek isteyen herkese aynı tavsiye gidiyor: şu çerçeveye geç, hızlanırsın. Oysa çerçeve seçimi bu kararın son adımı. İlk adım çok daha dar bir soru: çıktı, soran herkes için aynı mı? Cevap evetse sayfa build sırasında yazılabilir ve ziyaretçi geldiğinde ortada üretilecek bir şey kalmaz. Cevap hayırsa derleyici sayfayı kimin açacağını bilemez, dolayısıyla cevabı istek anında birinin üretmesi gerekir.
Astro’nun hızı nereden geliyor
Astro bir bileşeni build sırasında sunucuda HTML’e derler ve orada bırakır. Çerçeve çalışma zamanı tarayıcıya varsayılan olarak hiç gitmez. Bir bileşenin tarayıcıda da çalışması isteniyorsa bu açık bir istemci yönergesiyle söylenir; tarayıcıda çalışacak bileşenler tek tek işaretlenir. Sonucu şudur: bir sayfanın taşıdığı JavaScript, o sayfadaki bileşen sayısıyla değil işaretlenmiş bileşen sayısıyla orantılıdır. Bu sitedeki sayfaların çoğunda işaretlenmiş tek bir bileşen yok.
İkinci karar çıktı biçiminde veriliyor. Bu sitenin yapılandırması çıktıyı statik olarak sabitler: her sayfa istek gelmeden, build anında diskteki bir HTML dosyasına yazılır. Ziyaretçi geldiğinde çalışan bir sunucu şablonu yoktur. Dosya zaten durur; sunucunun tek işi onu göndermektir. Alternatifi, sayfayı her istekte sunucuda üretmekti; o yol ancak sayfanın isteği tanıması gerekiyorsa bir işe yarar.
Üçüncüsü, çerçevenin nereye gireceğini biz söylüyoruz. Bu sitede Preact tek bir yola daraltılmış durumda: teklif formunun bulunduğu yol. Kod tabanındaki tek istemci yönergesi orada duruyor. Formun dışındaki hiçbir sayfa Preact paketi çekmiyor, çünkü formun dışında adım adım ilerleyen, girdiyi hatırlaması gereken başka bir yüzey yok.
Bu, sitenin JavaScript’siz olduğu anlamına gelmiyor. İlk boyamadan önce çalışıp tema tercihini uygulayan koruma, gezinme çekmecesi, mega menü, bölüm animasyonu ve çerez bandı elle yazılmış, sayfaya gömülü davranış parçaları. Her biri tek iş yapıyor; hiçbiri bir çerçeve çalışma zamanı ya da uygulama iskeleti taşımıyor.
Bu siteyi Astro ile kurduk, müşteri sistemlerini kurmuyoruz
Bu bloğun üzerinde durduğu site Astro, TypeScript ve Preact ile kurulu. Aynı üçlü hiçbir müşteri sistemimizde kullanılmadı; Astro’yu hizmet olarak da satmıyoruz.
Müşteri işlerinin altyapısı tek: Laravel, MySQL ve Redis; arayüzde Inertia ile Tailwind. Masadan çıkan her telefon uygulaması React Native (Expo) ile kuruluyor ve ofis paneliyle aynı Laravel uygulamasına bağlanıyor. Proje başına yeni yığın seçmiyoruz; yıllarca bakılabilecek tek yığın seçiyoruz. Uzman bir çalışma zamanı ancak problem zorladığında devreye giriyor: görüntü işleme için Python ve OpenCV gibi.
Ayrım, iki yüzeyin iki ayrı soruyu cevaplamasından çıkıyor. Vipkurum’da hangi kiracının içeriğinin döneceği isteğin geldiği alan adında belli oluyor; çıktı kiracıya göre değişiyor. AlgoKlima’da kayıt teknisyenin telefonunun yerel kuyruğuna yazılıyor; kaydın ne zaman ve kimden geldiği çalışma zamanında belirleniyor. Build zamanının bu iki soruya verebileceği bir cevap yok. Astro’yu oraya taşımak sorunun yerini değiştirmekten öte bir şey yapmaz.
Bu sitede aynı sorular hiç sorulmuyor. Hizmet sayfası kim açarsa açsın aynı, vaka çalışması aynı, bu yazı aynı. İki dil de adres önekiyle ayrılıyor ve iki dilin sayfaları da aynı biçimde önceden yazılıyor. Çıktı sabit olduğu için sayfa önceden yazılabiliyor. Aynı sitede oturum, sepet ya da kişisel bir kayıt olsaydı bu satırların hiçbiri geçerli olmazdı.
Sayfa kim baktığını bilmek zorunda mı
Önceden derlemenin tek koşulu var: çıktı, soran herkes için aynıdır. Koşul bozulduğu anda build’in elinden bir şey gelmez, çünkü derleyici sayfayı kimin açacağını bilemez. Aşağıdaki üç durum koşulu üç ayrı yerden bozuyor.
Birincisi çok kiracılılık. Vipkurum çatısındaki 7 kurum kendi alan adı ve markasıyla tek çekirdek üstünde çalışıyor; hangi ders programının, öğrenci kaydının ve ödeme satırının döneceğini isteğin kendisi belirliyor. Bir kurumun ekranını önceden yazmak, öbür kurumların kayıtlarını da aynı build’e koymak demek olurdu; kurumların bilgisini ayrı tutan sınır buna izin vermiyor.
İkincisi kaydın ilk nerede yazıldığı. AlgoKlima’nın saha uygulamasında teknisyen kazan dairesinde, kapsama dışında kayıt açıyor. Kayıt önce telefonun yerel kuyruğuna yazılıyor; bağlantı dönünce kuyruk oluşturulma sırasına göre boşalıyor ve sahadan gelen değişiklikle ofisten gelen değişiklik çakışma çözümüyle tek kayıtta birleşiyor. Sıra kuralının kendisi çalışma zamanına ait bir bilgi.
Üçüncüsü talebin tipi. Diotek’te keşif randevusu ile servis çağrısı aynı formdan geçmiyor. Keşif mekânı merkeze alıyor, servis kurulu cihazı; talep tipi akışı en baştan ayırıyor ve hangi akışın açılacağı ziyaretçinin ne istediğine bağlı. Formun kendisi tek bir HTML dosyası olabilir, ama arkasındaki dallanma isteği okumadan seçilemiyor.
Üç işte de çerçeve tartışması hiç açılmadı. Sorulan şey şuydu: istek anındaki cevabı kim üretecek. Bu soruya cevabı olan bir Laravel uygulaması hazırda varken ikinci bir çerçeve eklemek, hız kazandırmadan bakım yükü ekliyor.
Sınır yüzey başına çizilir
Karar tek tek yüzeylerde veriliyor ve iki cevap aynı ürünün içinde yan yana durabiliyor.
Çatalca Merkez Kasap’ta basılı menünün yerini QR ile açılan bir menü sayfası aldı. Sayfa masadaki herkese aynı görünüyor: fiyat listesi ziyaretçiye göre değişmiyor, arkasında sipariş, ödeme ya da stok katmanı yok. Menü bölümlere ayrılmış ve her bölümün kendi adresi var; farklı masa veya vitrin QR’ları aynı sayfanın farklı noktasına iniyor, bölümler arası geçiş yeni bir sayfa isteği açmıyor.
Şu an inşa ettiğimiz QRVizit aynı ürünün içinde iki cevabı birden taşıyor. Basılı QR kodun açtığı tanıtım sayfası, kodu okutan herkese aynı içeriği gösteriyor. Ama o içerik sahibinin panelinden değişiyor ve panel kimin giriş yaptığını bilmek zorunda. Ürünün bir yarısı önceden yazılabiliyor, öbür yarısı yazılamıyor; bu yüzden tek bir üründe iki render kararı yan yana duruyor.
Spektrumun öbür ucunda Vipkurum duruyor: dönen içerik hem isteğin geldiği alan adına hem de giren kişinin rolüne göre belirleniyor. Öğretmen, veli ve yönetici aynı kayda farklı yetkiyle bakıyor. Burada önceden yazılabilecek tek bir ekran bile yok.
| Yüzey | Çıktı kime göre değişir | Render kararı | Kanıt |
|---|---|---|---|
| QR menü sayfası — bölümleri ayrı adreslenen tek sayfa | Kimseye göre değişmez; fiyat listesi masadaki herkese aynı, arkasında sipariş/ödeme/stok katmanı yok | Önceden hazırlanabilir: menü bir kez açılır, bölüm geçişi yeni sayfa isteği açmaz; fiyat değişimi baskı değil sayfa güncellemesi | Çatalca Merkez Kasap |
| QR kartvizit — tanıtım sayfası + sahibinin paneli (şu an inşa ediliyor) | Tanıtım sayfası kodu okutan herkese aynı; panel kimin giriş yaptığını bilmek zorunda | Aynı üründe iki cevap: sayfa istek anında ama Redis önbelleğinden sunuluyor, panel her koşulda istek anında | QRVizit |
| Çok kiracılı kurum paneli — ders programı, öğrenci, ödeme | İsteğin geldiği alan adına ve giren kişinin rolüne göre | Yalnız istek anında: önceden yazmak bütün kiracıların bütün kayıtlarını önceden yazmak olurdu | Vipkurum |
| Tahmin + arşiv + iklim özeti sayfaları | Ziyaretçiye göre değişmez; takvimle değişir | Laravel tarafında üretilir; her tarih–konum kırılımı kendi kalıcı adresinde yayınlanır | Günlük Hava Durumu |
Tablonun okunma biçimi şu: ikinci sütun cevabı verir, üçüncü sütun onun sonucudur. Şirket adı hiçbir satırda karara girmiyor; aynı müşterinin iki yüzeyi iki ayrı satırda durabilir.
İçeriğin değişmesi sayfayı dinamik yapmaz
Sık gelen bir itiraz var: içerik sürekli güncelleniyorsa sayfa statik kalamaz. Kalabilir. Belirleyici soru güncelleme sıklığı değil, çıktının kime göre değiştiği. Günde birkaç kez tazelenen bir sayfa herkese aynı görünüyorsa hâlâ yayındır; ayda bir değişen bir ekran kişiye özelse baştan durumdur.
Günlük Hava Durumu tek sitede üç ayrı değişme hızı taşıyor. 15 günlük tahmin sürekli tazelenip üzerine yazılıyor. Tarihi geçen gün, bir kez yazılan ve bir daha değişmeyen arşiv satırına dönüşüyor. İklim özeti ayrı bir kaynaktan gelmiyor; o arşivden hesaplanıyor ve arşiv büyüdükçe kendini yeniliyor. Üçü de takvimle değişiyor, hiçbiri kim baktığına göre değişmiyor.
Aynı sitede her tarih–konum kırılımı kendi kalıcı adresinde duruyor. Arşiv büyüdükçe site derinleşiyor ama sayfa yapısı yeniden kurgulanmıyor. Adres kalıcılığı, içerik tazeliğinden bağımsız bir karar: bir adres bir kez yayınlandıysa içeriği tazelenebilir, yeri değişemez. Bu ayrımı baştan yapmayan sitelerde arşiv büyüdükçe adresler kayıyor ve her kayma dışarıdan gelen bağlantıyı kırıyor.
Çatalca’da aynı ayrım daha küçük ölçekte görünüyor. Fiyat değiştiğinde sayfa güncelleniyor ve aynı QR kod, yeni baskı gerekmeden güncel menüyü açıyor. İçerik değişmiştir, ama çıktı masadaki herkese hâlâ aynıdır. Basılı menüde değişikliğin bedeli yeni bir baskıydı; burada bedel bir sayfa güncellemesi.
Bu kuralın işlemediği yer de belli. İçerik takvimle değil, ziyaretçinin kendi ürettiği kayıtla değişiyorsa ortada yayın değil durum vardır ve bölümün kuralı geçerliliğini yitirir. Kendi kaydını gören bir ekran, ne kadar seyrek güncellenirse güncellensin önceden yazılamaz.
Koşul bozulunca hız okuma yolundan gelir
Koşul bozulduğunda hızdan vazgeçilmiyor; hız başka bir yerden çıkarılıyor. İstek anında üretilen bir sayfada kazanç, render’ı öne çekmekten değil, tekrarlanan okumayı ucuzlatmaktan geliyor.
Devraldığımız SsangYong kurumsal sitesinde katalog okumaları Redis önbelleğinden karşılanıyor. Aynı sorgu her sayfa açılışında MySQL’e düşmüyor; veritabanı yalnızca veri değiştiğinde devreye giriyor. Sayfa hâlâ istek anında üretiliyor, ama üretimin pahalı kısmı her ziyaretçi için tekrarlanmıyor.
Aynı işte araç görselleri tek bir adlandırma ve klasör düzenine taşındı. Hangi modelin hangi dosyayı kullandığı artık kod okunmadan görülüyor. Dağınık duran görseller sayfa yükünün büyük bölümünü taşıyordu ve bu yük, çerçeveye hiç dokunulmadan hafifletildi.
Mevcut çatının dışına da çıkılmadı. Laravel, Tailwind ve jQuery seti korundu, çalışan bölümlere dokunulmadı; okuma yolu için bir önbellek katmanı devreye girdi, başka bir şey girmedi. Gerekçe şu: bakımı marka tarafı sürdürecekti ve çatıyı değiştiren bir bağımlılık, o haftaki işimizi kolaylaştırırken siteyi sahibinin elinden alırdı. Devralınan bir sistemde belirleyici soru, bizden sonra sistemi kimin sürdüreceğidir.
Aynı kurguyu kendi ürünümüzde de kuruyoruz. QRVizit’te ziyaretçinin gördüğü sayfanın içeriğini Redis’te önbelleğe alıyoruz; aynı kod tekrar tekrar okutulsa da her okutma MySQL’e inmiyor, kayıtlar MySQL’de duruyor. Koşul bozulan bir yüzey, sistem mimarisi çalışmasında masaya ilk koyduğumuz Laravel, MySQL ve Redis yığınına taşınıyor.
Kararı veren dört soru
Kendi yüzeyinizi yerleştirmek için dört soru yeter. Sıra da önemli: birincisi cevaplanmadan diğerleri anlamsız kalıyor.
Birincisi, çıktı kim baktığına göre değişiyor mu. Değişiyorsa yüzey önceden derlenemez ve tartışma burada biter. Vipkurum’da hangi kurumun içeriğinin döneceğini istek belirliyor; hiçbir çerçeve seçimi bu gerçeği değiştirmiyor.
İkincisi, içerik yayın takviminde mi yoksa veri akışında mı değişiyor. Bunlar ayrı sorular. Günlük Hava Durumu’nda tahmin takvimle tazeleniyor; AlgoKlima’da kayıt sahadaki teknisyenin hareketiyle oluşuyor. Birincisi önceden yazılabilir bir yayın, ikincisi baştan durum. Aynı sitede ikisi birden bulunabiliyor ve o zaman karar her ekran için ayrı veriliyor.
Üçüncüsü, bu yüzey kaç yıl yaşayacak. Bir sezon sürecek kampanya sayfasıyla yıllarca ayakta kalacak bir kurumsal vitrin aynı kararı hak etmiyor; ikinci durumda yığını ileride kim devralacaksa onun tanıyacağı bir yapı seçiyoruz.
Dördüncüsü, bakımı kim yaşayacak. Bakım maliyetini yalnız müşteriye anlatmıyoruz: 5 kendi ürünümüz var, 3’ünü şu an inşa ediyoruz ve yayında olanların bakımını kendimiz taşıyoruz. AlgoKlima bunlardan biri; çevrimdışı kuyruk gibi kuruluş kararlarının yıllar içinde ne getirdiğini kendi üzerimizde görüyoruz. Devraldığımız bir sistemdeyse cevabı bizim değil, sahibinin ekibi veriyor.
Dört sorunun cevabı bir arada okunuyor. Birinci soru yüzeyi ikiye ayırıyor; kalan üçü, ayrıldığı tarafta ne kadar dayanacağını söylüyor. Bir yüzey birinci soruda önceden derlenebilir tarafta kalıp üçüncü ve dördüncü soruda zorlanıyorsa render kararı doğrudur; eksik olan, o yüzeyi kimin sürdüreceğine dair plandır.
Astro’nun doğru cevap olduğu yer
Astro bu sitede doğru cevap ve gerekçesi koşulun sağlanması. Sitedeki hiçbir sayfanın çıktısı ziyaretçiye göre değişmiyor. Hizmet sayfaları, vaka çalışmaları ve bu yazı içerik yayınlıyor; hiçbiri durum taşımıyor. Aynı koşulun sağlandığı her yerde önceden derleme kazanıyor: kurumsal vitrin, dokümantasyon, kampanya sayfası, blog.
Koşul bozulduğunda yeni çerçeve aramıyoruz. Kim baktığını bilmesi gereken yüzey, müşteri sistemlerinin zaten üstünde çalıştığı yığına taşınıyor. Vipkurum’da kurumların bilgisini ayıran şey veri modelinin kendisi; o sınırı build zamanına taşımak mümkün olsaydı bile doğru olmazdı.
Bu yazının kendisi de kuralın örneği. Metin build sırasında HTML’e yazıldı; siz açtığınızda sunucuda çalışan bir şablon yoktu ve gördüğünüz dosya, başka herkese giden dosyayla aynı. Aynı kuralı bir kurum panelinde uygulamaya kalksaydık, iş ilk giriş ekranında dururdu.
İki yaklaşım arasında bir sıralama yok; soruyu yüzeyin kendisi soruyor. Tek bir çerçeveyi bütün yüzeylere uygulamak da ayakta duran bir sistemi hız gerekçesiyle yeniden yazmak da, soruyu duymadan verilmiş cevaptır.
Kural tek cümleye sığıyor: çıktı herkes için aynıysa sayfayı önceden yaz, değilse istek anında üret. Web yazılım işlerimizde bu ayrımı her projede baştan kuruyoruz ve ayrım, çerçeve adı geçmeden önce çizilmiş oluyor.