İçeriğe Atla
Mustafa Erbay
Rehberler · 11 dk okuma · görüntülenme Read in English

Mobil Uygulamalarda Offline-First Senkronizasyon Stratejileri

Mobil uygulamalarınızda veri senkronizasyonu, offline çalışma ve performans optimizasyonu için derinlemesine stratejiler ve pratik yaklaşımlar.

100%

Mobil Uygulamalarda Veri Senkronizasyonunun Önemi

Mobil uygulamalar artık sadece online olduğumuzda kullandığımız araçlar değil. Kullanıcılar, internet bağlantısı zayıf veya hiç olmayan ortamlarda bile uygulamalarından tam performans bekliyorlar. İşte bu noktada, mobil uygulamalarda offline-first senkronizasyon stratejileri devreye giriyor. Sahada internetin olmadığı durumlar için veri tutarlılığını sağlamak kritiktir. Bu tür senaryolar, kullanıcı deneyimini doğrudan etkiliyor ve uygulamanın güvenilirliğini belirliyor.

Offline-first mimarisi, verilerin öncelikle cihaz üzerinde saklanmasını ve ardından uygun olduğunda sunucu ile senkronize edilmesini savunur. Bu, sadece kullanıcı deneyimini iyileştirmekle kalmaz, aynı zamanda veri kaybı riskini de azaltır. Özellikle finansal işlemler, envanter takibi veya saha servis raporları gibi kritik verilerde, bu yaklaşım vazgeçilmezdir. Bu stratejileri doğru uygulamak, uygulamanızın kullanıcılar nezdindeki değerini artıracaktır.

Temel Offline-First Senkronizasyon Modelleri

Offline-first mimarisini hayata geçirmenin birkaç temel yolu var. Hangi modeli seçeceğiniz, uygulamanızın karmaşıklığına, veri yapısına ve senkronizasyonun ne kadar sık ve ne kadar güncel olması gerektiğine bağlıdır. Genellikle karşımıza çıkan iki ana model:

  1. Tek Yönlü Senkronizasyon (Client-to-Server): Bu modelde, cihazdaki değişiklikler sunucuya gönderilir, ancak sunucudaki değişiklikler cihaza geri gelmez veya belirli aralıklarla manuel olarak çekilir. Basit görev listeleri veya not alma uygulamaları gibi tekil veri akışının olduğu yerlerde işe yarayabilir. Ancak günümüzdeki çoğu mobil uygulama için yeterli değildir.

  2. Çift Yönlü Senkronizasyon (Bi-directional Synchronization): Bu, en yaygın ve en karmaşık modeldir. Hem cihazdaki hem de sunucudaki değişiklikler birbirine senkronize edilir. Bu, birden fazla cihazın aynı veriye eriştiği veya verilerin hem online hem de offline olarak düzenlenebildiği durumlar için idealdir. Bir üretim bandındaki operatör ekranları ile merkezi ERP sistemi arasındaki veri akışını düşünün; çift yönlü senkronizasyon burada şart.

Bu modellerin her birinin kendine göre avantajları ve dezavantajları var. Tek yönlü senkronizasyon daha basit bir yapı sunarken, çift yönlü senkronizasyon veri çakışmalarını yönetme gibi ek zorlukları beraberinde getirir.

Tek Yönlü Senkronizasyon: Basitlik ve Hız

Tek yönlü senkronizasyon, adından da anlaşılacağı gibi, verinin tek bir yönde hareket ettiği bir senaryoyu ifade eder. En basit haliyle, mobil cihazınızda yaptığınız değişiklikler yalnızca sunucuya iletilir. Örneğin, bir mobil uygulamada bir görevi tamamladığınızı işaretlediğinizde, bu bilgi sunucuya gönderilir. Sunucudaki veritabanında bir güncelleme olduğunda, bu mobil cihaza otomatik olarak yansımaz.

Bu yaklaşımın en büyük avantajı basitliğidir. Uygulama geliştirme süreci daha az karmaşık hale gelir çünkü veri çakışması senaryolarını yönetmeniz gerekmez. Ayrıca, sadece sunucuya veri gönderdiğiniz için ağ trafiği de daha az olabilir. Örneğin bir spam engelleyici uygulamada, engellenen numaralar listesini sadece cihaza kaydedip, merkezi bir kara listeyi sadece okuma modunda kullanmak gibi bir senaryo düşünebilirsiniz. Ancak bu, verilerin tutarlı kalmasını sağlamak için yeterli olmayabilir.

