İçeriğe Atla
Mustafa Erbay
Yaşam · 12 dk okuma · görüntülenme Read in English

Yan Projelerde Tekrar Denemeleri Yönetmenin 4 Akıllı Yolu

Kendi başınıza geliştirdiğiniz yan projelerde hatalardan ders çıkararak ilerlemenin pratik yollarını öğrenin. Mustafa Erbay'dan deneyim dolu bir rehber.

100%

Giriş: Kendi Projelerimin Gizli Öğretmenleri

Kendi başıma giriştiğim yan projeler, kariyerimin en büyük öğrenme alanları oldu. Genellikle büyük kurumsal projelerin gerektirdiği süreçlerden sıyrılıp, doğrudan teknolojiyle haşır neşir olabildiğim anlar bunlar. Ancak bu özgürlük, beraberinde belirli zorlukları da getiriyor. En belirginlerinden biri ise, özellikle hata durumlarında, tekrar denemeleri sistematik bir şekilde yönetebilmek. Geçtiğimiz on yılda, kendi finansal hesaplayıcımdan mobil spam engelleyicime kadar pek çok yan proje geliştirdim. Bu süreçte edindiğim tecrübelerle, hatalardan ders çıkarıp ilerlemeyi sağlayan dört temel stratejiyi oturtmaya çalıştım. Bu yazıda, bu stratejileri ve gerçek hayattan örneklerle nasıl uyguladığımı anlatacağım.

Bu yan projeler, benim için sadece birer kod parçası değil, aynı zamanda sürekli bir gelişim platformu. Bir üretim ERP’si geliştirirken veya bir bankanın iç platformunda çalışırken edindiğim kurumsal tecrübelerin yanı sıra, bu kişisel projeler, farklı bakış açıları ve deneysel yaklaşımlar kazanmamı sağlıyor. Örneğin, kendi VPS’imde çalışan özel finansal hesaplayıcılarımda yaptığım optimizasyonlar, bazen ana projelerdeki veritabanı performans sorunlarına bile ışık tutabiliyor. Bu makalede, bu “gizli öğretmenlerimin” bana öğrettiği, tekrar denemeleri nasıl daha akıllıca yönetebileceğime dair düşüncelerimi paylaşacağım.

1. Hata Kaydını Otomatikleştir: Journald ve Loglama Stratejileri

Yan projelerde en çok karşılaştığım sorunlardan biri, hataların neden meydana geldiğini anlamak için yeterli veriye sahip olmamamdı. Özellikle bir kerelik çalışan script’lerde veya anlık çalışan servislerde, hatanın oluştuğu anda sistemde neler olup bittiğini anlamak kritik önem taşıyor. Bu noktada, uzun süredir SystemD kullanan Linux sistemlerimde journald’in gücünden faydalanmaya başladım.

Journald, sadece logları toplamakla kalmıyor, aynı zamanda loglama seviyelerini ve oran sınırlamalarını da yönetebiliyor. Kendi yan projelerim için genellikle şu stratejiyi izliyorum: Kritik hatalar için syslog’a veya özel bir dosyaya yüksek detaylı loglama yaparken, rutin operasyonel logları daha özet tutuyorum. Bu, disk alanından tasarruf etmemi sağlarken, hata anında gerekli tüm bilgiyi de elde etmeme olanak tanıyor. Örneğin, bir seferlik çalışan bir veri çekme script’im vardı. Bu script, belirli bir API’den veri çekerken ara sıra HTTP 500 Internal Server Error alıyordu. İlk başta hatayı anlamak için script’in içine print() komutları ekleyerek debugging yapmaya çalıştım. Ancak bu hem yavaştı hem de hatanın oluştuğu anı tam olarak yakalamak zordu.

Journald’in sunduğu rate limiting özelliği de burada devreye giriyor. Özellikle yoğun çalışan servislerde, aynı hatanın defalarca loglanması hem disk alanını doldurabilir hem de logları okunaksız hale getirebilir. SystemD unit dosyalarına eklediğim RateLimitIntervalSec ve RateLimitBurst gibi parametrelerle, belirli bir zaman diliminde aynı kaynaktan gelen log sayısını sınırlayabiliyorum. Bu, özellikle aynı 429 Too Many Requests türünden hataların sürekli tekrarlandığı durumları analiz ederken işe yarıyor. Hataların nedenini anlamak için ilk adım, hatayı ne kadar detaylı ve ne kadar verimli bir şekilde kaydedebildiğimizi otomatikleştirmek. Bu, sadece hatayı tespit etmekle kalmıyor, aynı zamanda hatanın kök nedenini bulma sürecini de hızlandırıyor.

