Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Idempotency Key: Çift Tıklama ve Retry'da Aynı Siparişi İki Kez Oluşturmamak
Çift tıklama ve retry'da aynı siparişin iki kez oluşmasını engellemenin güvenilir yolu, istemcinin her işlem için ürettiği bir Idempotency-Key'i sunucunun kullanıcı scope'unda, request hash'iyle birlikte saklaması ve iş ile 'tamamlandı' kaydını aynı transaction'da yazmasıdır. Bu yazı IETF taslağının güncel durumunu (draft-08, RFC değil), 400/409/422 kurallarını ve ASP.NET Core endpoint filter + SQL Server uygulamasını gerçek çıktılarla gösteriyor.
Zaman ve Time Zone: UTC Instant, Yerel İş Günü, DateOnly ve TimeProvider
Zamanı doğru saklamak için üç kavramı ayırmak gerekir: event anları UTC instant (DateTimeOffset), takvim günleri DateOnly, gelecekteki yerel event'ler wall-clock time ve IANA zone id'si olarak saklanır. Bu yazı tenant'ın gününü UTC aralığına çevirmeyi, TimeProvider ile test edilebilir saati, SQL Server'daki AT TIME ZONE tuzaklarını ve Angular'daki tarih kaymasını gerçek çıktılarla gösteriyor.
Para ve Yuvarlama: decimal, Money Value Object, KDV ve Kuruş Dağıtımı
Parayı doğru modellemek için tutarı para birimiyle birlikte taşıyan bir Money value object, C# ile SQL'de aynı açık yuvarlama kuralı ve bölme yerine kuruşu kaybetmeyen Allocate gerekir. Yazı Math.Round ile SQL ROUND'un 0,125'te ayrıştığını, satır ve toplam bazında KDV'nin 1 kuruş farkını, tarihli KDV oranı tablosunu (Kasım 2026 itibarıyla %20, %10, %1), EF Core complex type mapping'ini ve JSON'da string tutarı gerçek çıktılarla gösteriyor.
Numaralandırma: Fatura ve Sipariş Numaraları, Gapless Sequence ve Yıllık Sıfırlama
Ardışık olması gereken fatura numarası identity, MAX + 1 ya da SEQUENCE ile değil, onay transaction'ının içinde (Series, Year) key'li bir counter tablosundan lock alan bir UPDATE ile alınmalıdır; boşluk kabul edilen sipariş numaraları için SEQUENCE yeterlidir. Yazı GİB'in 16 karakterlik belge numarası biçimini, 50 concurrent onayla boşluksuzluğu, lock süresinin throughput'a etkisini ve fatura tarihine göre yıllık sıfırlamayı gerçek çıktılarla gösteriyor.
Feature Flag'leri Kodda Tasarlamak: Toggle Türleri, Microsoft.FeatureManagement ve Flag Borcu
Feature flag'i doğru tasarlamak, önce türünü (release, experiment, ops, permission) belirlemek, kararı tek bir toggle router'da toplamak ve her flag'e sahip ile son kullanma tarihi vermektir. Yazı Microsoft.FeatureManagement 4.8.0 ile tenant filter'ı, snapshot ile istek içi tutarlılığı, WithFeatureGate ile kill switch'i ve süresi geçen flag'i yakalayan testi gerçek çıktılarla gösteriyor.
Settings Tabloları: Global → Tenant → Kullanıcı Override Hiyerarşisi
Çalışırken değişen, tenant ve kullanıcıya göre ezilen ayarlar için en sağlam yol, her ayarın tip, varsayılan, aralık ve en alt override seviyesini taşıyan bir tanımı ile bu tanıma bağlı tipli key-value değerlerdir; öncelik kuralı tek bir service'te, yazma doğrulamalı ve audit'li olur. Yazı EAV, tipli kolonlar, JSON belge ve dış store ile karşılaştırıyor ve EF Core'un nullable unique index'e eklediği gizli IS NOT NULL filtresini gösteriyor.
Multi-Tenancy'de Veri İzolasyonu: Database-per-Tenant, Shared Schema ve Row-Level Security
Çoğu SaaS için en iyi denge, TenantId kolonlu paylaşılan tablolar, EF Core'da named bir tenant query filter'ı ve onun arkasında SESSION_CONTEXT ile beslenen SQL Server row-level security'dir. Yazı database-per-tenant, schema-per-tenant ve shared table modellerini karşılaştırıyor; tenant çözümlemeyi, background job'ları ve izolasyonu otomatik test etmeyi gerçek çıktılarla gösteriyor.
Çok Dilli Veri: Ürün Adını TR ve EN Saklamak — Translation Table, JSON Kolon ve Fallback
Kullanıcının yönettiği çok dilli veri için en esnek seçenek, (EntityId, Culture, Name) key'li bir translation tablosu ve en-GB → en → tr gibi tek yerde kurulan bir fallback zinciridir. Yazı dil başına kolon, translation tablosu, SQL Server 2025 json kolonu ve ayrı bir translation service'i karşılaştırıyor; EF Core 10 LeftJoin ile fallback'i ve Türkçe I için collation seçimini gerçek çıktılarla gösteriyor.
Polymorphic Association: Yorum ve Ek Dosyaları Birden Fazla Tabloya Bağlamak
Ek dosyayı EntityType/EntityId çiftiyle birden çok tabloya bağlamak FK'yı, cascade delete'i ve güvenli yetkilendirmeyi kaybettirir; sahip tipleri az ve kararlıysa her sahip için nullable FK ve tam olarak birini zorunlu kılan check constraint'li exclusive arc kullan. Yetkiyi ekin kendisinden değil sahibinin policy'sinden türet.
SQL'de Hiyerarşik Veri: Adjacency List, Recursive CTE, Closure Table ve hierarchyid
Departman ağacında alt ağaç sorguları sık, taşımalar nadirse SQL Server'da hierarchyid (EF Core 8+ ile LINQ desteği) ve FK bütünlüğü için ParentId birlikte iyi bir seçimdir; veritabanı bağımsızlığı gerekiyorsa closure table kullan. Ağacı uygulamada düğüm düğüm gezmek N+1 üretir, döngüyü de taşıma anında IsDescendantOf ile engelle.
Status Field'ı Her Yerden Güncelleniyorsa: Transition Table, State Machine ve Status History
Status kolonunu her endpoint'in yazabildiği bir field olmaktan çıkar: istemci durum değil aksiyon göndersin, izinli geçişleri tek bir yerde (transition table, domain method veya Stateless) tut, her geçişi gerekçesiyle aynı transaction'da status history'ye yaz ve rowversion ile çift onayı engelle.
Temporal Data: Geçerlilik Tarihli Kayıtlar, Fiyat Geçmişi ve Bitemporal Model
Geçmişe dönük düzeltme yapılan verilerde iki zaman ekseni gerekir: valid time (bilgi hangi tarih için doğru) ve transaction time (bilgi ne zaman girildi). SQL Server temporal table yalnız transaction time verir; yarı açık [ValidFrom, ValidTo) aralıklı bir tabloyu system-versioned yaparak EF Core 10 ile bitemporal sorgu yazabilirsin.