İçeriğe geç
academia.sh

Ders 10 / 22

İyimser Güncelleme

Değişikliğin yanıt beklenmeden ekrana yansıtılması; anlık görüntüyle geri almanın eşzamanlı değişikliklerde bozulması, bekleyen değişiklik katmanı, sunucu yanıtıyla uzlaşma ve iyimserliğin uygulanmayacağı durumlar.

İçindekiler

Sunucu durumu katmanı okumayı çözdü: kopya anahtarla anılıyor, tazelik penceresiyle kullanılıyor, geçersizleştirmeyle yenileniyor. Yazma tarafında ise ekranda görünen şey hâlâ ağın hızına bağlı. Kullanıcı Kuzey Yamaç Ölçüm İstasyonu uygulamasında bir ölçümü siliyor; düğme beklemeye geçiyor, satır ancak sunucu yanıt verince kayboluyor.

Oysa isteğin sonucu çoğu durumda önceden bellidir. Silme işlemi başarılı olacaksa satırın kaybolacağı biliniyor. İyimser güncelleme, beklenen sonucu yanıttan önce ekrana yansıtmak ve yanıt geldiğinde uzlaşmaktır.

Neyi Kazandırır

Kazanç ağ süresinin kısalması değildir; istek yine aynı sürede tamamlanır. Kazanç kullanıcının bekleme algısındadır. Yüz milisaniyelik bir gecikme bile art arda yapılan işlemlerde birikir: on ölçümü tek tek silen bir kullanıcı, her silmede ekranın donmasını bekler.

İyimserlik ayrıca arayüzü basitleştirir. Her düğmenin bir bekleme durumu, her satırın bir “siliniyor” görünümü olmak zorunda kalmaz; ekran doğrudan sonucu gösterir.

Karşılığında bir söz verilmiş olur: ekranda görünen şey henüz doğrulanmamıştır. Söz tutulmadığında — istek başarısız olduğunda — ekran geri alınmalıdır. Bu dersin asıl konusu o geri almadır, çünkü ilk akla gelen yöntem belirli bir durumda sessizce yanlış çalışır.

Geri Almanın İki Yöntemi

İlk yöntem doğrudandır: değişiklik başlarken ekranın anlık görüntüsü alınır, istek başarısız olursa o görüntü geri yüklenir.

İkinci yöntem araya bir katman koyar. Sunucudan gelen veri taban olarak ayrı tutulur; tamamlanmamış değişiklikler bir bekleyen değişiklik listesinde durur; ekranda görünen şey, tabanın üzerine bekleyenlerin uygulanmasıyla her seferinde yeniden hesaplanır. Başarısızlık, o değişikliği listeden çıkarmaktır.

İkisi tek bir değişiklik varken aynı sonucu verir. Fark, iki değişiklik üst üste bindiğinde ortaya çıkar.

// iyimser-guncelleme.mjs — anlik goruntuyle geri alma ile bekleyen katman yonteminin karsilastirmasi
const TABAN = ["T-01", "T-02", "T-03"];

const DEGISIKLIK = {
  A: { etiket: "sil T-02", uygula: (l) => l.filter((x) => x !== "T-02") },
  B: { etiket: "ekle T-04", uygula: (l) => [...l, "T-04"] },
};

// 1. Yontem: degisiklik baslarken ekranin anlik goruntusu alinir, hatada geri yuklenir.
function anlikGoruntuYontemi(olaylar) {
  let ekran = [...TABAN];
  const goruntu = new Map();
  const satirlar = [];
  for (const [ad, tur] of olaylar) {
    if (tur === "basla") { goruntu.set(ad, [...ekran]); ekran = DEGISIKLIK[ad].uygula(ekran); }
    else if (tur === "basarili") { goruntu.delete(ad); }
    else { ekran = goruntu.get(ad); goruntu.delete(ad); }
    satirlar.push([`${ad} ${tur}`, [...ekran]]);
  }
  return satirlar;
}

// 2. Yontem: sunucu tabani ayri tutulur, bekleyen degisiklikler her cizimde uzerine uygulanir.
function bekleyenKatmanYontemi(olaylar) {
  let taban = [...TABAN];
  const bekleyen = [];
  const ciz = () => bekleyen.reduce((l, ad) => DEGISIKLIK[ad].uygula(l), taban);
  const satirlar = [];
  for (const [ad, tur] of olaylar) {
    if (tur === "basla") bekleyen.push(ad);
    else {
      bekleyen.splice(bekleyen.indexOf(ad), 1);
      if (tur === "basarili") taban = DEGISIKLIK[ad].uygula(taban);   // sunucu onayi tabana islenir
    }
    satirlar.push([`${ad} ${tur}`, ciz()]);
  }
  return satirlar;
}