2. Tekrar Deneme Mekanizmaları: İdeal Bekleme Süresi ve Üstel Geri Çekilme (Exponential Backoff)

Bir hata oluştuğunda, ilk aklıma gelen şeylerden biri “biraz bekleyip tekrar denemek” oluyor. Ancak bu “biraz”ın ne kadar olması gerektiği, sistemin kararlılığı ve kullanıcı deneyimi açısından kritik. Özellikle ağ hataları veya geçici servis kesintileri gibi durumlarda, hemen tekrar denemek yerine akıllıca bir bekleme stratejisi izlemek gerekiyor. Burada devreye giren temel konseptlerden biri “üstel geri çekilme” yani exponential backoff.

Yan projelerimde, özellikle harici API’lere veya servislere erişim sağlayan kodlarımda bu mekanizmayı sıkça kullanırım. Örneğin, kendi finansal hesaplayıcı projemde, bir veri sağlayıcının API’sine bağlanırken ara sıra ağ bağlantı sorunları yaşıyordum. İlk denemede hata aldığımda, hemen bir sonraki saniyede tekrar denemek yerine, 1 saniye bekleyip tekrar deniyordum. Eğer yine hata alırsam, bekleme süresini ikiye katlayarak 2 saniye, sonra 4 saniye, 8 saniye gibi artırarak devam ediyordum. Bu stratejinin en büyük avantajı, hem hedef servise aşırı yük bindirmemek hem de geçici bir sorunun düzelmesi için makul bir zaman tanımak.

Bu stratejiyi uygularken dikkat ettiğim bir diğer nokta ise maksimum tekrar deneme sayısı ve toplam bekleme süresi. Sonsuz bir döngüye girmek istemem. Genellikle 3 ila 5 tekrar deneme yeterli oluyor. Eğer bu denemeler sonunda hala hata alıyorsam, bu artık geçici bir sorun olmaktan çıkmış demektir ve sorunu manuel olarak incelemem gerektiğini anlarım. Bu konudaki bir başka önemli parametre ise “jitter” eklemek. Yani, bekleme süresini tam olarak hesaplamak yerine, hesaplanan süreye küçük bir rastgelelik eklemek. Bu, birden çok istemcinin aynı anda hata alıp aynı anda tekrar denemesini engelleyerek “thundering herd” problemini önlemeye yardımcı olur.

Astro’nun fetch API’sini kullanarak yaptığım bir örnekte, bu stratejiyi nasıl uyguladığımı görebilirsiniz:

async function fetchDataWithRetry(url, maxRetries = 3, initialDelay = 1000) {
  let delay = initialDelay;
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url);
      if (!response.ok) {
        // Hata durumunda tekrar deneme mantığı
        if (response.status >= 500 && response.status < 600) {
          console.warn(`Request failed with status ${response.status}. Retrying in ${delay}ms...`);
          await new Promise(resolve => setTimeout(resolve, delay));
          delay *= 2; // Exponential backoff
          // Jitter ekle
          delay += Math.random() * initialDelay;
        } else {
          // Client errors or other non-retryable errors
          throw new Error(`HTTP error! status: ${response.status}`);
        }
      } else {
        // Başarılı olursa veriyi döndür
        return await response.json();
      }
    } catch (error) {
      console.error(`Attempt ${i + 1} failed: ${error.message}`);
      if (i === maxRetries - 1) {
        throw error; // Son deneme ise hatayı fırlat
      }
      await new Promise(resolve => setTimeout(resolve, delay));
      delay *= 2;
      delay += Math.random() * initialDelay;
    }
  }
}

// Kullanım örneği:
// fetchDataWithRetry('https://api.example.com/data')
//   .then(data => console.log('Data received:', data))
//   .catch(error => console.error('Failed to fetch data after multiple retries:', error));

Bu kod parçası, harici bir servisten veri çekerken olası ağ sorunlarını ele almak için üstel geri çekilme ve jitter mekanizmalarını içeriyor. Bu tür basit ama etkili stratejiler, yan projelerimin daha kararlı çalışmasını sağlıyor.

3. Durum Yönetimi ve İdempotency: Tekrar Denemelerin Yan Etkileri

