Mobil uygulamalarda bağlantı çoğu zaman ikili bir durum değildir. Kullanıcı metroda, zayıf Wi-Fi altında veya kısa süreli ağ geçişlerinde uygulamayı kullanmaya devam eder. Bağlantı göstergesi açık olsa bile istek gecikebilir, zaman aşımına uğrayabilir ya da sunucu yanıtı cihaza dönmeden önce bağlantı kopabilir. Bu nedenle çevrimdışı davranış, yalnızca bir hata ekranı tasarlama konusu değildir; veri modelinin ve kullanıcı deneyiminin temel bir parçasıdır.
Offline-first yaklaşımında uygulama, ekranda göstereceği ve kullanıcının değiştireceği veriyi önce cihazdaki yerel depodan okur. Ağ, arayüzün çalışmasının ön koşulu değil; yerel değişiklikleri diğer cihazlarla ve sunucuyla uzlaştıran bir kanaldır. Hedef “internet yokken de bir şeyler göstermek” değildir. Hedef, kullanıcı yaptığı işlemin sonucunu hemen görürken verinin daha sonra güvenli biçimde eşitlenmesidir.
Yerel veri, geçici önbellekten fazlasıdır
Çevrimiçi öncelikli bir uygulamada yerel depolama genellikle bir cache olarak düşünülür: ağ çalışıyorsa sunucudan yeni veri alınır, çalışmıyorsa eldeki eski veri gösterilir. Offline-first tasarımda ise yerel veritabanı uygulamanın çalışma kaynağıdır. Ekranlar sorgularını buradan yapar; yeni kayıt, düzenleme ve silme işlemleri de önce burada gerçekleşir.
Bu düzen iki önemli fayda sağlar. Birincisi, etkileşim gecikmesi ağın durumuna bağlı olmaktan çıkar. Kullanıcı bir ders kaydı eklediğinde, not düzelttiğinde veya bir etkinliği tamamladığında değişiklik anında görünür. İkincisi, uygulamanın her ekranda “bekleniyor”, “yeniden dene” ve kısmi veri durumlarıyla mücadele etmesi gerekmez; tek bir tutarlı okuma kaynağı vardır.
Elbette yerel kaynak yaklaşımı, senkronizasyon sorumluluğunu ortadan kaldırmaz. Aksine, bu sorumluluğu görünür ve tasarlanabilir hale getirir.
Veri modeline kimlik, sürüm ve silme bilgisi ekleyin
Senkronize edilecek her kaydın cihazdan bağımsız, kalıcı bir kimliğe ihtiyacı vardır. Sunucunun sonradan atadığı sayısal bir kimlik, cihaz çevrimdışıyken yeni kayıt üretmek için yeterli değildir. İstemci tarafında oluşturulan UUID benzeri kimlikler, kaydın yaşam döngüsü boyunca aynı kalabilir.
Kayıtların ayrıca değişiklik sırasını anlamaya yarayan alanlara ihtiyacı vardır. updatedAt tek başına çoğu zaman yeterli değildir; cihaz saatleri farklı olabilir ve aynı anda yapılan değişikliklerde sıralama belirsizleşebilir. Sunucunun verdiği sürüm numarası, mantıksal saat veya revizyon belirteci; istemcinin hangi değişikliği gördüğünü açıkça ifade eder.
Silme için de aynı özen gerekir. Bir kaydı cihazdan hemen kaldırmak, diğer cihazların bu kaydın silindiğini öğrenmesini engeller. Bunun yerine yumuşak silme (deletedAt veya isDeleted) kullanmak, silme olayının senkronize edilmesini sağlar. Kayıt ancak tüm aktif istemciler için güvenli bir saklama süresi geçtikten sonra fiziksel olarak temizlenebilir.
Yazma akışını bir değişiklik günlüğüyle ayırın
Kullanıcının yaptığı her işlem doğrudan ağ isteğine dönüşürse, bağlantı kopmalarında aynı işlemin tekrar gönderilip gönderilmediğini anlamak zorlaşır. Daha güvenilir desen şudur: kullanıcı eylemi önce yerel veritabanındaki kayıtla birlikte bir değişiklik günlüğüne yazılır. Günlükte işlem türü, kayıt kimliği, önceki sürüm, deneme sayısı ve idempotency anahtarı yer alabilir.
Arka plan senkronizasyonu bu günlüğü sırayla işler. İstek zaman aşımına uğrarsa, “başarısız” sonucu işlemin sunucuya hiç ulaşmadığını kanıtlamaz. Aynı idempotency anahtarıyla tekrar denemek, sunucunun çift kayıt oluşturmadan isteği güvenle ele almasını sağlar. Başarılı yanıt geldiğinde günlük kaydı tamamlandı olarak işaretlenir ve sunucunun verdiği sürüm yerel kayda uygulanır.
Bu yapı, kullanıcı deneyiminde de netlik sağlar. Arayüz yalnızca “kaydedildi” demek yerine, gerektiğinde “bu cihazda kaydedildi, eşitlenmesi bekleniyor” durumunu gösterebilir. Kullanıcı verisinin kaybolmadığını bilir; ekip de sorun anında hangi değişikliklerin kuyrukta olduğunu inceleyebilir.
Çakışma çözümü alanın anlamına bağlıdır
İki cihaz aynı kaydı değiştirdiğinde tek bir evrensel kural her zaman doğru değildir. “Son yazan kazanır” basit görünür; ancak kullanıcıların farklı alanları değiştirdiği bir kayıtta gereksiz veri kaybı yaratabilir. Örneğin bir kişi telefonundan iletişim bilgilerini güncellerken başka biri tablette sadece not alanını değiştirmiş olabilir.
Bu nedenle alan bazlı birleştirme çoğu ürün için iyi bir başlangıçtır. Her alanın kendi değişiklik zamanı veya revizyonu izlenir; yalnızca çakışan alanlar için karar gerekir. Toplama ve liste gibi yapılar farklı stratejilere ihtiyaç duyabilir: ekleme işlemleri birleşebilir, sıralama ayrı bir anahtarla korunabilir, aynı öğenin metni değiştiğinde ise kullanıcıya seçim sunmak daha doğru olabilir.
Bazı veriler otomatik birleştirmeye uygun değildir. Ödeme tutarı, kota, ders paketi bakiyesi veya zaman çakışması olan randevu gibi alanlarda sunucu iş kuralının nihai otorite olması gerekir. İstemci iyimser olarak güncelleyebilir; fakat sunucu reddederse kullanıcıya anlaşılır bir düzeltme yolu sunmalıdır.
Çekme ve itme aynı protokolün parçalarıdır
Senkronizasyon yalnızca bekleyen yerel değişiklikleri sunucuya göndermek değildir. İstemci, diğer cihazlardan gelen değişiklikleri de düzenli olarak çekmelidir. Bunun için son görülen sunucu revizyonunu ya da bir sync token’ını saklamak pratiktir. İstemci “bana bu noktadan sonra ne değişti?” diye sorar; sunucu eklenen, güncellenen ve silinen kayıtları döndürür.
İtme ve çekme sırası ürünün kurallarına göre değişebilir, fakat her iki yönün de tekrar çalıştırılabilir olması önemlidir. Uygulama kapanırken, tekrar açılırken, bağlantı geri geldiğinde veya kullanıcı yenileme istediğinde aynı senkronizasyon adımı güvenle başlatılabilmelidir. Bu özellik, zamanlama hatalarını ve ağın öngörülemezliğini daha az kritik hale getirir.
Gözlemlenebilirlik ve gizlilik sonradan eklenmemeli
Senkronizasyon hatalarının büyük bölümü kullanıcının ekranında görünmez. Bu yüzden kuyruk uzunluğu, son başarılı senkronizasyon zamanı, tekrar deneme sayısı, çakışma oranı ve sunucu reddi gibi metrikler izlenmelidir. Kayıt kimlikleri ve hassas içerik loglara yazılmadan, olay zincirini takip etmeyi sağlayan teknik tanımlayıcılar kullanılabilir.
Yerel depoda kişisel veri varsa cihaz güvenliği, şifreleme, oturum kapatıldığında temizleme ve yetki değişiminde veri erişimini kesme de tasarımın içindedir. Offline-first olmak, yetkilendirme kurallarını çevrimdışında görmezden gelmek anlamına gelmez.
İyi senkronizasyon, kullanıcıdan ağın karmaşıklığını saklar ama sistemden saklamaz. Yerel kayıt, değişiklik günlüğü, sürümleme ve alanın anlamına uygun çakışma kuralları birlikte tasarlandığında mobil uygulama bağlantı değişse bile güvenilir ve sakin davranır.