Sunucu tarafında bir veri değişikliği olduğunda, mobil cihazın bu değişikliği nasıl alacağı konusunda ek bir mekanizma gerekebilir. Bu genellikle periyodik olarak sunucuyu sorgulama veya kullanıcıdan manuel olarak “senkronize et” komutu bekleme şeklinde olur. Bu durum, gerçek zamanlı veri güncelliği gerektiren uygulamalar için kabul edilemez olabilir.

Çift Yönlü Senkronizasyon: Karmaşıklık ve Tutarlılık

Çift yönlü senkronizasyon, mobil uygulamalarda en çok ihtiyaç duyulan ve en çok karşılaşılan senaryodur. Bu modelde, hem cihaz hem de sunucu üzerindeki veriler birbirine uyumlu hale getirilir. Bir kullanıcı mobil cihazında bir kaydı güncellediğinde, bu değişiklik sunucuya gönderilir. Aynı zamanda, başka bir kullanıcı veya bir arka plan süreci tarafından sunucuda yapılan değişiklikler de mobil cihaza senkronize edilir.

Bu yaklaşımın en büyük zorluğu, veri çakışmalarını (conflicts) yönetmektir. İki farklı yerden aynı veri üzerinde yapılan ve birbiriyle çelişen değişiklikler olduğunda ne yapılacağı sorusu kritik önem taşır. Örneğin, bir siparişin durumunu hem mobil uygulamadan “Tamamlandı” olarak işaretlediniz, hem de aynı anda web arayüzünden “İptal Edildi” olarak değiştirdiniz. Bu durumda hangi değişikliğin geçerli olacağına karar verilmesi gerekir.

Veri Çakışmalarını Yönetme Stratejileri

Çakışmaları yönetmek için çeşitli stratejiler mevcuttur:

  • Son Yazma Kazanır (Last Write Wins - LWW): En basit stratejilerden biridir. Hangi değişikliğin daha sonra yapıldığına bakılır ve o değişiklik geçerli sayılır. Bu stratejinin dezavantajı, bir değişikliğin diğerini tamamen yok edebilmesidir. Bir üretim planlama modülünde, operatörün girdiği verinin, merkezi sistemden gelen planla üzerine yazılması istenmeyen sonuçlar doğurabilir. Timestamp’ler bu stratejinin temelini oluşturur.
  • İlk Yazma Kazanır (First Write Wins - FWW): LWW’nin tersidir. Hangi değişikliğin önce yapıldığına bakılır ve o değişiklik geçerli sayılır. Bu da LWW kadar veri kaybına yol açabilir.
  • Birlikte Yaşatma / Kullanıcıya Sorma: Bu stratejide, çakışma durumunda sistem otomatik bir karar vermez. Bunun yerine, kullanıcıya her iki değişikliği de sunar ve hangisinin geçerli olacağına kendisinin karar vermesini ister. Bu, kullanıcı deneyimini karmaşıklaştırabilir ancak veri bütünlüğü açısından en güvenli yollardan biridir. Bir maliyet hesaplayıcısında, manuel girilen bir değer ile sistem tarafından hesaplanan değer arasındaki çakışmada kullanıcıya sormak mantıklı olabilir.
  • Çakışma Çözümleyici Mantığı (Conflict Resolution Logic): Uygulamanızın iş mantığına özel çözümler geliştirebilirsiniz. Örneğin, bir sipariş durumunda “iptal” işlemi “tamamlandı” işlemine her zaman öncelik verebilir veya bir envanter sayımında, manuel girilen sayım değeri, sistemdeki stoktan daha öncelikli kabul edilebilir.

Çakışma yönetimi, çift yönlü senkronizasyonun en kritik ve en zorlu parçasıdır. PostgreSQL gibi veritabanlarında, MVCC (Multi-Version Concurrency Control) mekanizmaları bu tür durumları yönetmeye yardımcı olsa da, uygulama seviyesinde de ek mantıklar geliştirmeniz gerekebilir.

Senkronizasyon Mekanizmaları ve Veri Modelleri