Tekrar deneme mekanizmalarını uygularken göz ardı edilmemesi gereken en önemli konulardan biri, yapılan işlemin “idempotent” olup olmadığıdır. İdempotency, bir işlemin birden çok kez uygulanmasının, tek bir kez uygulanmasıyla aynı sonucu doğurması anlamına gelir. Eğer yaptığınız işlem idempotent değilse, tekrar denemeler beklenmedik ve istenmeyen yan etkilere yol açabilir.

Örneğin, bir kullanıcıya e-posta gönderen bir fonksiyon düşünelim. Eğer bu fonksiyon idempotent değilse ve ağ hatası nedeniyle tekrar denenirse, kullanıcıya aynı e-postayı iki kez gönderebilir. Bu, kullanıcı deneyimi açısından oldukça rahatsız edici bir durumdur. Kendi projelerimde, özellikle finansal işlemler veya veri güncellemeleri gibi hassas operasyonlarda idempotency’yi sağlamak için çeşitli yöntemler kullanıyorum.

Bir yöntem, her işlem için benzersiz bir işlem kimliği (transaction ID) kullanmaktır. Bir istek gönderdiğimde, bu kimliği de istekle birlikte gönderirim. Sunucu tarafında, bu kimliği kontrol ederek işlemin daha önce gerçekleştirilip gerçekleştirilmediğini anlar ve eğer gerçekleştirilmişse, aynı işlemi tekrar yapmaz. Örneğin, kendi Android spam engelleyici uygulamamda, bir numarayı engelleme isteği gönderirken, her engelleme isteği için benzersiz bir UUID oluşturur ve bunu sunucuya gönderirdim. Sunucu, bu UUID’yi daha önce görmüşse, aynı numarayı tekrar engelleme komutunu işleme almazdı. Bu, uygulamanın kararlılığını artırdı ve çift engelleme gibi durumların önüne geçti.

Bir diğer yaklaşım ise, işlemin kendisini idempotent hale getirmektir. Örneğin, bir değeri arttırmak yerine, değeri doğrudan belirli bir değere ayarlamak (SET operasyonu gibi) daha idempotent bir yaklaşımdır. Veya, bir öğeyi silmek yerine, öğenin “silindi” olarak işaretlenmesini sağlamak. Bu tür yaklaşımlar, tekrar denemelerin güvenli bir şekilde yapılabilmesine olanak tanır. PostgreSQL gibi veritabanlarında INSERT ... ON CONFLICT DO NOTHING veya UPSERT gibi özellikler de bu konuda bize yardımcı olabilir.

Bu konuda, “transaction outbox” deseni de oldukça kullanışlıdır. Bir işlemi veritabanına kaydederken, aynı zamanda bu işlemin gerçekleştirileceği mesajı da bir “outbox” tablosuna yazarız. Daha sonra ayrı bir servis bu outbox’tan mesajları okuyarak dış servislere gönderir. Bu sayede, veritabanı işlemi başarılı olur ancak dış servis mesajı alınamazsa, mesaj tekrar gönderilebilir. Bu, iki aşamalı commit’in (two-phase commit) daha basit ve daha güvenilir bir alternatifidir.

4. Öğrenme Döngüsü Oluşturma: Hatalardan Ders Çıkarma ve Dokümantasyon

Yan projelerimin en değerli yanlarından biri, hatalardan ders çıkarma ve bu dersleri kalıcı hale getirme becerisidir. Sadece hatayı çözmek yeterli değil; neden olduğunu anlamak, gelecekte benzer hataların önüne geçmek için gerekli adımları atmak ve bu bilgiyi organize etmek uzun vadede büyük fark yaratır. Bu, bir nevi kendi kişisel “post-mortem” analizimi yapmaktır.

Benim için bu öğrenme döngüsünün ilk adımı, yukarıda bahsettiğim gibi detaylı loglama ve tekrar deneme mekanizmalarını kurmak. Ancak bundan sonra gelen adım, bu logları ve hata durumlarını analiz etmek. Kendi yan projelerimde genellikle basit bir Markdown dosyası veya bir Notion sayfası kullanarak “Hata Günlüğü” tutarım. Bu günlüğe, karşılaştığım sorunu, hatanın ne zaman ve nerede oluştuğunu, sorunu çözmek için attığım adımları ve en önemlisi, bu hatadan çıkardığım dersleri yazarım.

