Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Debugging Bir Yöntemdir: Gözlem, Hipotez, Deney ve 9 Altın Kural
Debugging tahminle değil yöntemle yapılır: gözlem, test edilebilir hipotez, tahmin, deney ve sonuç döngüsü. 1 kuruşluk sipariş toplamı farkıyla başlayan vakada Agans'ın 9 kuralını, shotgun debugging'in maliyetini ve debugging günlüğünü gerçek çıktılarla anlatıyoruz.
Bug'ı Reproduce Etmek: Minimal Repro, Ortam Farkları ve Önce Kırmızı Test
Reproduce edemediğin bug'ı düzeltemezsin: önce kullanıcıdan doğru bilgiyi al, culture, timezone, configuration ve sürüm farklarını kontrol et, hatayı minimal repro'ya indir ve düzeltmeden önce kırmızı bir xUnit testi yaz. Container'da 1245'e dönüşen 12,45 ve iki satıra inen sipariş toplamı hatası gerçek çıktılarla.
Problemi Daraltmak: Binary Search, git bisect run ve Delta Debugging
Hatayı bulmanın en hızlı yolu aralığı her adımda ikiye bölmektir: kodda, katmanlarda, commit'lerde ve girdide. git bisect run 31 commit'lik aralıkta derlenmeyen commit'i 125 ile atlayıp hatalı refactoring'i 7 denemede buluyor; ddmin algoritması 5.000 satırlık import dosyasını 3 satıra indiriyor.
Hata Mesajı ve Stack Trace Okumak: .NET Exception'ları, Async Stack'ler ve Angular NG Hataları
Stack trace yukarıdan aşağı değil katman katman okunur: asıl sebep çoğu zaman ---> ile başlayan inner exception'dadır ve log'daki 50 aynı hatanın kökü genellikle zaman sırasındaki ilk hatadır. .NET 10'da InnerException zinciri, AggregateException, throw ex ile kaybolan stack, ExceptionDispatchInfo, ProblemDetails traceId'den log'a gitmek, source map ve Angular 22'nin NG0100, NG0200, NG0201 hatalarını gerçek çıktılarla okuyoruz.
.NET Debugger İleri Seviye: Conditional, Tracepoint, Data Breakpoint ve Exception Settings
Değeri kimin değiştirdiğini bulmanın en kısa yolu data breakpoint: Visual Studio'da .NET Core 3+ projelerde property değişince debugger yazan satırda durur. Conditional, hit count ve dependent breakpoint, tracepoint, yutulan exception'lar için Exception Settings, Set Next Statement, Hot Reload, DebuggerDisplay ve Source Link'i gerçek çıktılarla; Copilot önerilerini hipotez olarak test etmeyi ve Rider ile Visual Studio Code karşılıklarını görüyoruz.
Async ve Multi-Thread Debugging: Parallel Stacks, Tasks Penceresi, Deadlock ve Race Condition
Async bir hang'de bekleyen kod hiçbir thread'in stack'inde görünmez; Parallel Stacks'in Tasks görünümüne ya da dump'taki async zincire bakmak gerekir. Lock sırası deadlock'unu ve .Result kaynaklı sync-over-async deadlock'unu dotnet-stack çıktısıyla okuyor, thread pool starvation'ı ölçüyor, Dictionary, sayaç ve check-then-act race condition'larını gerçek koşularla gösterip freeze/thaw ile race'i zorlamayı anlatıyoruz.
Log'lardan Sebep Bulmak: Correlation ID, Trace ID ve Zaman Çizelgesi Kurmak
Hatanın sebebini log'larda bulmak için önce ilk sinyali, sonra tek bir request'in trace ID ile servisler arasındaki hikâyesini, en son deploy ve configuration değişiklikleriyle ortak bir zaman çizelgesini kuruyoruz. W3C traceparent, ProblemDetails'teki traceId, runtime'da log seviyesi açmak, jq sorguları ve log'daki kişisel veriyi maskelemek.
Crash ve Memory Dump Analizi: dotnet-dump, SOS Komutları ve Container'da Dump Almak
Crash dump'ı DOTNET_DbgEnableMiniDump ile otomatik alıyor, dotnet-dump analyze içinde pe -lines, clrthreads, dumpheap -stat, gcroot, syncblk ve dumpasync ile çöken thread'i, büyüyen static cache'i ve lock deadlock'unu buluyoruz. Container'da PID 1 ve --init farkı, SDK'sız image'a aracı koymak, Heap/Full dump'ın OOM riski ve dump'lardaki kişisel veri.
Hang ve Yavaşlık Teşhisi: dotnet-stack, dotnet-trace ve Thread Pool Starvation
Cevap vermeyen servisi sırayla dotnet-counters, dotnet-stack ve süreli bir dotnet-trace ile teşhis ediyoruz: .Result kullanan endpoint 200 eşzamanlı istekte p50'yi 47 saniyeye çıkarıyor, await ile 204 ms'ye iniyor. WaitHandleWait event'leri, .NET 10'daki collect-linux'un ön koşulları ve production'da trace'i güvenle sınırlamak.
Root Cause Analysis: 5 Whys, Fishbone ve Blameless Postmortem
Root cause bir kişi değil, hatanın production'a ulaşmasına izin veren koşullardır. Sipariş toplamı vakasında belirti, proximate cause ve root cause'u ayırıyor; 5 Whys ve fishbone ile etkenleri buluyor, etkiyi ölçüyor, Money value object ve BannedApiAnalyzers ile bu sınıf bug'ı imkânsız kılıyor ve blameless postmortem'i yazıyoruz.
Gerçek Hayattan Bug Avları 1: Backend — Kültür, Saat Dilimi, Socket ve Mutable Key
Backend bug'larında ilk hipotez çoğu zaman suçu başka bir sisteme atar; onu çürüten ucuz bir gözlemdir. Altı gerçek vaka: tr-TR'de bozulan rol kontrolü, UTC ile 3 saat kayan rapor, new HttpClient() ile biriken TIME_WAIT socket'leri, Dictionary'de değişen key, process'i çökerten async void (ve PID 1 container'da yarı ölü kalması), EF Core'da N+1; her birinde düzeltme, regression testi ve analyzer.