function karsilastir(baslik, olaylar) {
  console.log(`-- ${baslik} --`);
  const a = anlikGoruntuYontemi(olaylar);
  const b = bekleyenKatmanYontemi(olaylar);
  console.log("olay".padEnd(14), "anlik goruntu".padEnd(30), "bekleyen katman");
  for (let i = 0; i < a.length; i++)
    console.log(a[i][0].padEnd(14), a[i][1].join(",").padEnd(30), b[i][1].join(","));
}

karsilastir("tek degisiklik, basarisiz", [["A", "basla"], ["A", "basarisiz"]]);
karsilastir("iki degisiklik, ilki basarisiz", [
  ["A", "basla"], ["B", "basla"], ["B", "basarili"], ["A", "basarisiz"]]);
karsilastir("iki degisiklik, ikisi de basarili", [
  ["A", "basla"], ["B", "basla"], ["B", "basarili"], ["A", "basarili"]]);
-- tek degisiklik, basarisiz --
olay           anlik goruntu                  bekleyen katman
A basla        T-01,T-03                      T-01,T-03
A basarisiz    T-01,T-02,T-03                 T-01,T-02,T-03
-- iki degisiklik, ilki basarisiz --
olay           anlik goruntu                  bekleyen katman
A basla        T-01,T-03                      T-01,T-03
B basla        T-01,T-03,T-04                 T-01,T-03,T-04
B basarili     T-01,T-03,T-04                 T-01,T-03,T-04
A basarisiz    T-01,T-02,T-03                 T-01,T-02,T-03,T-04
-- iki degisiklik, ikisi de basarili --
olay           anlik goruntu                  bekleyen katman
A basla        T-01,T-03                      T-01,T-03
B basla        T-01,T-03,T-04                 T-01,T-03,T-04
B basarili     T-01,T-03,T-04                 T-01,T-03,T-04
A basarili     T-01,T-03,T-04                 T-01,T-03,T-04

İlk senaryoda iki yöntem aynı sonucu verir. Silinen satır geri gelir, ekran istek öncesi hâline döner.

İkinci senaryonun son satırı ise ayrışır. Silme başarısız olduğunda anlık görüntü yöntemi ekranı, silmenin başladığı andaki hâle döndürür — o an henüz eklenmemiş olan T-04 kaybolur. Kullanıcı hiç hata yapmadığı bir işlemin sonucunun ekrandan silindiğini görür ve bunun nedenini anlayamaz.

Bekleyen katman yöntemi aynı satırda doğru sonucu verir. Başarısız değişiklik listeden çıkarılır, taban ise başarılı olan değişikliğin sonucunu zaten almıştır; ekran yeniden hesaplandığında hem silinen satır geri gelir hem de eklenen satır yerinde kalır.

Fark yöntemin kendisinden gelir. Anlık görüntü, ekranın bir andaki sonucunu saklar ve o sonuç başka değişikliklerin izini de taşır. Bekleyen katman ise yalnız değişikliğin kendisini saklar; geri alma, tek bir değişikliği kaldırıp yeniden hesaplamaktır.

Sunucu Yanıtıyla Uzlaşma

Başarılı yanıt geldiğinde bekleyen değişiklik listeden çıkarılır, ama ekranın bozulmaması için tabanın da güncellenmesi gerekir. İki yol vardır.

Sunucu yanıtında güncel kaydı döndürüyorsa taban doğrudan güncellenir; ek istek yapılmaz. Döndürmüyorsa Sunucu Durumu Yönetimi dersindeki geçersizleştirme kullanılır: etkilenen anahtarlar bayatlatılır ve bir sonraki okumada yenilenir. İkinci yolda kısa bir aralık oluşur — bekleyen çıkarılmış, taze veri henüz gelmemiştir — ve bu aralıkta ekran bir an eski veriyi gösterebilir. Bu nedenle bekleyen değişiklik, yenileme tamamlanana kadar listede bırakılabilir.

