ÇalışmalarAğ ve hata yönetimi
Merkezi Ağ Hata Yönetimi ve Kullanıcı Geri Bildirimi
HTTP, bağlantı, zaman aşımı ve veri ayrıştırma hatalarını merkezi olarak sınıflandırıp kullanıcıya anlaşılır, yerelleştirilmiş ve aksiyon alınabilir mesajlar sunan Flutter altyapısı.
Problem
Bir mobil uygulamada “istek başarısız oldu” tek bir hata değildir. Kullanıcının internet bağlantısı kesilmiş olabilir, sunucu zamanında yanıt vermemiş olabilir, oturum süresi dolmuş olabilir, backend iş kuralı nedeniyle isteği reddetmiş olabilir veya başarılı görünen yanıt uygulamanın beklediği modelle uyuşmamış olabilir.
Bu durumlar teknik olarak birbirinden farklıdır ve kullanıcı açısından da farklı karşılıkları vardır. İnterneti olmayan bir kullanıcıya “Beklenmeyen bir hata oluştu” demek yardımcı olmaz. Sunucu hatasını “Bağlantınızı kontrol edin” mesajıyla göstermek ise kullanıcıyı çözemeyeceği bir problemi çözmeye yönlendirir. İptal edilmiş bir isteği hata olarak sunmak da kullanıcıya kendi yaptığı navigasyonun başarısız olduğu izlenimini verir.
Uygulama büyüdükçe her özellik kendi try-catch bloğunu, hata metnini ve HTTP durum kontrolünü
yazmaya başlamıştı. Bunun doğal sonuçları şunlardı:
- Aynı hata farklı ekranlarda farklı mesajlarla gösteriliyordu.
- Bazı ekranlar backend mesajını kullanırken bazıları teknik exception metnini sızdırıyordu.
- Bağlantı ve sunucu hataları birbirine karışıyordu.
- Global olarak gösterilen bir hata, özellik ekranında ikinci kez gösterilebiliyordu.
- Model ayrıştırma hataları sıradan kullanıcı hatası gibi ele alınıyor ve teknik ekibe yeterli bağlam ulaşmıyordu.
- Yeni bir modül eklendiğinde aynı hata eşleme mantığı tekrar yazılıyordu.
Sağlık uygulamasında bu yalnızca görsel tutarsızlık değildir. Kullanıcı bir sağlık kaydını, randevuyu veya ölçümü gönderdiğinde işlemin tamamlanıp tamamlanmadığını doğru anlamalıdır. Mesajın tonu kadar verdiği yönlendirme de güvenin parçasıdır.
Hedef
Amaç bütün hataları aynı mesaja çevirmek değildi. Tam tersine, teknik ayrıntıyı merkezi olarak doğru sınıflandırıp her senaryoya uygun bir ürün davranışı üretmekti.
Kurulan sistemin şu özelliklere sahip olması gerekiyordu:
- HTTP ve istemci kaynaklı hataları tip güvenli biçimde ayırmak,
- Backend’in anlamlı iş mesajını mümkün olduğunda korumak,
- Teknik exception metinlerini son kullanıcıdan gizlemek,
- Çevrimdışı, zaman aşımı ve sunucu hatalarında doğru yönlendirmeyi göstermek,
- Global aksiyon gerektiren hataları özellik ekranlarından bağımsız yönetmek,
- Teknik detayları hata takibine taşırken arayüze sade bir mesaj vermek,
- Tüm modüllerde aynı kullanım biçimini sağlamak.
Hata yaşam döngüsü
Hata yönetimi tek bir yardımcı fonksiyona sıkıştırılmadı. Her katmanın kendi sorumluluğunu taşıdığı bir dönüşüm zinciri kuruldu:
Dio / HTTP hatası
↓
Tip güvenli ağ hatası
↓
Backend sonucu veya ortak mesaj eşlemesi
↓
ServiceMessageResult
↓
Cubit failure durumu
↓
Toast, ekran içi hata veya global aksiyon
Ağ katmanı ham exception’ı sınıflandırıyor. Repository sonucu Either olarak özellik katmanına
taşıyor. Ortak hata eşleyici teknik hatayı kullanıcı mesajına dönüştürüyor. Cubit bu mesajı
başarısızlık durumuna ekliyor; ekran ise mesajın nasıl sunulacağına karar veriyor.
Bu ayrım sayesinde arayüzün DioException, HTTP kodu veya response gövdesi bilmesine gerek kalmıyor.
Ağ katmanı da hangi ekranda dialog, toast veya tam sayfa hata gösterileceğini belirlemiyor.
Tip güvenli ağ hataları
Ham exception’ları doğrudan özelliklere taşımak yerine bütün sonuçlar ortak ağ hata modeli altında sınıflandırılıyor. Model yalnızca HTTP 400 veya 500 ayrımını değil, taşıma ve veri katmanındaki hataları da kapsıyor:
- 3xx yönlendirme cevapları,
- 4xx istemci ve iş kuralı cevapları,
- 5xx sunucu hataları,
- Bağlantı, gönderme ve yanıt zaman aşımı,
- Sertifika ve bağlantı hataları,
- İptal edilen istekler,
- İnternet bağlantısının bulunmaması,
- Boş veya beklenmeyen yanıt,
- Format ve model ayrıştırma hataları,
- Sınıflandırılamayan beklenmeyen hatalar.
Her özellik isterse belirli bir hata türü için özel davranış tanımlayabiliyor. Özel davranış yoksa ortak varsayılan devreye giriyor. Böylece istisnai ürün ihtiyaçları desteklenirken standart hata yönetimi delinmiyor.
Backend mesajı ile uygulama mesajının dengesi
Backend yanıtları ortak bir servis zarfı içinde sonuç, cevap kodu, mesaj, mesaj türü ve hata durumu taşıyor. Geçerli bir iş mesajı geldiğinde bu bilgi kaybedilmiyor. Kullanıcı, örneğin seçtiği kaynağın artık kullanılabilir olmaması gibi iş alanına özgü bir nedeni genel hata yerine doğrudan görebiliyor.
Backend mesajı bulunmadığında veya yanıt güvenli biçimde ayrıştırılamadığında uygulamanın yerelleştirilmiş varsayılan mesajları kullanılıyor. Mesaj sonuna eklenen kısa destek kodları, kullanıcı teknik detaylarla karşılaşmadan destek ekibinin hata sınıfını ayırt etmesini sağlıyor.
Bu yaklaşım iki uçtan da kaçınıyor:
- Her durumda yalnızca “Bir hata oluştu” diyerek anlamı kaybetmek,
- Backend veya kütüphane exception’ını olduğu gibi göstererek teknik ayrıntıyı kullanıcıya sızdırmak.
Kullanıcıya anlamlı mesaj üretmek
Teknik hata, arayüze ulaşmadan önce ortak bir ServiceMessageResult modeline dönüştürülüyor. Bu
model yalnızca metni değil, mesajın anlamını da taşıyor: başarı, bilgi, uyarı veya hata.
Örneğin:
- İnternet yoksa kullanıcıya bağlantısını kontrol etmesi gerektiğini söyleyen bir uyarı gösteriliyor.
- Yanıt zaman aşımında işlemin beklenen sürede tamamlanamadığı belirtiliyor; bağlantı yokmuş gibi davranılmıyor.
- Sunucu hatasında problemin hizmet tarafında olduğu anlatılıyor ve kullanıcı teknik detayla karşılaştırılmıyor.
- 404 durumunda kaynağın bulunamadığını temsil eden kontrollü mesaj kullanılıyor.
- Çok fazla istek gönderildiğinde backend mesajı okunabiliyorsa korunuyor, okunamıyorsa bu duruma özel yerel mesaj gösteriliyor.
- Model ayrıştırma hatasında üretimde güvenli genel mesaj kullanılırken teknik ayrıntı hata takip sistemine aktarılıyor; geliştirme ortamında ayrıştırma noktası daha görünür hale getiriliyor.
- İstek kullanıcı tarafından iptal edildiyse hata mesajı gösterilmiyor.
Global ve yerel hata ayrımı
Bazı hatalar yalnızca açık olan özelliği ilgilendirir. Örneğin bir indirim kodunun geçersiz olması sepet ekranının kendi durumudur. Bazı hatalarsa uygulamanın tamamını etkiler: internet bağlantısının olmaması, sunucuya erişilememesi veya oturumun geçersiz hale gelmesi gibi.
Ortak hata katmanı global mesajı kendisi gösterdiğinde sonucu “global olarak gösterildi” bilgisiyle işaretliyor. Özellik ekranındaki mesaj bileşeni bu alanı kontrol ederek aynı bildirimi yeniden göstermiyor. Böylece tek bir ağ hatasının hem global toast hem ekran hatası hem de ikinci bir toast üretmesi engelleniyor.
Yerel hatalarda ise Cubit, mesajı kendi failure durumuna taşıyor. Ekran bu sonucu akışa göre toast,
dialog veya içerik alanında hata görünümü olarak sunabiliyor. Hata metni ortak kalsa da sunum biçimi
ürün bağlamına uyarlanabiliyor.
Oturum ve yetki hataları
401 yanıtı yalnızca ekranda “Yetkisiz” göstermekle çözülemez. Kullanıcının aktif oturumu varsa token yenileme akışı çalışıyor ve istek kontrollü biçimde tekrar deneniyor. Yenileme başarısız olduğunda uygulama mevcut rotayı da dikkate alarak güvenli çıkış sürecini başlatıyor.
Aynı anda birden fazla isteğin 401 dönmesi halinde her birinin ayrı ayrı çıkış işlemi başlatması yarış durumuna yol açabilirdi. Bu nedenle oturum sonlandırma kritik bölümü kilit altında çalışıyor; tek bir akış kullanıcı durumunu temizliyor.
Bazı yetki hatalarıysa oturumla değil, kullanıcının başka bir kişi adına işlem yapma kapsamıyla ilgili. Böyle bir durumda servis mesajı dialog içinde gösteriliyor ve kullanıcı geçerli bir başlangıç noktasına yönlendiriliyor. Yani aynı 4xx ailesi içinde bile ürün davranışı hata anlamına göre değişiyor.
Sessizce ele alınması gereken durumlar
İyi hata yönetimi her exception için mesaj göstermek değildir.
Kullanıcı ekrandan ayrıldığı için iptal edilen ağ isteği normal yaşam döngüsünün parçasıdır ve sessizce sonlandırılır. Artık var olmayan bir kaynağın belirli akışlarda 410 dönmesi de kullanıcıya yeni bir hata üretmeden mevcut durumun yenilenmesiyle ele alınabilir. Benzer biçimde, zaten global olarak gösterilen hata yerel katmanda tekrar açılmaz.
Bu ayrım arayüzdeki hata gürültüsünü azalttı. Kullanıcı yalnızca aksiyonunu veya beklentisini değiştirmesi gereken durumlarda mesaj görüyor.
Yerelleştirme ve destek kodları
İstemci tarafından üretilen bütün kullanıcı mesajları çeviri sistemi üzerinden geliyor. Böylece bağlantı, zaman aşımı ve genel sunucu mesajları desteklenen dillerde aynı anlamı koruyor; özellikler kendi içinde sabit metin üretmiyor.
Ortak mesajlara eklenen kısa hata kodları iki amaca hizmet ediyor. Kullanıcı destek ekibine uzun bir teknik açıklama yapmak zorunda kalmıyor; “FL002 kodunu görüyorum” demesi yeterli olabiliyor. Ekip de bu kod üzerinden sorunun zaman aşımı, bağlantı veya genel istemci hatası olduğunu hızla daraltabiliyor.
Geliştirici yetkisine sahip kullanıcılar için mesaj bileşeni ağ hata detayını kopyalanabilir biçimde sunabiliyor. Bu teknik kolaylık normal kullanıcı deneyimine veya üretim mesajına yansımıyor.
Özellik modüllerinde kullanım
Ortak altyapı; randevu, sağlık bilgileri, dosyalar, reçeteler, hatırlatıcılar, mağaza ve cihazlar gibi çok sayıda modül tarafından aynı şekilde kullanılıyor. Repository çağrısı başarı ve hata olmak üzere iki açık sonuç üretiyor. Cubit başarıda veriyi, hatada normalize edilmiş kullanıcı mesajını state’e taşıyor.
Bu düzenin önemli tarafı kod kısalığı değil, kararların tek yerde verilmesi. Yeni bir modül bağlantı hatasının hangi metne çevrileceğini, 5xx mesajının daha önce gösterilip gösterilmediğini veya parse hatasının raporlanıp raporlanmayacağını yeniden çözmek zorunda kalmıyor.
Gözlemlenebilirlik ile bağlantısı
Kullanıcı mesajı üretmek ve teknik hatayı incelemek aynı akışın iki farklı çıktısı olarak tasarlandı. Dio, model ayrıştırma ve beklenmeyen istemci hataları ortak hata facade’ine gönderiliyor. Bu kayıtlar oturum, ekran ve ağ zaman çizelgesiyle birleştirilebildiği için kullanıcıya sade mesaj gösterilirken teknik ekip ayrıntılı neden analizi yapabiliyor.
Örneğin kullanıcı yalnızca “Sunucuya şu anda ulaşılamıyor” mesajını görür. Hata kaydında ise isteğin adresi, süresi, yanıt durumu, aktif ekran, çağrıyı yapan akış ve stack trace bulunabilir. Kullanıcı deneyimi ile hata ayıklama ihtiyacı birbirine karşıt hedefler olmaktan çıkıyor.
Sonuç
Merkezi hata yönetimi, ağ katmanındaki teknik çeşitliliği kullanıcı arayüzünde tutarlı bir ürün diline dönüştürdü. Bağlantı kesintisi, zaman aşımı, sunucu problemi, iş kuralı hatası ve istemci veri hatası artık aynı “bir şeyler ters gitti” mesajının arkasında kaybolmuyor.
Özellik ekipleri HTTP ve Dio ayrıntıları yerine kendi başarılı ve başarısız durumlarına odaklanabilir hale geldi. Global hata davranışları tek noktadan yönetildi, tekrarlanan bildirimler azaldı ve destek ekibinin kullanıcıdan aldığı kısa hata kodları teknik incelemeyi hızlandıran ortak bir dile dönüştü.
Öğrendiklerim
- Her teknik hata kullanıcı hatası değildir. İptal edilen veya yaşam döngüsü nedeniyle sona eren istekler sessizce ele alınmalıdır.
- Anlamlı mesaj doğru sorumluyu işaret eder. Bağlantı hatasında kullanıcıya, sunucu hatasında sisteme yönelik bir açıklama verilmelidir.
- Backend mesajı değerlidir fakat güvenli bir varsayılan şarttır. Mesaj ayrıştırılamadığında ürün dili bozulmamalıdır.
- Global ve yerel gösterim ayrılmalıdır. Aynı hatanın birden fazla bileşende görünmesi açıklık değil, gürültü üretir.
- Tip güvenli sonuçlar hata akışını görünür kılar.
Eithertabanlı sözleşme başarı ve başarısızlığın özellik katmanında bilinçli biçimde ele alınmasını sağlar. - Kullanıcı mesajı ile tanılama kaydı farklı çıktılardır. Teknik ayrıntıyı kullanıcıdan saklamak, geliştirme ekibinden de saklamak anlamına gelmemelidir.
- Hata kodları destek ile mühendislik arasında köprü kurar. Kısa ve kararlı bir referans, belirsiz ekran görüntülerinden daha kullanışlıdır.