Aikido

Hataları boş bırakmak yerine catch bloklarında neden ele almalısınız?

Okunabilirlik

Kural
Hataları catch bloklarında yönetin. 
Boş catch blokları hataları sessizce yutar
ve hata ayıklamayı zorlaştırır.
Desteklenen diller: Java, C, C++, PHP, JavaScript,
TypeScript, Go, Python

Giriş

Boş catch blokları, prodüksiyon kodundaki en tehlikeli antipaterns'lerden biridir. İstisnalar yakalandığı halde yönetilmediğinde, hata hiç iz bırakmadan ortadan kaybolur. Uygulama; bozuk durumlar, geçersiz veriler veya durdurulması gereken başarısız işlemlerle çalışmaya devam eder. Kullanıcılar özelliklerin çalışmadığı ancak hiçbir hata mesajı almadıkları sessiz hatalarla karşılaşır. Operasyon ekiplerinin hata ayıklayabileceği hiçbir log bulunmaz. Bir şeylerin yanlış gittiğine dair tek işaret, saatler veya günler sonra zincirleme hatalar sistemi kullanılamaz hale getirdiğinde ortaya çıkar.

Neden önemli?

Hata ayıklama ve olay müdahalesi: Boş catch blokları hata loglarını ortadan kaldırır. Mühendislerin yığın izi (stack trace), hata mesajı veya hatanın ne zaman ve nerede gerçekleştiğine dair hiçbir göstergesi olmaz, bu da sorunları yeniden üretmeyi neredeyse imkansız hale getirir.

Sessiz veri bozulması: Veritabanı işlemlerinde veya API çağrılarında boş catch blokları içinde hatalar meydana geldiğinde, uygulama sanki başarılı olmuş gibi devam eder. Kayıtlar kısmen güncellenir, işlemler yarım kalır ve veri bozulması fark edildiğinde denetim izi (audit trail) çoktan kaybolmuştur.

Güvenlik açıkları: Boş catch blokları, kimlik doğrulama hataları veya yetkilendirme kontrolleri gibi güvenlik açıklarını maskeler. Güvenlik açısından kritik bir yolda istisnayı tetikleyen bir saldırgan, hata sessizce yutulursa korumaları tamamen atlayabilir.

Zincirleme hatalar: Hatalar yutulduğunda, uygulama geçersiz bir durumda çalışmaya devam eder. Başarısız olan işlemin sonucuna bağlı olan sonraki işlemler de başarısız olur ve mühendisleri gerçek kök nedenden uzaklaştıran bir hata zinciri yaratır.

Kod örnekleri

❌ Kural dışı:

async function updateUserProfile(userId, profileData) {
    try {
        await db.users.update(userId, profileData);
        await cache.invalidate(`user:${userId}`);
        await searchIndex.update(userId, profileData);
    } catch (error) {
        // TODO: handle error
    }

    return { success: true };
}

Neden yanlış: Herhangi bir işlem başarısız olursa, hata sessizce yoksayılır ve fonksiyon başarılı sonucu döndürür. Veritabanı güncellenebilir ancak önbellek geçersiz kılma (cache invalidation) başarısız olabilir ve eski veriler kalabilir. Veya arama dizini güncellemesi başarısız olur, bu da kullanıcının aranamaz hale gelmesine yol açar ancak sorunu gösterecek hiçbir log veya uyarı üretilmez.

✅ Kurallara uygun:

async function updateUserProfile(userId, profileData) {
    try {
        await db.users.update(userId, profileData);
        await cache.invalidate(`user:${userId}`);
        await searchIndex.update(userId, profileData);
        return { success: true };
    } catch (error) {
        logger.error('Failed to update user profile', {
            userId,
            error: error.message,
            stack: error.stack
        });
        throw new ProfileUpdateError(
            'Unable to update profile',
            { cause: error }
        );
    }
}

Neden önemli: Her hata bağlamıyla birlikte loglanır ve hata ayıklama bilgisi sağlar. Hata, çağrı yapan üst koda (caller) iletilerek uygun düzeyde doğru hata yönetimi sağlanır. İzleme sistemleri bu hatalar konusunda uyarı verebilir ve uygulama geçersiz durumla devam etmek yerine hızlıca hata verip durur (fail fast).

Sonuç

Boş catch blokları prodüksiyon kodunda asla kabul edilemez. Yakalanan her istisnanın en azından loglanması gerekir ve birçoğunun üst katmanlara iletilmesi veya belirli kurtarma eylemlerini tetiklemesi şarttır. Bir hatayı gerçekten yoksaymanız gerekiyorsa, bunun iş açısından gerekçesini açıklayan bir yorum satırıyla belgelendirin. Varsayılan yaklaşım her zaman hataları sessizce göz ardı etmek değil, açıkça yönetmek olmalıdır.