İyimser sonucun sunucu sonucundan ayrılabildiği durumlar da vardır. Yeni bir kayıt eklenirken kimliği sunucu üretir; istemcinin koyduğu geçici kimlik yanıt gelince gerçek kimlikle değiştirilir. Zaman damgası, sıra numarası ve sunucuda hesaplanan toplamlar da aynı gruptadır. Kural şudur: iyimser değer bir tahmindir ve doğru kaynak yanıttır; tahminle yanıt çeliştiğinde yanıt kazanır.

İyimserliğin Uygulanmadığı Yerler

İyimser güncelleme her işlem için uygun değildir. Üç ölçüt onu dışarıda bırakır.

Sonuç öngörülemiyorsa uygulanmaz. Sunucunun çalıştırdığı bir doğrulama, bir kota denetimi ya da bir çakışma çözümü varsa istemci sonucu bilemez; tahmin sık tutmayacaktır.

Başarısızlık olağansa uygulanmaz. Geri alma seyrek olduğunda kabul edilebilir; sık olduğunda ekran sürekli kendini düzeltiyor görünür ve kullanıcı hiçbir şeye güvenemez.

İşlem geri alınamıyorsa uygulanmaz. Bir ödeme, bir dış bildirim gönderimi ya da kalıcı bir silme işleminde ekranda başarı göstermek, henüz olmamış bir şeyi olmuş gibi sunmaktır. Bu işlemlerde bekleme göstergesi doğru davranıştır.

Aynı uygulamada iki yaklaşım bir arada bulunur: ölçüm silme ve etiket değiştirme iyimser yapılır, istasyon kaydı ve yetki değişikliği yanıt beklenerek yapılır.

Başarısızlığın Görünürlüğü

Geri alma sessiz yapılamaz. Ekranda kaybolan bir satırın geri gelmesi, kullanıcı için açıklanmamış bir olaydır; işlemin başarısız olduğunu söylemeyen bir arayüz, kullanıcıyı işlemin yapıldığına inandırmış olur.

Başarısızlık bildirimi üç şeyi taşır: hangi işlemin başarısız olduğu, nedeni ve yeniden deneme yolu. Bildirimin ekran okuyucuya da ulaşması gerekir; Belge ve Olaylar konusunda kurulan odak ve duyuru kuralları burada geçerlidir.

Yeniden deneme kendiliğinden yapılacaksa, Eşzamansız JavaScript ve Çalışma Zamanı kursundaki geri çekilme kuralları uygulanır ve deneme sırasında değişiklik bekleyen listesinde tutulmaya devam eder. Kullanıcıya ancak son deneme de başarısız olduğunda hata gösterilir.

Özet

  • İyimser güncelleme, beklenen sonucu yanıttan önce ekrana yansıtır; kazancı ağ süresinde değil, bekleme algısında ve arayüzün sadeleşmesindedir.
  • Anlık görüntüyle geri alma, ekranın bir andaki sonucunu sakladığı için araya giren başka bir değişikliğin sonucunu da siler.
  • Bekleyen değişiklik katmanı sunucu tabanını ayrı tutar ve ekranı her seferinde yeniden hesaplar; geri alma tek bir değişikliği listeden çıkarmaktır.
  • Başarılı yanıt tabana işlenir ya da ilgili anahtarlar geçersizleştirilir; iyimser değer bir tahmindir, sunucu yanıtıyla çeliştiğinde yanıt kazanır.
  • Sonucu öngörülemeyen, sık başarısız olan ve geri alınamayan işlemlerde iyimserlik uygulanmaz; bekleme göstergesi doğru davranıştır.
  • Geri alma sessiz yapılmaz: hangi işlemin neden başarısız olduğu ve nasıl yeniden deneneceği kullanıcıya bildirilir.

Sonraki Adım

Durumun nereye konacağı ve nasıl güncelleneceği çözüldü, ama tümü bellekte duruyor. Kullanıcı sekmeyi kapattığında arayüz teması, seçili birim sistemi ve yarım kalan ölçüm formu kayboluyor; sayfa yenilendiğinde uygulama baştan kuruluyor. Tarayıcı ve Web Platformu kursundaki depolama katmanları bunu saklayacak yeri sağlıyor, ama hangi durumun saklanacağı, saklanan kaydın kod değiştiğinde nasıl okunacağı ve iki sekmenin aynı depoya yazmasının ne üreteceği ayrı sorular. Sonraki ders durumu kalıcılaştırmayı ele alır.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat