2 puan yazan GN⁺ 2024-04-05 | 1 yorum | WhatsApp'ta paylaş
  • Sequin ekibi, hem React SPA hem de saf Phoenix LiveView kullandıktan sonra, LiveView ile Svelte’i LiveSvelte aracılığıyla birleştirmenin en üretken yaklaşım olduğuna karar verdi
  • LiveView, sunucu durumu ve DOM artımlı güncellemeleri ile SPA olmadan zengin arayüzler oluşturabilir; ancak istemci durumunun gerektiği anlarda JS modülleri, hook’lar ve LiveView durumu birbirine karışır, sınırlar bulanıklaşır
  • Saf LiveView’deki LiveView, LiveComponent, Component yapıları; yaşam döngüsü, props aktarımı ve iletişim biçimleri bakımından farklı olduğundan, yeniden düzenleme ve durumun nereye yerleştirileceği React’e kıyasla daha zahmetlidir
  • LiveSvelte, Elixir’in props’u aşağı göndermesi ve Svelte’in live.pushEvent ile olayları yukarı iletmesi sayesinde net bir çift yönlü sınır sağlar
  • Bu kombinasyonda routing, iş mantığı ve veri hazırlama sunucuda tutulurken; UI durumu, animasyonlar ve koşullu rendering Svelte’e bırakılarak SPA karmaşıklığı azaltılabilir

LiveView’ün sunduğu geliştirme modeli

  • Geleneksel sunucu tarafı rendering uygulamalarında sunucu durum tutmaz ve her istemci isteğinde sayfayı render eder
  • SPA’larda sayfanın oluşturulmasını istemci üstlenir; veriler backend API üzerinden okunup yazılır ve React’in useState benzeri yöntemleriyle istemci durumu yönetilir
  • LiveView, sayfa rendering’ini sunucunun yapmaya devam etmesini sağlarken durumu korur; frontend aksiyonlarını işledikten sonra DOM’u SPA gibi artımlı olarak günceller
  • SPA karmaşıklığı, istemci JS uygulamasının fiilen bir frontend mikroservisi gibi davranmasından büyür
    • Frontend’e özgü gereksinimler yüzünden backend route’ları ve controller’ları artar
    • Tek bir istek onMount, API çağrısı, yanıt ayrıştırma, router, kimlik doğrulama plug’ı, controller, domain fonksiyonu ve yanıt hazırlama katmanlarından geçebilir
  • LiveView’ün avantajı, frontend mikroservisi olmadan da zengin bir istemci deneyimi oluşturabilmesidir
    • Tablo rendering fonksiyonunun yakınında veritabanı sorgulanabilir
    • Yeni bir satır geldiğinde tabloya push edilir ve LiveView istemciyi günceller
    • Her istekte tüm durumu yeniden kuran geleneksel sunucu rendering yaklaşımına kıyasla, stateful frontend framework’lerine daha yakın etkileşimler oluşturulabilir

Saf LiveView’de karşılaşılan sürtünmeler

  • İstemci tarafı durumundan kaçınılamaz

    • LiveView, sunucu ile kullanıcı arasındaki gidiş-dönüş gecikmesini önleyemez
    • Animasyon, tooltip, DOM öğelerini gösterme/gizleme, form alanını devre dışı bırakma gibi işler bazen istemcide ele alınmalıdır
    • Birbirine bağımlı iki dropdown bulunan bir formda, iyi bir UX için ilk dropdown seçilir seçilmez ikinci dropdown hemen devre dışı bırakılmalı; sunucu yeni listeyi doldurduktan sonra yeniden etkinleştirilmelidir
    • Bu davranışı yalnızca LiveView ile uygulamak için birden çok kavram birlikte gerekir
      • İlk dropdown değiştiğinde ikinci dropdown’ı devre dışı bırakmak için LiveView’ün JS module yapısı kullanılır
      • İkinci dropdown’a event listener kaydetmek ve backend’den yeniden etkinleştirme aksiyonu göndermek için hook kullanılır
      • Koşullu olarak yeniden etkinleştirmek gerekiyorsa LiveView durumu da devreye girebilir
    • JS, hook ve LiveView durumu birlikte kullanıldığında DOM durumunun bir kısmı LiveView dışında bulunur ve tutarlı bir pattern oluşturmak zorlaşır
  • React’ten farklı durum sınırları

    • React, çoğu geçişi durum ve aksiyon gibi temel kavramlarla ele alır; DOM durumu ile bileşen durumu arasındaki sınır nispeten nettir
    • İstemci aksiyonu ile istemci durumu arasında gecikme olmadığı için React, aksiyonları ve geçişleri durum paradigmasıyla ele alabilir
    • LiveView’ün durumu sunucu tarafında olduğundan, istemci aksiyonu ile sunucu durumu arasındaki gecikme hesaba katılmalıdır
    • Girdi alanı örneğinde React, karakter girilmeden önce durum yolundan geçer ve bileşen her tuş girişinde yeniden render edilir
    • LiveView ise kullanıcının önce girdi alanını değiştirdiği, kısa bir süre sonra sunucu durumunun bundan haberdar olup tepki verdiği modele daha yakındır
    • Gecikme neredeyse yoksa React gibi görünür; ancak gecikme arttıkça iki model arasındaki fark belirginleşir