Sık Sorulan Sorular

Sorularınız mı var?

Belirli hataları gerçekten yoksaymam gerekirse ne yapmalıyım?

Hatonun neden yoksayılmasının güvenli olduğunu açıklayan bir yorum satırıyla bunu açıkça belgelendirin. Ayrıntılı loglarda (verbose logs) görünmesi ancak uyarıları tetiklememesi için hatayı debug düzeyinde loglayın. Hatayı yoksaymanın geçersiz bir duruma yol açıp açmayacağını değerlendirin. Önbellek uyuşmazlıkları (cache misses) veya ağ zaman aşımı gibi "beklenen" hatalar için bile loglama, operasyon ekiplerinin sistem davranış kalıplarını anlamasına yardımcı olur.

Catch bloklarında her zaman hataları loglamalı mıyım?

Neyin başarısız olduğunu görmeden sorunları ayıklayamayacağınız için loglama genellikle iyi bir fikirdir. Hatayı başka bir yerde ele alınmak üzere hemen yeniden fırlatmak (re-throwing) gibi loglara ihtiyaç duymadan sorunu takip edebileceğiniz durumlar vardır veya kritik hatalarda uygulama çöküp yeniden başlamalıdır. Ancak uygun loglama her zaman yardımcı olur.

Loglama ve hataları yeniden fırlatma (re-throwing) arasındaki fark nedir?

Loglama; hata ayıklama ve izleme amacıyla ne olduğunu kaydeder. Yeniden fırlatma ise hatayı çağrı yapan üst koda ileterek nasıl yanıt vereceğine karar vermesini sağlar. İkisini de yapın: hatayı hata noktasında bağlamıyla birlikte loglayın, ardından çağrı yapanların kurtarma sürecini yönetmesine izin vermek için (daha spesifik bir hata türüne sararak) yeniden fırlatın. Aynı hatayı birden fazla düzeyde loglamayın, bu gürültü yaratır.

Finally bloklarında oluşan hataları nasıl yönetirim?

Finally blokları nadiren hata fırlatmalıdır. Hata potansiyeli olan işlemler (kaynakları kapatmak gibi) gerçekleştirmeleri gerekiyorsa, bunları kendi try-catch blokları içine alın. Tüm hataları loglayın ancak orijinal hatayı maskelemelerine izin vermeyin. Bazı diller hem ana hatayı hem de finally bloğu hatalarını yönetmek için sözdizimi sağlar; her iki hata bağlamını da korumak için bu mekanizmaları kullanın.

Her hatayı loglamanın performans üzerindeki etkisi nedir?

Loglama, prodüksiyon sorunlarını loglar olmadan ayıklamanın maliyetiyle karşılaştırıldığında ucuzdur. Modern loglama framework'leri yüksek düzeyde optimize edilmiştir. Loglamanın performansı etkileyecek kadar çok hatanız varsa, bunları gizlemek yerine hataları düzeltin. Yüksek hata oranları, boş catch bloklarının yalnızca daha da kötüleştireceği ciddi sorunlara işaret eder.

Catch blokları her zaman hata mı fırlatmalı, yoksa hata değerleri mi döndürmeli?

Bu, dile ve mimariye bağlıdır. Promise'ler içeren JavaScript'te, catch'ten hata fırlatmak sonraki hata işleyicisine iletilir. Catch'ten bir hata nesnesi döndürmek ise promise'i o hata ile çözer ki bu genellikle yanlıştır. Dilinizin hata yönetimi semantiğine aşina olun. Genellikle, anlamlı bir şekilde kurtarma şansınız olmadıkça hataların yayılmasına izin verin.

Try-catch içermeyen async işlemlerdeki hataları nasıl yönetirim?

Promise'ler üzerinde .catch() işleyicilerini, event emitter'larda hata olay dinleyicilerini veya callback tabanlı API'lerde hata callback'lerini kullanın. Reddedilme (rejection) işleyicilerini veya hata callback'lerini asla yoksaymayın. İşlenmeyen promise reddedilmeleri süreç düzeyinde izlenmeli ve kritik hatalar olarak ele alınmalıdır. Modern Node.js, sessiz başarısızlıktan daha iyi bir seçenek olarak işlenmeyen reddedilmelerde sonlandırılabilir.

Şimdi güvenliğinizi sağlayın

Kodunuzu, bulutunuzu ve çalışma zamanınızı tek bir merkezi sistemde güvenceye alın.
Güvenlik açıklarını otomatik olarak hızla bulun ve düzeltin.

Kredi kartı gerekmez | Tarama sonuçları 32 saniyede.