Offline-first senkronizasyonunu destekleyen temel veri modelleri ve mekanizmalar vardır. Bunlar, verinin nasıl saklandığını, güncellemelerin nasıl izlendiğini ve sunucu ile nasıl iletişim kurulduğunu belirler.

Yerel Veritabanı Seçimi

Mobil cihazlarda veriyi saklamak için genellikle yerel veritabanları kullanılır. Bu veritabanları, senkronizasyon için gerekli olan bilgileri (örneğin, değişikliklerin ne zaman yapıldığı, hangi verinin değiştiği) tutabilmelidir.

  • SQLite: Mobil platformlarda en yaygın kullanılan yerel veritabanıdır. Hafif, hızlı ve platformlar arası desteğe sahiptir. Ancak, karmaşık senkronizasyon mantığını doğrudan desteklemez, bu nedenle ek bir katman gerektirir.
  • Realm: Mobil cihazlar için özel olarak tasarlanmış bir veritabanıdır. Gerçek zamanlı senkronizasyon yetenekleri sunar ve SQLite’a göre daha gelişmiş özelliklere sahip olabilir. Kendi “Realm Sync” servisi ile çift yönlü senkronizasyonu kolaylaştırır.
  • Diğerleri: Couchbase Lite, PouchDB gibi NoSQL tabanlı çözümler de offline-first ve senkronizasyon ihtiyaçları için tercih edilebilir. Özellikle büyük veri setleri ve esnek şemalar söz konusu olduğunda avantajlıdırlar.

Pratikte sık işe yarayan bir desen şudur: veri modeli olarak SQLite kullanıp, her bir tablo için değişiklikleri izlemek amacıyla last_modified gibi timestamp kolonları ve bir sync_status (pending, synced, failed) alanı eklemek. Bu, verinin sunucuya gönderilip gönderilmediğini takip etmenizi sağlar.

Değişiklik İzleme (Change Tracking)

Senkronizasyonun temelinde, hangi verilerin değiştiğini bilmek yatar. Bunun için birkaç yöntem kullanılır:

  • Timestamp Tabanlı İzleme: Her kayıt için bir created_at ve updated_at timestamp’i tutulur. Senkronizasyon sırasında, en son ne zaman senkronize edildiğini bilen istemci, sunucuya bu tarihten sonra değişen tüm kayıtları sorar. Sunucu da aynı mantıkla değişiklikleri gönderir. Bu yöntem basit olsa da, zaman dilimi sorunları veya saat senkronizasyon hataları nedeniyle çakışmalara yol açabilir.
  • Versiyon Numaraları: Her kayıt için bir versiyon numarası tutulur. Her güncellemede versiyon numarası artırılır. Bu, LWW veya FWW gibi stratejilerde daha kesin bir sıralama sağlar. PostgreSQL’in xmin gibi sistem kolonları da bu tür versiyonlama bilgilerini barındırabilir.
  • Değişiklik Kayıtları (Change Logs / Journals): Veritabanı veya uygulama seviyesinde yapılan tüm değişikliklerin kaydedildiği ayrı bir tablo veya yapı kullanılır. Bu kayıtlar, hangi verinin ne zaman ve nasıl değiştiğini detaylı olarak içerir. Bu, en kapsamlı izleme yöntemidir ve karmaşık çakışma çözümlerini destekler.

Timestamp tabanlı basit bir yaklaşım, cihaz saatleri farklılık gösterdiğinde senkronizasyonda ufak tefek tutarsızlıklara yol açabilir. Bu tür durumlarda, versiyon numaraları veya daha gelişmiş bir değişiklik kayıt sistemi daha sağlam bir çözüm sunar.

Senkronizasyon Protokolleri ve Ağ İletişimi

Verilerin cihaz ve sunucu arasında nasıl iletileceği, senkronizasyonun verimliliği ve güvenilirliği açısından büyük önem taşır.

HTTP/REST vs. WebSocket