Üç bileşen türünün yarattığı karmaşıklık

  • LiveView’de LiveViews, LiveComponents, Components adlı üç bileşen türü vardır
  • LiveViews ve LiveComponents, React’in stateful bileşenlerine; Components ise fonksiyonel bileşenlere daha yakındır
  • LiveView her zaman en üst seviye ebeveyn bileşendir; altında LiveComponents ve Components render edilir
  • React’te useState hook’unu ekleyip kaldırarak stateful bileşen ile fonksiyonel bileşen arasında kolayca gidip gelinebilir
    • İkisi de props’u aynı şekilde alır
    • Durum hariç özellik setleri aynıdır
    • DOM olaylarını kaydetme ve yanıtlama biçimleri de aynıdır
  • LiveView’de üç bileşen türü arasındaki farklar büyük olduğundan, LiveView’ü LiveComponent’e refactor etmek zahmetlidir
    • LiveViews ile LiveComponents’ın rendering ve props aktarım söz dizimi farklıdır
    • Yaşam döngüleri farklıdır
    • İletişim seçenekleri farklıdır; LiveViews için send, LiveComponents için send_update kullanılır
    • LiveComponents süreç olmadığı için LiveViews gibi sistemin diğer bölümleriyle etkileşime giremez

LiveComponent’in kısıtları

  • LiveView bir Elixir süreci olduğundan pid, durum ve inbox’a sahiptir; Elixir/OTP sistemindeki diğer süreçler gibi davranabilir
  • LiveView’de pub/sub kullanarak sistem genelindeki değişikliklere abone olunabilir
  • LiveComponent kendi başına bir süreç değil, LiveView’ün çağırdığı bir modüldür
  • Ebeveyn LiveView süreci alt bileşenlerin durumunu tuttuğundan, LiveView alt LiveComponents’a mesaj yönlendirmeyi de ele almak zorundadır
  • LiveComponents’ın bağımsız durum yönetimi ve aksiyon işleme yeteneğine sahip olması için her birinin süreç olması gerekir; ancak mevcut model böyle değildir
  • Gerçek geliştirmede LiveComponent’e event veya aksiyon göndermek istendiğinde iyi bir yöntem yoktur; send_update’in aksiyon iletimi için mi yoksa durum patch’i için mi kullanılacağı belirsizleşir
    • Durum patch’i için kullanılırsa update clause’unda mount ile update’i nasıl ayırmak gerektiği de düşünülmelidir

LiveSvelte’in oluşturduğu sınır

  • LiveSvelte, LiveView içinde Svelte bileşenleri render etmeyi sağlar
  • LiveView’ün render içinde Elixir veri yapılarını frontend’e yönelik plain map olarak encode edip Svelte bileşeninin props’u olarak aktarmak mümkündür
  • Svelte bileşeni props’u export let ile alır ve LiveSvelte’in sağladığı live prop’u üzerinden LiveView ile iletişim kurar
  • Svelte tarafında live.pushEvent ile sunucuya event gönderilebilir
    • Örnekte Svelte’in reactive block’u, form değiştiğinde sunucuya "form_updated" event’ini gönderir
    • LiveView, handle_event("form_updated", ...) içinde frontend parametrelerini decode eder ve changeset’i günceller
    • Changeset doğrulama hataları yeniden errors prop’u üzerinden frontend’e iletilir
  • Veri Elixir’den props olarak Svelte’e iner; Svelte’ten ise websocket event’i olarak LiveView’e çıkar
  • LiveView süreci, props’u istediği an güncelleyerek Svelte bileşeninin yeniden render edilmesini sağlayabilir

