Çevrimdışı Çalışan Uygulama Yazmak ve Çakışmaları Çözmek
Çevrimdışı desteği "veriyi yerelde tut" demek değil. Asıl zor kısım, iki taraf da aynı kaydı değiştirdiğinde ne olacağına karar vermek.
Bir uygulamanın çevrimdışı çalışması, kullanıcı için sihir gibi görünüyor: internet yokken de her şey duruyor, bağlantı gelince kendiliğinden yerine oturuyor. Geliştirici tarafında ise bu, üzerinde en çok düşünülmesi gereken konulardan biri.
Çünkü kolay kısım veriyi yerelde saklamak. Zor kısım şu soru: iki taraf da aynı kaydı değiştirdiyse hangisi kazanacak?
Önce şunu netleştirin: her veri aynı değil
Uygulamadaki her verinin çevrimdışı davranışı aynı olmak zorunda değil. Ben veriyi üçe ayırıyorum:
| Tür | Örnek | Çevrimdışı davranış |
|---|---|---|
| Yalnızca kullanıcının | Kişisel notlar, ayarlar | Tam çevrimdışı yazma. Çakışma neredeyse hiç olmaz. |
| Paylaşılan | Ekip görevleri, ortak liste | Çevrimdışı yazma mümkün ama çakışma stratejisi şart. |
| Sunucunun otoritesinde | Stok, bakiye, ödeme | Çevrimdışı yazmaya hiç izin vermeyin. Kuyruğa alın, sunucu karar versin. |
Bu ayrımı baştan yapmak, sonradan çözülmesi çok zor olan bir sınıf problemi ortadan kaldırıyor. Bakiyeyi çevrimdışı düşürmeye izin verirseniz, kullanıcı uçak modunda parasından fazlasını harcayabiliyor.
Varsayılan strateji: son yazan kazanır
Çoğu araç varsayılan olarak bunu yapıyor: en son gelen yazma işlemi öncekini eziyor. Uygulaması kolay, ama sessizce veri kaybettiriyor. Kullanıcı yazdığı notun kaybolduğunu ancak günler sonra fark ediyor ve neden olduğunu asla anlamıyor.
"Son yazan" kararını cihazın saatine göre veriyorsanız, saati yanlış ayarlanmış tek bir cihaz tüm senkronizasyonu bozabilir. Zaman damgasını sunucu üretmeli; istemcinin gönderdiği saati kayıt için değil, yalnızca bilgi olarak tutun.
Daha iyisi: alan düzeyinde birleştirme
Çoğu çakışma aslında gerçek bir çakışma değil. Kullanıcı çevrimdışıyken görevin başlığını değiştirdi, siz panelden son tarihini değiştirdiniz. Dokümanın tamamını ezmek yerine yalnızca değişen alanları birleştirmek ikisini de koruyor.
// Tüm dokümanı göndermek yerine sadece değişen alanı gönder
// (Firestore'da update, REST'te PATCH mantığı)
db.collection("gorevler").document(id)
.update(mapOf("baslik" to yeniBaslik))
Bunu yapabilmek için istemcinin neyin değiştiğini bilmesi gerekiyor. Yani yerel tarafta "bu kaydın şu alanları değişti" bilgisini tutmak, tüm nesneyi göndermekten daha fazla iş ama sonuç çok daha sağlam.
Bekleyen işlemleri kuyrukta tutun
Çevrimdışı yapılan değişiklikleri doğrudan "veri" olarak değil, işlem olarak saklamak işleri kolaylaştırıyor. Bağlantı gelince kuyruk sırayla işleniyor.
// Veriyi değil, niyeti sakla
{ "islem": "gorev_ekle", "id": "g_918", "veri": { ... }, "zaman": 1723... }
{ "islem": "gorev_guncelle", "id": "g_204", "alanlar": ["baslik"] }
{ "islem": "gorev_sil", "id": "g_177" }
Bu yapı, "önce ekle sonra sil" gibi sıralı işlemlerin doğru uygulanmasını sağlıyor. Ayrıca başarısız olan tek bir işlemi yeniden denemek, tüm senkronizasyonu baştan çalıştırmaktan çok daha ucuz.
İşlemler tekrarlanabilir olmalı
Ağ kopukluğunda aynı isteğin iki kez gitmesi çok olağan. Sunucu bunu ikinci bir işlem sanırsa aynı kayıt iki kez oluşuyor.
Çözüm, her işleme istemcide üretilmiş benzersiz bir kimlik vermek. Sunucu aynı kimliği ikinci kez gördüğünde işlemi tekrar uygulamıyor, sadece önceki sonucu döndürüyor.
Kullanıcıya durumu gösterin
Çevrimdışı destek, kullanıcıyı bilgilendirmediğiniz sürece güven vermiyor. Basit bir durum göstergesi çok işe yarıyor:
- Kaydedildi — sunucuya ulaştı.
- Bekliyor — cihazda duruyor, bağlantı gelince gönderilecek.
- Gönderilemedi — bir sorun var, kullanıcı tekrar deneyebilir.
Bu göstergeyi koymadığınızda kullanıcı, verinin kaydedilip kaydedilmediğinden emin olamadığı için aynı işlemi tekrar tekrar yapıyor — ve asıl karmaşa o zaman başlıyor.
Gerçek çakışmada kullanıcıya sorun
Otomatik olarak çözülemeyen bir çakışma varsa — iki taraf da aynı alanı farklı şekilde değiştirmişse — sessizce birini seçmek yerine kullanıcıya iki sürümü gösterip seçtirmek en dürüst yol. Nadiren olur, ama olduğunda kullanıcı veri kaybetmemiş olur.
Çevrimdışı desteği, mutlu senaryoda hiç fark edilmeyen ama kötü senaryoda ürünün tamamını kurtaran bir yatırım. Zor kısmı yazmak değil, ne olacağına önceden karar vermek.
- Çevrimdışı
- Senkronizasyon
- Çakışma
- Mimari
- Veri modeli
Demir Taşdemir
Mobil Uygulama & Web Geliştirici
2018'den beri yazılım geliştiriyorum. App Store ve Google Play'de 11 uygulama yayınladım; şu an 6 mobil uygulama, 1 e-ticaret platformu ve 1 masaüstü oyun üzerinde çalışıyorum.
Zor kısmı atlamayan bir yaklaşım
Mutlu senaryoyu herkes yazar. Ürünü ayakta tutan, kenar durumların düşünülmüş olması.