Senkronizasyon için en yaygın kullanılan iletişim protokolleri HTTP ve WebSocket’tir.

  • HTTP/REST: Geleneksel istek-cevap modelini kullanır. Mobil cihaz, sunucuya bir istek gönderir (örneğin, “bana son senkronizasyondan beri değişenleri gönder”) ve sunucu da bu isteğe bir yanıt verir. Bu, basit senaryolar için uygundur ancak sürekli olarak sunucuyu sorgulama (polling) gerektirebilir ki bu da pil tüketimini artırır ve ağ kaynaklarını verimsiz kullanır. REST API üzerinden yürüyen senkronizasyonlarda sürekli veri çekme ihtiyacı, özellikle düşük bant genişliğine sahip ağlarda performans sorunlarına yol açar.
  • WebSocket: Sürekli çift yönlü iletişim kanalı açar. Bu, sunucunun herhangi bir zamanda istemciye veri gönderebilmesini sağlar. Mobil uygulama, bağlantıyı açık tutar ve sunucudan gelen güncellemeleri gerçek zamanlı olarak alır. Bu, pil tüketimi açısından daha verimli olabilir ve daha iyi bir kullanıcı deneyimi sunar. Operatör ekranlarında gerçek zamanlı stok güncellemeleri gibi anlık veri gerektiren senaryolarda WebSocket, polling’e kıyasla belirgin bir fark yaratır.

Örneğin gerçek zamanlı döviz kuru güncellemeleri gerektiren bir uygulamada WebSocket tabanlı bir API, kullanıcıların kurlardaki anlık değişimleri kesintisiz olarak görmesini sağlar.

Veri Sıkıştırma ve Batch İşlemleri

Ağ trafiğini azaltmak ve senkronizasyon hızını artırmak için veri sıkıştırma ve toplu (batch) işlemler kritik öneme sahiptir.

  • Veri Sıkıştırma: Gönderilen verinin boyutunu küçültmek için Gzip gibi sıkıştırma algoritmaları kullanılabilir. Bu, özellikle mobil ağlarda veri kullanımını ve senkronizasyon süresini önemli ölçüde azaltır.
  • Batch İşlemleri: Tek tek kayıtlar yerine, birden fazla değişikliği tek bir istekte gruplayarak göndermek, ağ iletişiminin overhead’ini azaltır. Örneğin, 100 adet değişikliği tek bir batch isteğinde sunucuya göndermek, 100 ayrı istek göndermekten çok daha verimlidir.

Batch boyutu, senkronizasyon performansını ayarlamak için önemli bir koldur. Çok küçük batch’ler istek başına overhead’i artırırken, aşırı büyük batch’ler bellek ve sunucu yükü açısından sorun çıkarabilir; dengeli bir orta nokta genellikle ağ trafiği ve sunucu yükü açısından en iyi sonucu verir. Doğru değeri kendi veri ve ağ koşullarınızda ölçerek belirlemek en sağlıklısıdır.

Güvenlik ve Yetkilendirme

Offline-first senkronizasyonunda güvenlik, en az veri tutarlılığı kadar önemlidir. Cihazlar çevrimdışı olduğunda bile, verilerin yetkisiz erişime karşı korunması gerekir.

Yerel Veri Şifreleme

Mobil cihazda saklanan verilerin şifrelenmesi, cihazın fiziksel olarak ele geçirilmesi durumunda veri gizliliğini sağlamak için şarttır. Çoğu mobil işletim sistemi, disk şifreleme (full-disk encryption) sunar, ancak hassas veriler için uygulama seviyesinde ek şifreleme katmanları eklemek de iyi bir uygulamadır.

Örneğin, bir finansal hesaplayıcı uygulamasında kullanıcıların kişisel bilgilerini saklıyorsanız, bu bilgileri yerel veritabanına kaydetmeden önce AES gibi güçlü bir şifreleme algoritması ile şifrelemeniz gerekir.

Kimlik Doğrulama ve Yetkilendirme

Sunucu ile senkronizasyon yapılırken, istemcinin kimliğinin doğrulanması ve yalnızca yetkili olduğu verilere erişebildiğinden emin olunması gerekir.

  • Token Tabanlı Kimlik Doğrulama (JWT, OAuth2): Kullanıcı giriş yaptıktan sonra alınan bir token, sonraki tüm isteklerde kullanılır. Bu token, kullanıcının kimliğini ve izinlerini taşır. Sunucu, gelen token’ı doğrulayarak isteği işler.
  • API Anahtarları: Uygulamanın kendisi için bir API anahtarı kullanılarak, sunucu tarafında uygulamanın kimliği doğrulanabilir. Ancak bu, kullanıcı bazlı yetkilendirme için yeterli değildir.

Tipik bir kurulumda, mobil uygulamanın backend’inde JWT tabanlı bir kimlik doğrulama sistemi kullanılır: kullanıcılar giriş yaptıklarında bir erişim tokenı alır ve bu token senkronizasyon isteklerinde taşınır. FastAPI gibi çerçevelerle bu token doğrulama mekanizması kolayca uygulanabilir.

Gerçek Dünya Senaryoları ve Uygulama Örnekleri

Bu teorik bilgileri somutlaştırmak için birkaç gerçek dünya senaryosuna göz atalım.

Senaryo 1: Saha Servis Uygulaması

Bir saha servis teknisyeni, müşterinin yerinde bir arızayı gideriyor. İnternet bağlantısı yok. Teknisyen, mobil uygulamayı kullanarak arızayı kaydeder, yapılan işlemleri listeler ve yedek parça kullanımını işaretler. Uygulama, tüm bu verileri cihazdaki yerel veritabanına kaydeder. Teknisyen işini bitirip ofise döndüğünde veya internet bağlantısı kurulduğunda, uygulama otomatik olarak yerel verileri sunucuya senkronize eder. Bu senaryoda, çift yönlü senkronizasyon ve çakışma yönetimi (eğer aynı anda birden fazla teknisyen aynı müşteri kaydını güncellerse) önemlidir.

Senaryo 2: E-Ticaret Mobil Uygulaması

Bir kullanıcı, alışveriş sepetine ürünler ekler. İnternet bağlantısı kesilir. Kullanıcı, sepette değişiklikler yapmaya devam eder. Bağlantı geri geldiğinde, sepet bilgileri sunucu ile senkronize edilir. Bu senaryoda, tek yönlü veya çift yönlü senkronizasyon yeterli olabilir, ancak LWW veya daha gelişmiş çakışma çözümleme stratejileri, kullanıcının yaptığı değişikliklerin kaybolmamasını sağlamak için önemlidir.

Senaryo 3: Üretim Takip Sistemi

Bir üretim hattındaki operatör, kullandığı makinenin durumunu ve ürettiği parça sayısını mobil bir terminalden giriyor. Sistem, bu bilgileri anında merkezi ERP sistemine aktarmalıdır. Ancak operatörün bulunduğu alanda ağ bağlantısı stabil olmayabilir. Bu durumda, veri kaybını önlemek ve gerçek zamanlıya yakın takip sağlamak için hem güvenilir bir offline depolama hem de hızlı, çift yönlü senkronizasyon mekanizmaları gereklidir. Sunucu tarafında senkronizasyon servisleri systemd unit’leri ile yönetilebilir; PostgreSQL’deki WAL (Write-Ahead Logging) mekanizması da veri dayanıklılığını sağlamaya katkı sunar.

Sonuç ve Gelecek Adımlar

Mobil uygulamalarda offline-first senkronizasyon stratejileri, günümüzün bağlantılı dünyasında kullanıcı deneyimini en üst düzeye çıkarmak için vazgeçilmezdir. Doğru veri modeli, etkili çakışma yönetimi, güvenli iletişim protokolleri ve sağlam güvenlik önlemleri ile kullanıcılarınıza kesintisiz bir deneyim sunabilirsiniz.

Bu stratejileri uygularken, projenizin özel ihtiyaçlarını göz önünde bulundurarak en uygun çözümü seçmek önemlidir. Basit uygulamalar için tek yönlü senkronizasyon yeterli olabilirken, daha karmaşık veri etkileşimleri gerektiren durumlar için çift yönlü senkronizasyon ve gelişmiş çakışma çözme mekanizmaları kaçınılmazdır.

Bir sonraki adım olarak, uygulamanızın veri akışını analiz edin ve hangi senkronizasyon modelinin sizin için en uygun olduğuna karar verin. Ardından, seçtiğiniz modeli hayata geçirmek için gerekli teknik altyapıyı kurmaya başlayın.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

Sıkça Sorulanlar

Bu makale ile ilgili okurların sorduğu yaygın sorular.

Offline-first mimarisinde veri çakışmaları yaşadığınızda, çözmek için hangi stratejiyi uyguluyorsunuz ve bu, kullanıcı deneyimini nasıl etkiliyor?
Ben, üretim ERP sistemi üzerinde çalışırken, veri çakışmalarını çözmek için 'timestamp + kullanıcı onayı' stratejisini geliştirdim. Değişiklikler cihazda yerel olarak kaydedilir ve senkronizasyon anında sunucu ile karşılaştırılır. Eğer aynı veri üzerinde iki değişiklik varsa, daha yeni olan otomatik öncelik alır, ancak kritik alanlarda kullanıcıya 'Hangi sürümü kaydetmek istersiniz?' diye sorarım. Bu, veri tutarlılığını korurken kullanıcı kontrolünü de sağlıyor. İlk başlarda otomatik birleştirme denedim ama hatalı veri girişlerine yol açtı, bu yüzden insan onayı koyduk.
Cihazda veri saklamak için SQLite mi yoksa Firebase Offline Persistence mi tercih edersiniz, ve bu kararı hangi kriterlere göre veriyorsunuz?
Kişisel tecrübeme göre, veri yapısı karmaşıksa ve ilişkisel sorgular gerekiyorsa ben her zaman yerel SQLite kullanmayı tercih ediyorum. Özellikle envanter takibi gibi senaryolarda, cihazda JOIN ve filtreleme yapabilmek çok büyük fark yaratıyor. Firebase Offline Persistence ise basit yapılar için hızlı çözüm sunar ama bana göre çok esnek değil. ERP mobilde SQLite ile çalıştık, hem performans hem de kontrol açısından çok daha tatmin ediciydi. Ancak ekibin zamanı azsa, Firebase başlangıç için daha uygun olabilir.
Offline-first uygulamalarda, senkronizasyon başarısız olduğunda kullanıcıya nasıl geri bildirim veriyorsunuz ve arka planda yeniden deneme mantığını nasıl yapıl
Ben, kullanıcıya açıklayıcı ama korkutmayan mesajlar veriyorum: 'Veriler senkronize edilemedi, internete bağlandığınızda otomatik gönderilecek.' Ayrıca, işlem kuyruğunu cihazda saklıyorum ve arka planda 5 dakikada bir yeniden deniyorum. Üç başarısız deneme sonrasında kullanıcıya bildirim gönderiyorum. ERP projesinde, işçilerin rapor gönderdikten sonra 'Gönderildi' anlamaları çok önemliydi, bu yüzden kuyruk durumunu da uygulama içinde görselleştirdik. Böylece kullanıcı ne zaman neyin beklediğini görüyor.
Çoğu geliştirici 'offline-first, online-second' mantığını abartıyor mu, yoksa gerçekten bu kadar kritik mi?
Ben başta şüpheyle yaklaşmıştım ama sahada çalışan kullanıcıları izledikten sonra fikrim değişti. Özellikle üretim alanlarında internet sinyali kesintisi çok yaygın. Offline-first olmasaydı, kullanıcılar veri girmeyi erteler, sonra hatalı veri girerdi. Bu, benim için artık bir 'iyi olur' değil, zorunlu bir mimari karar. Ancak abartı da var: her uygulamaya gerek yok. Basit içerik görüntüleyiciler için çok maliyetli olabilir. Ama işlem kaydı, raporlama, envanter gibi alanlarda offline-first olmazsa uygulama güvenilmez sayılır.
ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Yorumlar

Sunucu Taraflı AI Moderasyon

Yorumlar sunucuda yapay zeka ile denetlenir ve kalıcı olarak saklanır.

?
0/2000

Sunucu taraflı AI denetim

✉️ Ücretsiz · Spam yok · İstediğin an çık

Yeni yazılardan haberdar olun

Yeni içerikler ve teknik notlar e-postanıza gelsin.

  • 📌
    Haftanın en iyisi Sadece okumaya değer tek yazı
  • 🔧
    Alet çantası Bu hafta kullandığım araçlar
  • 🧠
    Perde arkası Blog'a girmeyen notlar

Spam yapmıyoruz. İstediğiniz zaman ayrılabilirsiniz. · Sadece Umami (self-hosted, Google yok) ile takip.

Okuma İstatistikleriniz

0

Yazı Okundu

0dk

Okuma Süresi

0

Gün Serisi

-

Favori Kategori

İlgili Yazılar