LiveView ve Svelte kombinasyonunun temel özellikleri

  • Bu kombinasyonun özü, stateful backend süreci ile stateful frontend bileşeninin birlikte çalışmasıdır
  • Kombinasyonu üç özellik destekler
    • Backend, frontend bileşeninin props’unu kontrol eder
    • Hem frontend hem backend durum tutar
    • İki tarafın da birbirine mesaj başlatabildiği özel bir çift yönlü iletişim kanalı vardır
  • İlk özellik LiveView’ün rendering biçimi sayesinde mümkündür
    • Sunucu yeniden rendering sonucu otomatik olarak istemciye push edilir ve uygulanır
    • Sunucu, bir JS ebeveyn bileşeni gibi bileşen props’unu güncelleyebilir
  • İkinci özellik LiveView’ün bir Elixir süreci olmasından gelir
    • Elixir süreçleri, durumu kapsüllemenin bir yoludur
  • Üçüncü özellik LiveView’ün sunduğu sürekli websocket bağlantısı ile mümkündür

SPA’dan farkları

  • Tarayıcı routing’inin tamamı backend’de gerçekleştiği için yapı basitleşir
    • Tipik SPA’larda tarayıcı route’ları ve API route’ları olmak üzere iki tür route tutulmalıdır
  • Backend durum sahibidir; mevcut route’u ve üzerinde çalışılan kaynağı bilir
    • Her aksiyon, durumu baştan yeniden oluşturmak yerine backend’in kendi durum değişikliği olarak işlenebilir
  • Frontend ile backend arasındaki iletişim özel ve bağlıdır
    • Tek bir bileşeni desteklemek için RPC çağrılarıyla sunucunun public route’ları artırılmaz
    • İstemcide pushEvent görüldüğünde ilgili handler’ın birlikte çalışan Elixir modülünün içinde olduğu anlaşılır
  • Özellikler ağırlıklı olarak iki dosyaya ayrılır
    • Backend modülü, veritabanı sorgulama gibi backend fonksiyonlarını çağırır
    • Frontend, bileşen ve stilleri getirir
    • Frontend-backend gidiş dönüşü API modülü, router ve controller stack’inden geçmez
  • İletişim adımları da azalır
    • Backend, yalnızca props güncellemesiyle frontend değişikliğini bildirebilir
    • Frontend; süresi dolmuş token, timeout veya hata işleme handler’ları olmadan pushEvent gönderebilir
    • Websocket açıksa sunucu çalışıyor demektir; kapalıysa LiveView genel bir “disconnected” banner’ı gösterir

Sorumluluk ayrımı ve kod yapısı

  • Bu yapıda frontend mikroservisi ortadan kaldırılmış gibi çalışılır
  • İş mantığı backend’de tutulur
    • Verinin nasıl yükleneceği
    • Hangi verinin getirileceği
    • Sıralama ve filtreleme biçimi
    • Doğrulayıcılar
  • Svelte frontend kodu sadeleşir
    • Koşullu rendering için if/end blokları
    • Animasyonlar
    • Sunucuya gönderilen basit pushEvent fonksiyonu
  • Tipik bir SPA frontend’inde sunucu verisi işleme, gösterim için veri hazırlama ve sunucuya gönderilecek veri hazırlama amacıyla çok sayıda map, reduce, filter mantığı oluşabilir
  • LiveSvelte uygulamasında bu işlemler sunucu tarafında yapılabilir
    • LiveView, veriyi Svelte bileşeninin ihtiyaç duyduğu biçimde hazırlar
    • Karmaşıklık sunucu dili, sunucu veri yapıları ve sunucu test suite’i içinde kalır
  • LiveView ve Svelte bileşeni, gevşek bağlı iki unsurdan ziyade tek bir özelliğin iki yarısı gibidir
    • LiveView yalnızca ilgili Svelte bileşenini render eder
    • O Svelte bileşeni yalnızca ilgili LiveView tarafından render edilir

