Form Ağırlıklı Android Uygulamalar için Kotlin MVI vs MVVM: UI Durumları
Form ağırlıklı Android uygulamalar için Kotlin MVI ve MVVM karşılaştırması; doğrulama, optimistik UI, hata durumları ve çevrimdışı taslakları pratik yollarla nasıl modelleyeceğiniz açıklanıyor.

Form ağırlıklı Android uygulamalar neden hızla karışır
Form ağırlıklı uygulamalar yavaş veya kırılgan hissedilebilir çünkü kullanıcılar, kodunuzun sık sık vermesi gereken küçük kararlarda bekler: bu alan geçerli mi, kayıt başarılı oldu mu, hata göstermeli miyiz, ağ koparsa ne olur gibi.
Ayrıca formlar, birkaç tür durumu aynı anda karıştırdıkları için durum hatalarını ilk gösterir: UI durumu (ne görünür), giriş durumu (kullanıcının yazdıkları), sunucu durumu (ne kaydedildi) ve geçici durum (hangisi ilerlemekte). Bunlar uyumsuzlaştığında uygulama “rastgele” davranmaya başlar: butonlar yanlış zamanda devre dışı kalır, eski hatalar kalır veya ekran döndürmede sıfırlanır.
Çoğu sorun dört alanda toplanır: doğrulama (özellikle alanlar arası kurallar), optimistik UI (iş devam ederken hızlı geri bildirim), hata yönetimi (açık, kurtarılabilir hatalar) ve çevrimdışı taslaklar (tamamlanmamış işi kaybetmemek).
İyi form UX’i birkaç basit kurala uyar:
- Doğrulama yardımcı olmalı ve alana yakın olmalı. Yazmayı engellemeyin. Önemli olduğunda, genellikle gönderimde katı olun.
- Optimistik UI kullanıcının eylemini hemen yansıtmalı, ama sunucu reddederse temiz bir geri alma yolu olmalı.
- Hatalar özgül, yapılabilir olmalı ve asla kullanıcının girdisini silmemeli.
- Taslaklar yeniden başlatmalarda, kesintilerde ve kötü bağlantılarda hayatta kalmalı.
İşte bu yüzden formlar için mimari tartışmaları yoğunlaşır. Seçtiğiniz desen, bu durumların baskı altında ne kadar öngörülebilir hissettireceğini belirler.
Kısa tekrar: MVVM ve MVI basitçe
MVVM ve MVI arasındaki gerçek fark, ekran boyunca değişimin nasıl aktığıdır.
MVVM (Model View ViewModel) genellikle şöyle görünür: ViewModel ekran verilerini tutar, UI’ya (çoğunlukla StateFlow veya LiveData ile) açar ve save, validate veya load gibi metodlar sağlar. UI, kullanıcı etkileşince ViewModel fonksiyonlarını çağırır.
MVI (Model View Intent) genelde şöyle işler: UI olaylar (intentler) gönderir, bir reducer bunları işler ve ekran şu an UI’nin ihtiyaç duyduğu her şeyi temsil eden tek bir durum nesnesinden render edilir. Yan etkiler (network, database) kontrollü şekilde tetiklenir ve sonuçlarını olay olarak geri bildirir.
Akıl yürütme biçimi şöyle özetlenebilir:
- MVVM sorar: “ViewModel hangi veriyi açmalı ve hangi metotları sunmalı?”
- MVI sorar: “Hangi olaylar olabilir ve bunlar bir durumu nasıl başka bir duruma dönüştürür?”
Basit ekranlar için her iki desen de iyi çalışır. Ancak alanlar arası doğrulama, otomatik kaydetme, yeniden denemeler ve çevrimdışı taslaklar eklediğinizde, kim hangi durumda değişiklik yapabilir ve ne zaman yapmalı gibi daha katı kurallara ihtiyaç duyarsınız. MVI bu kuralları varsayılan olarak zorlar. MVVM yine iyi çalışabilir ama disiplin gerektirir: tutarlı güncelleme yolları ve tek seferlik UI olaylarının (toast, navigasyon) dikkatli yönetimi.
Form durumunu sürpriz olmadan modelleme
Kontrolü kaybetmenin en hızlı yolu form verilerinin çok fazla yerde yaşamasına izin vermektir: view bindingler, birden fazla flow ve "bir tane daha" boolean. Form ağırlıklı ekranlar tahmin edilebilir kalırsa tek bir doğruluk kaynağı olduğunda.
Pratik bir FormState yapısı
Ham girdileri ve güvenilir birkaç türev bayrağı tutan tek bir FormState hedefleyin. Sıkıcı ama eksiksiz tutun, biraz büyük hissetse bile.
data class FormState(
val fields: Fields,
val fieldErrors: Map\u003cFieldId, String\u003e = emptyMap(),
val formError: String? = null,
val isDirty: Boolean = false,
val isValid: Boolean = false,
val submitStatus: SubmitStatus = SubmitStatus.Idle,
val draftStatus: DraftStatus = DraftStatus.NotSaved
)
sealed class SubmitStatus { object Idle; object Saving; object Saved; data class Failed(val msg: String) }
sealed class DraftStatus { object NotSaved; object Saving; object Saved }
Bu yapı alan düzeyindeki doğrulamayı (her giriş için) form düzeyi problemlerinden (ör. "toplam \u003e 0 olmalı") ayrı tutar. isDirty ve isValid gibi türev bayraklar bir yerde hesaplanmalı, UI’da yeniden uygulanmamalıdır.
Temiz bir zihinsel model: fields (kullanıcının yazdıkları), validation (yanlış olan), status (uygulamanın ne yaptığı), dirtiness (son kayıttan bu yana ne değişti) ve drafts (çevrimdışı kopya olup olmadığı).
Tek seferlik efektler nerede olmalı
Formlar ayrıca tek seferlik olaylar tetikler: snackbarlar, navigasyon, "kaydedildi" banner’ları. Bunları FormState içine koymayın, yoksa döndürme veya UI yeniden abone olduğunda tekrar tetiklenirler.
MVVM’de efekti ayrı bir kanal (örneğin SharedFlow) ile yayınlayın. MVI’de bunları UI’nin bir kez tükettiği Effects (veya Events) olarak modelleyin. Bu ayrım “hayalet” hataları ve çift başarı mesajlarını önler.
Doğrulama akışı: MVVM vs MVI
Doğrulama form ekranlarını en kırılgan hissettiren alanlardan biridir. Ana seçim kuralların nerede olduğu ve sonuçların UI’ya nasıl döndüğüdür.
Basit, senkron kurallar (zorunlu alan, min uzunluk, sayı aralıkları) UI içinde değil ViewModel veya domain katmanında çalıştırılmalıdır. Bu kuralları test edilebilir ve tutarlı kılar.
Asenkron kurallar ("bu e-posta zaten alındı mı?") daha zordur. Yüklenme, eskimiş sonuçlar ve "kullanıcı tekrar yazdı" durumunu ele almanız gerekir.
MVVM’de doğrulama genellikle state ve yardımcı metotların bir karışımı haline gelir: UI değişikleri (metin güncellemeleri, odak kayıpları, gönderme tıklamaları) ViewModel’e gönderir; ViewModel bir StateFlow/LiveData günceller ve alan bazlı hatalar ile türetilmiş "canSubmit" gibi değerler açar. Async kontroller genellikle bir iş başlatır, bir yükleme bayrağı ve tamamlandığında bir hata günceller.
MVI’de doğrulama daha net olur. Pratik görev bölümü şöyle olabilir:
- Reducer senkron doğrulamayı çalıştırır ve alan hatalarını hemen günceller.
- Bir effect asenkron doğrulamayı yapar ve bir sonuç intent gönderir.
- Reducer o sonucu yalnızca hâlâ en son girdiye uyuyorsa uygular.
Son adım önemlidir. Kullanıcı e-posta yazarken "unique email" kontrolü çalışıyorsa ve kullanıcı aynı anda yeni bir şey yazdıysa, eski sonuçlar mevcut girdiyi ezmemeli. MVI bunu kodlamak için sıklıkla daha uygundur çünkü son doğrulanan değeri state içinde saklayıp eski yanıtları yok sayabilirsiniz.
Optimistik UI ve asenkron kayıtlar
Optimistik UI, ağ yanıtı gelmeden önce ekranın kaydın başarılıymış gibi davranması demektir. Bir formda bu genelde Kaydet düğmesinin "Saving..."a dönmesi, küçük bir "Saved" göstergesinin görünmesi ve girdilerin kullanılmaya devam etmesi (veya kasıtlı olarak kilitlenmesi) ile olur.
MVVM’de bu genelde isSaving, lastSavedAt ve saveError gibi bayrakları değiştirmekle uygulanır. Risk, çakışan kayıtların bu bayrakları tutarsız bırakmasıdır. MVI’de reducer tek bir durum nesnesini güncellediği için "Saving" ve "Disabled" gibi bayraklar daha az çelişir.
Çift gönderimleri ve yarış durumlarını önlemek için her kaydı tanımlanmış bir olay olarak ele alın. Kullanıcı iki kere Kaydet’e tıklarsa veya kaydederken düzenleme yaparsa hangi yanıtın kazanacağına dair kural gerekir. Her iki desen için birkaç korunma işe yarar: kaydederken Kaydet’i devre dışı bırakmak (veya tıklamaları debouncelamak), her kayda requestId (veya versiyon) ekleyip eski yanıtları yok saymak, kullanıcı ayrıldığında devam eden işi iptal etmek ve kaydetme sırasında yapılan düzenlemelerin ne anlama geldiğini (başka bir kaydı sıraya almak veya formu tekrar kirletmek) tanımlamak.
Kısmi başarı da yaygındır: sunucu bazı alanları kabul eder ama diğerlerini reddeder. Bunu açıkça modelleyin. Per-alan hataları tutun (ve gerekirse alan bazlı senkron durumunu) böylece genel olarak "Kaydedildi" gösterilirken hâlâ dikkat gerektiren bir alan vurgulanabilir.
Kullanıcının kurtarabileceği hata durumları
Form ekranları sadece "bir şeyler yanlış gitti" şeklinde başarısız olmaz. Her hata genel bir toast olursa, kullanıcılar veriyi tekrar yazar, güven kaybeder ve süreci bırakır. Hedef her zaman aynıdır: girdiyi güvende tutmak, net bir düzeltme göstermek ve yeniden denemeyi normal hissettirmek.
Hataları nerede olduklarına göre ayırmak yardımcı olur. Yanlış bir e-posta formatı bir sunucu kesintisiyle aynı şey değildir.
Alan hataları inline ve ilgili girişe bağlı olmalı. Form-düzeyi hatalar gönderme yakınında yer almalı ve gönderimi engelleyen nedenleri açıklamalı. Ağ hataları yeniden deneme sunmalı ve formu düzenlenebilir tutmalı. İzin veya kimlik hataları kullanıcıyı yeniden kimlik doğrulamaya yönlendirmeli ama taslağı korumalı.
Temel bir kurtarma kuralı: başarısızlıkta kullanıcı girdisini asla temizleme. Kayıt başarısız olursa, mevcut değerleri bellekte ve diskte tutun. Yeniden deneme, kullanıcı düzenlemediyse aynı payload’u tekrar göndermeli.
Farklı desenler arasında ayrım, sunucu hatalarının UI durumuna nasıl eşlendiğidir. MVVM’de birden fazla flow veya alanı güncellemek kolaydır ve istemeden tutarsızlıklara yol açabilir. MVI’de genellikle sunucu yanıtını tek bir reducer adımında uygulamak daha yaygındır; böylece fieldErrors ve formError birlikte güncellenir.
Ayrıca neyin state neyin tek seferlik efekt olduğuna karar verin. Inline hatalar ve "gönderim başarısız" durumları state içinde olmalı (dönüşte kalmalı). Snack bar, titreşim veya navigasyon gibi tek seferlik işlemler efekt olmalı.
Çevrimdışı taslaklar ve devam eden formların geri yüklenmesi
Form ağırlıklı bir uygulama, ağ iyi olsa bile "çevrimdışı" hissedebilir. Kullanıcı uygulamalar arasında geçiş yapar, OS process’i öldürür veya bağlantı ortasında sinyal kaybetmiştir. Taslaklar bunun tekrar başlamasını engeller.
Önce taslağın ne anlama geldiğini tanımlayın. Sadece "temiz" modeli kaydetmek genelde yeterli olmaz. Genellikle ekranın tam olarak nasıl görünüyorduysa onu geri yüklemek istersiniz; yarım yazılmış alanlar dahil.
Saklanmaya değer olan genellikle ham kullanıcı girdisidir (yazıldığı haliyle stringler, seçilmiş ID’ler, ek URI’leri), artı daha sonra güvenli bir şekilde birleştirmek için yeterli meta veri: son bilinen sunucu anlık görüntüsü ve bir versiyon işareti (updatedAt, ETag veya basit bir artan sayı). Doğrulama geri yüklemede yeniden hesaplanabilir.
Depolama seçimi hassasiyete ve boyuta bağlıdır. Küçük taslaklar tercihlerde (preferences) yaşayabilir; çok adımlı formlar ve ekler yerel veritabanında daha güvenlidir. Taslak kişisel veri içeriyorsa, şifreli depolama kullanın.
En büyük mimari soru doğruluk kaynağının nerede olduğudur. MVVM’de ekipler genellikle alan değişiklikleri oldukça ViewModel’den persist eder. MVI’de her reducer güncellemesinden sonra persist etmek daha basit olabilir çünkü tek bir tutarlı durum (veya türetilmiş bir Draft nesnesi) kaydediliyor.
Autosave zamanlaması önemlidir. Her tuş vuruşunda kaydetmek gürültülüdür; kısa bir debounce (ör. 300–800 ms) ve adım değişikliklerinde kaydetme iyi çalışır.
Kullanıcı çevrimiçi olduğunda geri geldiğinde birleştirme kurallarına ihtiyacınız vardır. Pratik yaklaşım: sunucu versiyonu değişmediyse taslağı uygula ve gönder; değiştiyse net bir seçim göster: taslağı tut veya sunucu verisini yeniden yükle.
Adım adım: her iki desenle güvenilir bir form implementasyonu
Güvenilir formlar net kurallarla başlar, UI koduyla değil. Her kullanıcı eylemi öngörülebilir bir duruma yol açmalı ve her async sonuç tek bir belirgin yere inmelidir.
Ekranınızın tepki vermesi gereken eylemleri yazın: yazma, odak kaybı, gönderme, yeniden deneme ve adım navigasyonu. MVVM’de bunlar ViewModel metotları ve state güncellemeleri olur. MVI’de bunlar açık intentler olur.
Sonra küçük adımlarla kurun:
- Tam yaşam döngüsü için olayları tanımlayın: edit, blur, submit, save success/failure, retry, restore draft.
- Tek bir durum nesnesi tasarlayın: alan değerleri, alan hataları, genel form durumu ve "kaydedilmemiş değişiklik".
- Doğrulamayı ekleyin: düzenleme sırasında hafif kontroller, gönderimde daha ağır kontroller.
- Optimistik kaydetme kurallarını ekleyin: ne hemen değişir, ne geri alma tetikler.
- Taslakları ekleyin: debounce ile otomatik kaydet, açılışta restore ve kullanıcıya gösterilecek küçük bir "taslak geri yüklendi" göstergesi ekleyin.
Hataları deneyimin bir parçası olarak ele alın. Girdiyi koruyun, sadece düzeltilmesi gerekenleri vurgulayın ve bir sonraki açık adımı teklif edin (düzenle, yeniden dene veya taslağı tut).
Karmaşık form durumlarını Android UI yazmadan önce test etmek isterseniz, AppMaster gibi no-code bir platform iş akışını doğrulamak için faydalı olabilir. Böylece aynı kuralları MVVM veya MVI ile uygulamaya geçirirken sürprizleri azaltırsınız.
Örnek senaryo: çok adımlı gider raporu formu
Dört adımlı gider raporunu düşünün: detaylar (tarih, kategori, miktar), fiş yükleme, notlar, sonra incele ve gönder. Gönderme sonrası Draft, Submitted, Rejected, Approved gibi onay durumları gösterir. Zorlayıcı kısımlar doğrulama, başarısız olabilecek kayıtlar ve telefon çevrimdışıyken taslağın korunmasıdır.
MVVM’de genellikle ViewModel içinde bir FormUiState (çoğunlukla StateFlow) tutarsınız. Her alan değişikliği onAmountChanged() veya onReceiptSelected() gibi ViewModel fonksiyonunu çağırır. Doğrulama değişiklik, adım geçişi veya gönderme sırasında çalıştırılır. Ortak yapı ham girdiler + alan hatalarıdır; türetilmiş bayraklar Next/Submit’in etkin olup olmadığını kontrol eder.
MVI’de aynı akış açık intentlere dönüşür: AmountChanged, NextClicked, SubmitClicked, RetrySave. Reducer yeni bir durum döner. Yan etkiler (fiş yükleme, API çağrısı, snackbar gösterme) reducer dışarıda çalışır ve sonuçları olaylar olarak geri yollar.
Pratikte MVVM, fonksiyon ekleyip bir flow’u hızlıca güncellemek için uygundur. MVI ise yanlışlıkla bir durum geçişini atlamayı zorlaştırır çünkü her değişiklik reducer üzerinden akar.
Yaygın hatalar ve tuzaklar
Çoğu form hatası, gerçeğin kimin elinde olduğu, doğrulamanın ne zaman çalıştığı ve async sonuçlar geç geldiğinde ne olduğu konusunda belirsizlikten kaynaklanır.
En yaygın hata doğruluk kaynaklarını karıştırmaktır. Bir text field bazen widget’tan, bazen ViewModel state’inden ve bazen restore edilmiş taslaktan okunuyorsa rastgele sıfırlamalar ve "girdim kayboldu" raporları alırsınız. Ekran için tek bir kanonik state seçin ve her şeyi ondan türetin (alan modeli, cache satırları, API payloadları).
Diğer bir tuzak state ile olayları karıştırmaktır. Toast, navigasyon veya "Kaydedildi!" banner’ı tek seferliktir. Kullanıcının düzenleyene kadar görünmesi gereken hata mesajı ise state’tir. Bunları karıştırmak döndürme sonrası tekrarlanan efektlere veya kaçırılan geri bildirime yol açar.
Sık görülen iki doğruluk sorunu:
- Her tuş vuruşunda aşırı doğrulama, özellikle pahalı kontroller. Debounce yapın, blur’da doğrulayın veya sadece dokunulmuş alanları doğrulayın.
- Sıralar dışı async sonuçları görmezden gelmek. Kullanıcı iki kere kaydeder veya kaydettikten sonra düzenlerse, eski yanıtlar yeni girdileri ezmemeli; request ID veya "yalnızca en son" mantığı kullanın.
Son olarak, taslaklar "sadece JSON kaydetmek" değildir. Versiyonlama yoksa uygulama güncellemeleri restore’ları bozabilir. Basit bir şema versiyonu ve migration hikayesi ekleyin; çok eski taslaklar için bile "sil ve baştan" seçeneği bile olsun.
Yayına almadan önce hızlı kontrol listesi
MVVM vs MVI tartışmadan önce formunuzun tek bir net doğruluk kaynağı olduğundan emin olun. Bir değer ekranda değişebiliyorsa, state içinde olmalı; view widget’ta veya gizli bir bayrakta değil.
Pratik ön-yayın kontrolü:
- State girdileri, alan hatalarını, kayıt durumunu (idle/saving/saved/failed) ve taslak/sıra durumunu içermeli ki UI asla tahmin yürütmek zorunda kalmasın.
- Doğrulama kuralları saf (pure) ve UI olmadan test edilebilir olmalı.
- Optimistik UI için sunucu reddi durumunda geri alma yolu olmalı.
- Hatalar kullanıcı girdisini asla silmemeli.
- Taslak geri yükleme öngörülebilir olmalı: ya net bir otomatik geri yükleme banner’ı ya da açık "Taslağı geri yükle" eylemi.
Gerçek hataları yakalayan bir test: kaydetme sırasında uçak modunu açın, kapatın, sonra iki kez yeniden deneyin. İkinci yeniden deneme çoğaltma oluşturmamalı. Request ID, idempotency anahtarı veya yerel "beklemede kayıt" işareti kullanarak yeniden denemeleri güvenli yapın.
Cevaplarınız belirsizse, önce durum modelini sıkılaştırın; sonra kuralları uygulaması en kolay deseni seçin.
Sonraki adımlar: yol seçimi ve daha hızlı inşa
Bir soruyla başlayın: formunuz tuhaf yarım-güncellenmiş bir durumda kalırsa maliyeti ne kadar yüksek? Maliyet düşükse basit kalın.
MVVM, ekran basitse, durum çoğunlukla "alanlar + hatalar" ise ve ekibiniz ViewModel + LiveData/StateFlow ile zaten güvenli şekilde dağıtım yapıyorsa iyi bir eşleşmedir.
MVI, sıkı, öngörülebilir durum geçişlerine ihtiyaç duyduğunuzda, çok sayıda async olay varsa (otomatik kaydetme, yeniden denemeler, senkronizasyon) veya hataların maliyeti yüksekse (ödeme, uyumluluk, kritik iş akışları) daha uygundur.
Hangi yolu seçerseniz seçin, formlar için en yüksek getirili testler genellikle UI’ya dokunmaz: doğrulama uç vakaları, durum geçişleri (edit, submit, success, failure, retry), optimistik kaydetme geri alma ve taslak geri yükleme + çatışma davranışı.
Backend, admin ekranları ve API’leri de mobil uygulamanızla birlikte yönetmeniz gerekiyorsa, AppMaster (appmaster.io) tek bir modelden üretim kalitesinde backend, web ve native mobil uygulamalar oluşturabilir; böylece doğrulama ve iş akışı kurallarını farklı yüzeylerde tutarlı hale getirebilirsiniz.
SSS
MVVM tercih edin: akışınız çoğunlukla lineer ise ve ekibiniz StateFlow/LiveData, tek seferlik olaylar ve iptal konvansiyonlarında güvenliyse.
MVI tercih edin: çoklu eşzamanlı async işler (otomatik kaydetme, yeniden denemeler, yüklemeler) bekliyorsanız ve durum geçişlerinin daha katı ve öngörülebilir olmasını istiyorsanız.
Tek ekransal durum nesnesiyle başlayın (örneğin FormState) — ham alan değerleri, alan bazlı hatalar, form-düzeyi hata ve Saving/Failed gibi açık durumlar. Türev bayraklar (isValid, canSubmit) tek bir yerde hesaplanmalı, UI yalnızca render etmelidir.
Düzenleme sırasında hafif, ucuz kontroller çalıştırın (zorunlu alan, aralık, temel format). Gönderme sırasında daha sıkı kontroller çalıştırın. Doğrulama kodunu UI içinde tutmayın; böylece test edilebilir olur ve hatalar döndürülüp state içinde saklanır.
Async doğrulamayı “en son girdinin galip geldiği” şekilde ele alın. Doğrulanan değeri (veya bir istek/versiyon id’sini) saklayın ve sonuçlar mevcut durumla eşleşmiyorsa yok sayın. Bu, eski yanıtların yeni yazılanı ezmesini önler.
Kullanıcının eylemini hemen yansıtın (örneğin Saving… gösterin ve girişi görünür tutun), ama sunucu reddederse geri alma yolu mutlaka olsun. İstek id/versiyon kullanın, Kaydet düğmesini devre dışı bırakın veya debouncelayın ve kaydetme sırasında yapılan düzenlemelerin ne anlama geldiğini (alanları kilitleme, yeni bir kaydı sıraya alma veya tekrar kirletme) tanımlayın.
Hata durumunda kullanıcı girdisini asla temizlemeyin. Alan-özgü problemleri ilgili alanın yanında gösterin, form-düzeyi engelleyicileri gönderme yakınında tutun ve ağ hatalarını aynı yükü tekrar gönderecek şekilde yeniden denenebilir yapın (kullanıcı bir şey değiştirmediği sürece aynı yük gönderilsin).
Tek seferlik efektleri kalıcı state’e koymayın. MVVM’de bunları ayrı bir akışta (ör. SharedFlow) yayınlayın; MVI’de onları UI’nin bir kez tükettiği Effects olarak modelleyin. Bu, döndürme veya yeniden abone olma sonrası tekrar eden bildirimleri önler.
Ham kullanıcı girdisini (yazıldığı haliyle) saklayın ve daha sonra güvenli şekilde birleştirmek için yeterli meta veriyi tutun (ör. sunucu versiyon göstergesi). Doğrulamayı geri yüklemede yeniden hesaplayın; doğrulamayı saklamayın. Basit bir şema versiyonu ekleyin ki uygulama güncellemeleri restore’ları kırmasın.
Kısa bir debounce (ör. birkaç yüz ms) ve adım değişikliklerinde veya uygulama arka plana alınırken kaydetme iyi bir dengedir. Her tuş vuruşunda kaydetmek gürültülü olur; sadece çıkışta kaydetmek ise işlem ölümü veya kesinti sırasında veri kaybına yol açabilir.
Sunucu ve taslak için bir versiyon işareti tutun (updatedAt, ETag veya yerel bir sayaç). Sunucu versiyonu değişmemişse taslağı uygulayıp gönderin; değişmişse kullanıcılara net bir seçim gösterin: taslağı koru veya sunucu verisini yeniden yükle. Sessizce üzerine yazmak yerine kullanıcıya seçim sunun.