Örneğin, kendi finansal hesaplayıcı projelerimde PostgreSQL’in WAL (Write-Ahead Logging) dosyalarının şişmesi gibi bir sorunla karşılaştığımda, bu durumu detaylıca kaydettim. pg_wal dizininin boyutunun beklenmedik biçimde büyüyüp disk alanını doldurduğunu belirttim. Sorunu çözmek için pg_wal_keep_size parametresini ayarladığımı ve autovacuum ayarlarını optimize ettiğimi not aldım. Bu notlar, ileride benzer bir sorunla karşılaştığımda bana yol gösterecektir. Bu tür dokümantasyon, sadece bana değil, eğer bir gün projeyi başkasıyla paylaşacak olursam onlara da büyük fayda sağlar.

Bu öğrenme döngüsünü tamamlamak için bazen kodumda da iyileştirmeler yaparım. Örneğin, bir hata nedeniyle sürekli manuel müdahale gerekiyorsa, bu durumu otomatikleştirecek küçük bir script veya script değişikliği yapmaya çalışırım. Bu, sadece mevcut sorunu çözmekle kalmaz, aynı zamanda projenin genel güvenilirliğini de artırır. Kendi yan projelerimde, bu yaklaşım sayesinde zamanla daha sağlam ve daha az bakım gerektiren sistemler inşa edebildim.

Sonuç: Hatalar, Gelişimin Yakıtıdır

Yan projeler, kendi başımıza bir şeyler inşa etme ve deneme özgürlüğü sunar. Ancak bu denemeler sırasında hatalarla karşılaşmak kaçınılmazdır. Önemli olan bu hatalarla nasıl başa çıktığımızdır. Sistematik hata kaydı, akıllı tekrar deneme mekanizmaları, idempotency’nin sağlanması ve hatalardan ders çıkarma döngüsünün oluşturulması, bu süreci daha verimli ve daha öğretici hale getirir. Kendi projelerimde edindiğim bu tecrübeler, sadece kişisel projelerimde değil, aynı zamanda kurumsal projelerimde de karşılaştığım zorluklara daha hazırlıklı olmamı sağladı. Hatalar, gelişimin yakıtıdır; yeter ki onları doğru yönetebilelim.

Bu makalede anlattığım stratejiler, benim kişisel deneyimlerimden yola çıkarak oluşturduğum yaklaşımlardır. Her projenin kendine özgü dinamikleri olabilir, ancak temel prensipler genellikle aynı kalır. Umarım bu bilgiler, sizlerin de yan projelerinizde daha sağlam adımlarla ilerlemenize yardımcı olur. Unutmayın, her hata, daha iyi bir sonraki adımın habercisidir.

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.

Yan projelerde hata yönetimini daha efektif hale getirmek için hangi araçları kullanmalıyım?
Ben kişisel projelerimde, özellikle hataların neden meydana geldiğini anlamak için Journald ve loglama stratejilerini kullanıyorum. Bu araçlar, hatanın oluştuğu anda sistemde neler olup bittiğini anlamamı sağlıyor ve daha hızlı bir şekilde sorunları çözmeme yardımcı oluyor.
Tekrar denemeleri sistematik bir şekilde yönetmek için hangi stratejileri uygulamalıyım?
Ben dört temel stratejiyi uyguluyorum: hata kaydını otomatikleştirmek, düzenli olarak kod gözden geçirmek, hataları öğrenme fırsatlarına çevirmek ve sürekli olarak geri bildirim almak. Bu stratejiler, hatalardan ders çıkararak ilerlememi sağlıyor ve projelerimi daha efektif bir şekilde yönetmeme yardımcı oluyor.
Yan projelerdeki hataların öğrenme fırsatlarına nasıl çevrilir?
Ben hataları öğrenme fırsatlarına çevirmek için, her hatayı bir öğrenme deneyimi olarak görüyorum. Hatanın nedenini anlamak için zaman ayırıyor, nedenini bulduktan sonra ise bu bilgiyi gelecekteki projelerimde kullanıyorum. Ayrıca, hataları belgeleyerek ve paylaşıp geri bildirim almak suretiyle, diğer geliştiricilerle bilgi ve deneyim paylaşımında bulunuyorum.
Yan projelerde sürekli olarak geri bildirim almak için hangi yöntemleri kullanmalıyım?
Ben sürekli olarak geri bildirim almak için, projelerimi diğer geliştiricilerle paylaşıyorum ve onların geri bildirimlerini dinliyorum. Ayrıca, projelerimin kullanıcılarından da geri bildirim alarak, projelerimi daha iyi hale getirmeye çalışıyorum. Bu şekilde, projelerimi sürekli olarak geliştirebiliyor ve daha efektif bir şekilde yönetebiliyorum.
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