Saf LiveView’e göre değişenler

  • LiveSvelte yaklaşımı frontend’in durumunu ve durum geçişlerini kabul eder
  • Frontend ile backend arasındaki sınır katmanı netleşir
  • Svelte’in olgun bileşen paradigmasından yararlanılabilir
  • Yalnızca saf LiveView ile erişmesi zor olan JavaScript framework ekosistemi de kullanılabilir
    • Svelte animasyon primitives sağlar
  • Daha fazla sorumluluğu frontend’e taşıyarak garip bir ara bölgede kalma hissi azalır

Svelte’in seçilme nedeni ve LiveView’ün konumu

  • LiveSvelte’in seçilme nedeni, React tarafında benzer olgunlukta bir LiveView kütüphanesinin olmamasıydı
  • Svelte, temel durum ve reaktivite konusunda hafif ve hızlı bir frontend framework’ü olarak görülür
  • LiveView durum yönetiminin büyük kısmını üstlendiği için Svelte tarafındaki durum yönetimi basit kalır
  • Svelte’in template özellikleri de React’e tercih edilir
    • Ternary operator yerine if/else kullanılabilir
    • Koşullu attribute ayarı kullanılabilir
  • Svelte 5’in runes, Svelte’i öğrenmesi ve akıl yürütmesi daha kolay hale getirmesi bekleniyor
  • LiveView; frontend bileşenlerini render eden, artımlı güncellemeler yapan, stateful backend sürecini koruyan ve websocket API sağlayan bir backend-for-frontend olarak en iyi halini gösterir

1 yorum

 
GN⁺ 2024-04-05
Hacker News görüşleri
  • Çok oyunculu oyunlarda sık kullanılan kalıp, temelde aynı kodu hem istemci hem de sunucu tarafında çalıştırmaktır.
    İstemci kodu, sunucu durumunu tahmin edip önce çalışır; sunucu durumu geldiğinde de istemci durumunun üzerine yazılır.
    Oyunlarda istemci kendi girdisinin sonucunu oldukça iyi tahmin edebilir ama diğer oyuncuların girdilerini bilemez; bu yüzden “tahmin” sözcüğü yerli yerine oturur.
    Ancak bu yöntem, bir dropdown'ı etkinleştirme/devre dışı bırakma ya da loading spinner gösterme gibi, resmi sunucu durumunu beklerken anında tepki vermek için de kullanılabilir.
    Parçacık sistemleri veya ragdoll gibi sunucuda hiç çalıştırılması gerekmeyen pek çok istemci durumu da var; sürekli bir sunucu bağlantısı varsa reaktif paradigma içinde bunun olmaması için bir neden görünmüyor.

    • https://territoriez.io/ üzerinde tam olarak bu yöntemi kullandım.
      https://generals.io/ klonu ve LiveSvelte ile yapıldı.
      Aslında bir masa oyunu sayılır ve saniyede 2 tick olduğu için tahmin özelliğine gerek yok; ama sunucu güncellemesinden önce oyun durumunu göstermeye yarayan iyimser güncellemeler kullanılıyor.
      Sunucuyla senkron dışına çıkarsa sunucu oyun durumunun üzerine yazar.
      Oyun mantığının tamamı Elixir içinde; tahmini doğru yapmak için sunucu ile istemcinin mantığı paylaşması gerekir.
      Yoksa mantığı iki kez yazarsınız ki bu felakete giden yoldur.
      Araştırmadım ama olası bir çözüm, tüm oyun mantığını gleam(https://gleam.run/) ile yazmak.
      Gleam, Elixir ile uyumlu ve JavaScript'e de derlenebiliyor; teoride aynı kodu sunucu ve istemcide çalıştırabilirsiniz.
      Gerçi “o zaman hepsini js ile yazsanıza” demek de oldukça haklı bir söz olur; ben de muhtemelen katılırım.
      Yine de elde edilen avantaj BEAM ve gerçek zamanlı dağıtık sistemler için iyi özellikleri kullanabilmek; frontend hariç tutulursa bu, çok oyunculu oyunlara cuk oturuyor.
    • Overwatch gibi ragdoll fiziğini yerelde deterministik olmayan biçimde simüle eden oyunları oynarken bunun düzgün yapılmış olmasını istiyorum.
      Biri ölüp cesedi havaya uçtuğunda ya da komik bir pozda sıkıştığında başka hiç kimse bunu görmüyor; replay'de de her istemci farklı render ettiği için tekrar izlenemiyor.
      Gerçek zamanlı kayıtla yakalamazsanız sonsuza dek kayboluyor.
      Overwatch gibi ara sıra gülünçleşen oyunlarda bunu kimsenin birlikte görememesi üzücü.
    • Dövüş oyunları bu tür düşük gecikmeli çakışma çözümü problemini uç noktaya kadar zorluyor ve gerçek zamanlı olay akışlarını ayarlamaya yönelik “netcode” tekniklerinin kendi alt alanı var.
      https://arstechnica.com/gaming/2019/10/explaining-how-fighti... harika bir açıklama; ilgili tartışmalar https://news.ycombinator.com/item?id=34399790 ve https://news.ycombinator.com/item?id=26289933 adreslerinde.
      MMO'larda olduğu gibi sunucu kalıcılığı devreye girince, giriş/çıkış darboğazlarını da birlikte düşünmek gerekiyor.
      https://prdeving.wordpress.com/2023/09/29/mmo-architecture-s... bu açıdan ilginç bir yazı; tartışması da https://news.ycombinator.com/item?id=37702632 adresinde.
    • Bu sadece iyimser güncelleme değil mi? İstemci tarafı mantığında çok uzun zamandır yaygın bir yöntem değil mi?
    • Bu dikkatli kullanılmalı.
      Örneğin canlı/interaktif bir form, sayfadaki türetilmiş verileri güncelleyip her şey iyi çalışmış gibi görünebilir; ama daha sonra bir sunucu hatası veya ağ sorunu yüzünden hepsi geri alınırsa sıkıntı olur.
      Daha da kötüsü, kullanıcı bunu bilmeden sayfayı kapatabilir ya da başka yere gidebilir.
  • LiveView + Svelte kombinasyonunu seviyorum.
    ElixirConf 2022'de ikisini birleştirmenin yolunu sunmuştum, ama live_svelte katkıcıları bunu gerçekten kullanılabilir hale getirdi.
    Zengin kullanıcı deneyimine sahip uygulamaların her zaman istemci tarafı duruma ihtiyaç duyduğunu düşünüyorum.
    Özellikle New York'ta yaşıyorsanız, hareket halindeyken ağ bağlantısı garanti değil.
    Yazıda ele alınmayan güçlü bir özellik de Phoenix'in pubsub'ını kullanarak başka sunucularda gerçekleşen sunucu tarafı durum değişikliklerini tüm istemcilere reaktif biçimde push edebilmek.
    Orta ve üzeri trafiği karşılamak için birden fazla web sunucusu çalıştırmak oldukça yaygın.

    • Mobil ağlar da genel olarak yüksek gecikmeli ve istemcide çoğu zaman local-first önbellekleme sistemi gerekiyor.
      LiveView benzeri bir kullanıcı deneyimi isterken kararsız ağlara da dayanmak istiyorsanız, Triplit[1]'e Svelte 5 binding'leri ekledim.
      İstemci tarafında sorgular yazıp websocket üzerinden sunucuyla senkronize edebilirsiniz.
      Elixir geliştiricileri için pek cazip olmayabilir; ama merkezde Svelte varsa Triplit iyi bir seçenek.
      [1] https://www.triplit.dev/docs/frameworks/svelte
    • Ağın ara ara koptuğu durumlarda LiveView sayfası çevrimdışıyken ne kadar kullanışlı?
  • Yeni satırlar geldiğinde onları doğrudan tabloya itip LiveView’ın istemciyi güncellemesine bırakmak, bu satırların etkileşimli olduğu iş uygulamalarında kaçınılması gereken bir yöntemdir
    Algısal gecikme yüzünden kullanıcının yanlış öğeye tıklaması, yanlış müşteriye e-posta göndermesi veya yanlış işlemi iade etmesi kolaylaşır
    Tercih edilen kullanıcı deneyimi, “Veri değişti. Yenilemek için buraya tıklayın” gibi sabit bir bannerdır
    Acele gerekiyorsa yeni satırları yalnızca ekleme şeklinde render etmeli ve kaydırma konumunun değişmemesini sağlamalısınız

    • Yeni satırları yavaşça animasyonla ekleyip, yeni veri gelirken tıklamayı devre dışı bırakırsanız bu yaklaşım da mümkün olur
  • BeaconCMS’de Svelte ve LiveView birlikte kullanılıyor
    İstemcide UI üzerinde daha ayrıntılı kontrol gerektiren iyi kullanım alanları kesinlikle var, ancak ekibin her şeyde Svelte + LiveView’ı baştan sona benimsemesi konusunda dikkatli olmak gerekir
    Phoenix’te de LiveView her zaman yanıt değildir; bazen normal render edilen sayfalar yeterlidir
    Her şeyi ya hep ya hiç şeklinde seçmemek gerekir
    Yazıda söylendiği gibi “LiveView tarzı”nın dışına çıkmayı haklı çıkaran iyi kullanım alanları var
    Gidiş-dönüş süresi 1.000 ms ise başka seçenekleri de düşünmek gerekir; ancak maliyet gibi nedenlerle coğrafi olarak yakın sunucu bulunduramayan ekipler de olduğundan, istemci tarafı durum yönetimi çözüm olabilir

  • İstemci durumunu yönetmek yerine hem istemci hem de sunucu tarafı durumu mu yönetilecek?
    Başka bir API oluşturmak zorunda kalmamak avantaj olsa da, bu bir iyileştirme gibi görünmüyor

    • Web uygulamalarının durumu o kadar basit değildir
      Her zaman istemcinin izlemesi gereken durum ile sunucunun izlemesi gereken durum vardır; bunun üzerine yalnızca bellekte bulunması yeterli olan geçici durum ile oturumlar arasında korunması gereken durum da biner
      Bunu yönetmenin yolları neredeyse sonsuzdur ve JavaScript’te “ne yaparsan yap doğru cevap yok” gibi bir durum olduğundan ya framework’ün belirlediği yolu kullanırsınız ya da geçici çözümlerle, yani kaosla ilerlersiniz
      En son yazdığım karmaşık tek sayfa uygulamada, istemcinin sayfayı her yüklediğinde senkronizasyon yapmasını sağladım
      Tüm yerel durumlara veya varlıklara tarih tabanlı bir hash eklenmişti; sunucudaki değerle farklıysa sunucu güncellenmiş sürümü gönderiyordu
      Basit bir değişken de olsa, devasa bir JSON nesnesi de olsa, tüm bir görüntü/ses blob’u da olsa aynıydı
      İstemci sunucu durumu değişikliği gerektiren bir şey yaptığında, bu durum güncellemesini WebSocket üzerinden gönderiyordu ve uygulamanın %99’u WebSocket tabanlıydı
      Özel bir framework veya pattern kullanmadım; kod yazarken “bunu sunucu izlemeli” diye düşünürsem yeni durumu sunucuya mesaj olarak gönderiyor, sayfa yüklenirken senkronize edilip edilmeyeceğine sunucunun karar vermesini sağlıyordum
      Bu tür durum yönetiminde bunun neredeyse en basit mekanizma olduğunu düşünüyorum
      WebSocket, durum yönetiminde gerçekten çok yardımcı oluyor
    • Sonunda bu paradigmanın bir biçiminin kazanacağını düşünüyorum
      Gerçek uygulamalar hem istemci hem de sunucu tarafında duruma ihtiyaç duyar
      Sunucu istemciye güvenemeyeceği için yetkili duruma sahip olmalıdır; ancak istemci de gidiş-dönüş olmadan kullanıcı etkileşimlerine yanıt verip yeniden render edebilmelidir
    • Bazı şeyleri tamamen istemci tarafında ele almak daha iyi bir deneyim sağlar
      Her şeyi böyle yapmayın; yalnızca anlamlı olduğunda kullanın
      Ayrıca hoşuma giden bir diğer nokta, Heex yerine Svelte’i şablon dili gibi kullanabilmek
    • Bu, yeni bir neslin ColdFusion, Web Forms, JSF, PHP, Spring ve Rails’i yeniden keşfetmesine yakın bir şey
    • Bu, diğer yazılım ekosistemlerinde yapılan optimizasyonlardan farklı değil
      Gerekmiyorsa yapmanın bir nedeni yoktur; gerekli hale gelmesinin nedeni de performans ve kullanıcı deneyimidir
      Web uygulamasında kullanıcı etkileşimi çoksa istemci JavaScript’i gerekir ve çok sayıda deney nedeniyle her istekte bundle değişiyorsa, istemciye gönderilen JavaScript miktarını azaltmak için mantığı sunucu ile istemci arasında bölmek istersiniz
      Aksi halde uygulamanın karşılaşabileceği tüm olasılıkları içeren MB’larca JavaScript bundle’ınız olur
      Photoshop’un web sürümü gibi kullanıcının ilk yükleme süresini anlayışla karşıladığı uygulamalarda bu kabul edilebilir; ancak Stripe veya Gmail gibi anında yüklenmesi beklenen uygulamalarda sayfanın ilk gecikmesini azaltmak istersiniz
      Her şeyi sunucuya da taşıyabilirsiniz; ancak GitHub’ın yaşadığı gibi, anında tepki vermesi gereken kullanıcı eylemleri sunucu gidiş-dönüşü gerektirdiğinde sayfa etkileşimi kötüleşir
      O zaman ışık hızı ve sunucu dağıtımı sorun haline gelir
      async import gibi yöntemlerle bundle’ı geç yükleyebilirsiniz; ancak geç yüklenen JavaScript kendi verisini almak için tekrar istek gönderdiğinde şelale sorunu ortaya çıkar
      Bu sorunların hepsiyle karşılaşınca, sonunda istemci ile sunucu arasında mantık/durum paylaşımı gibi karmaşık bir problemi kolayca ele alan bir çözüm aramaya başlarsınız
  • Bu yaklaşımda “sunucunun kullanıcıya ne kadar yakın olabileceğinin bir sınırı var” ifadesinin tam anlamıyla ışık hızı sınırı bulunur
    Sonraki adım, sunucuyu WebAssembly’ye derleyip istemciye göndermektir
    Böylece gerçek sunucu yanıtını beklerken iyimser biçimde yanıtı render edebilirsiniz
    Kulağa biraz çılgınca geliyor, ama gerçek bir projede bunu başardık ve sihir gibiydi

    • Kalıcılık nasıl sağlanıyor? Bana göre backend’in temel amacı bu
      Sunucuyu istemcide çalıştırmak bunu çözmez; sonunda kalıcılığın ağ gecikmesi aynen kalır
      Nihayetinde kazanması gereken sunucu durumu da bu kalıcılıktır
    • Aşırı mühendislik gibi geliyor
      Pek çok aşırı mühendislik zaten pek neden olmadan da gerçekten uygulanıyor
    • Neden sadece Service Worker kullanılmasın?
    • Daha fazla ayrıntı paylaşabilir misiniz?
    • Modern çok oyunculu oyunların yaptığı istemci tarafı tahmine çok benziyor
  • LiveSvelte’i ben yaptım; merak ettiğiniz bir şey olursa söyleyin

    • LiveSvelte kullanıyorsanız yine de JS Hooks kullanmak için bir neden olur mu?
  • Genel olarak, uygulamaları hep böyle bir modelle geliştirmek istemiştim.
    Olay odaklı, sunucuyla çift yönlü gerçek zamanlı güncellemeler, sıralı olaylar, yerel/uzak durum gibi bir yaklaşım.
    LiveView’u bilmiyordum ve Erlang ailesinden bir dil de hiç kullanmadım ama kesinlikle bir şeyleri doğru yakalıyor gibi görünüyor.
    Geleneksel istek-yanıt modeli, tutarlılık ve bayat veri sorunlarını sık sık ince biçimlerde ortaya çıkarıyor.
    Geçtiğimiz 10 yıl fonksiyonel programlama kavramlarını ana akım dillere entegre etme dönemiyse, önümüzdeki 10 yılın durumlu, mesaj odaklı programlamayı ana akım full-stack’e entegre etme yönünde olmasını isterim.

    • JavaScript(http://liveviewjs.com), Go(https://github.com/canopyclimate/golive), Java(https://github.com/floodfx/undead), Python(https://github.com/ogrodnek/pyview) ile yazılmış LiveView backend’leri var.
      Bu arada ilk üçünü ben yaptım ya da yapılmasına yardımcı oldum.
    • asdf ile erlang/BEAM/OTP ve elixir kurulabiliyor; araç kullanma konusunda biraz deneyiminiz varsa birkaç dakika sürüyor.
      Kılavuzu takip edip biraz kurcalarsanız, yaklaşık iki saat içinde tarayıcıda çalışan temel bir Phoenix sohbet uygulamasını ayağa kaldırabilirsiniz.
    • “Durumlu mesaj odaklı ya da reaktif programlamayı ana akım full-stack’e entegre etmek”, Rails terimi yeniden tanımlamadan önce MVC olarak da adlandırılıyordu.
  • İyi bir çözüm.
    Kendi uygulamamda LiveView ile birlikte yeniden kullanılabilir Stimulus controller’ları kullanıyorum ve bu da sorunsuz çalışıyor.
    Genel olarak LiveView ile geliştirme yapmak keyifli ama gerçek senaryolarda daha fazla kullandıkça Hotwire gibi durumsuz HTTP framework’lerinin avantajlarını da daha çok hissediyorum.
    Daha performanslı ve yeniden bağlanmaya daha dayanıklı hissettiriyor; ayrıca kararlılık için kullanıcıya yakın daha fazla sunucu yerleştirme ihtiyacı da azalıyor.

    • Stimulus/Turbo ilk duyurulduğunda, yazarın açıkladığı sorunları çözmeye yardımcı olmasını epey ummuştum.
      Ama Stimulus, istemcide durumu tutmak için zarif bir yol sunmuyor.
      “Stimulus uygulamasının durumu DOM’un nitelikleri olarak bulunur” gibi bir yaklaşımı var; bu da vanilla JS ya da jQuery’den daha iyi değil.
      Gerçek bir projede Stimulus kullanmış değilim, dolayısıyla değerler ve değişiklik callback’leri ilk düşündüğümden daha iyi bir deneyim sunuyor olabilir.
    • Ben de Stimulus ve LiveView’u birlikte kullanıyorum.
      Bu kombinasyonun karmaşıklık seviyesi tam yerinde; Svelte ise LiveView ile birlikte kullanıldığında, en başta sorun olmayan pek çok şeyi de ele alıyormuş gibi hissettiriyor.
      Gerekli olan şey vanilla JS ya da onun üzerinde ince bir katman; tam teşekküllü bir framework değil.
      Zaten çok fazla JavaScript kullanmaya gerek kalmıyor.
      Prodüksiyondaki uygulamanın JS’i 200 satırı geçmiyor ve birkaç Stimulus controller’ını da kaldırabilirim gibi görünüyor.
      LiveView o kadar iyi.
      Stimulus-LiveView hook adaptörünü de oldukça hacky bir şekilde yaptım; böylece Stimulus controller’ı LiveView sürecine doğrudan olay gönderebiliyor.
      Ayrıca LiveView, fly.io tarzı Kool-Aid’i fazla içmediyseniz, coğrafi olarak dağıtılmış sunucuları mutlaka gerektirmez.
      Bağlantı kopmalarını da harika yönetiyor.
      Kesintisiz güncellemeleri desteklemek için ayrıca hiçbir şey yapmadım.
      İstemcinin WebSocket bağlantısını kaybedip yeni sürüme yeniden bağlanması ve durumu geri yüklemesi tamamen varsayılan olarak otomatik işleniyor.
      Daha ne istenir?
  • Şirketimiz LiveView ile Alpine’ı birlikte kullanarak büyük fayda gördü; özellikle istemcide eval’e izin veremediğimiz için CSP modu kullanıyoruz.
    LiveSvelte’i ilk gördüğümde çok yeni ve yeterince doğrulanmamış görünüyordu; ayrıca sıkı CSP ortamlarında çözülmemiş etkileri de vardı.
    Şimdi oldukça kullanışlı hale gelmiş gibi görünmesine sevindim.
    Bizim kalıbımız kabaca LiveAlpine olarak adlandırılabilir.
    Bileşenin HTML’e ihtiyacı varsa HTML Component kullanıyoruz; sunucu tarafı durumu varsa Live Component kullanıyoruz.
    İstemci tarafı davranış ya da durum gerekiyorsa Alpine component’i de tanımlıyoruz.
    Sunucuda istemci event’i almak ya da HTTP isteği yapmak gerekiyorsa Phoenix Hook da tanımlıyoruz.