Gereksinimler ve Ön Hazırlık
Projeye başlamadan önce geliştirme ortamınızın güncel olduğundan emin olmalısınız. .NET 9 SDK, modern C# özelliklerini (record tipleri, pattern matching vb.) en verimli şekilde kullanmanıza olanak tanır. İhtiyacınız olan temel araçlar şunlardır:
- Visual Studio 2022 (v17.12+) veya VS Code (C# Dev Kit ile).
- .NET 9.0 SDK.
- Veri yapılarını yönetmek için temel LINQ (Language Integrated Query) bilgisi.
- Unit test süreçleri için xUnit kütüphanesi.
Kod örneklerimizde, dış kaynaklardan gelen verileri temsil etmek için record yapılarını kullanacağız. record kullanımı, veri transfer nesneleri (DTO) için değişmezlik (immutability) sağlar ve hata payını düşürür.
Adım 1: Veri Modellerini Oluşturma
Algoritmanın kalbi, farklı kaynaklardan gelen verileri tek bir potada eritebilen esnek bir veri modelidir. Her platformun fiyat formatı farklı olabilir, bu yüzden bir ProductPrice modeli tanımlayarak işe başlıyoruz.
public record ProductPrice(
string ProductName,
decimal Price,
string Currency,
string SourceName,
DateTime LastUpdated
);
Yukarıdaki kod bloğu, ürünün adını, fiyatını, para birimini, kaynağını ve zaman damgasını tutan değişmez bir veri yapısı oluşturur. Bu yapı, karşılaştırma sırasında verilerin tutarlı kalmasını sağlar.
Adım 2: Fiyat Normalleştirme Stratejisi
Farklı kaynaklardan gelen veriler genellikle farklı para birimlerine veya vergi oranlarına sahip olabilir. Karşılaştırma yapmadan önce tüm fiyatları ortak bir birime çevirmek zorunludur. Aşağıdaki örnek, basit bir kur dönüştürme mantığını göstermektedir.
public class PriceNormalizer
{
private readonly decimal _usdToTryRate = 34.50m; // Örnek kur değeri
public decimal NormalizeToTry(decimal price, string currency)
{
return currency.ToUpper() switch
{
"USD" => price * _usdToTryRate,
"EUR" => price * 37.20m,
"TRY" => price,
_ => throw new NotSupportedException("Desteklenmeyen para birimi.")
};
}
}
Bu metot, switch ifadesini kullanarak gelen para birimini Türk Lirası'na çevirir. NotSupportedException kullanımı, hatalı veri girişlerinde sistemin güvenli bir şekilde durmasını sağlar.
Adım 3: Karşılaştırma Algoritmasını Yazma
Şimdi elimizdeki verileri karşılaştırıp en uygun olanı seçen algoritmayı yazalım. LINQ kullanarak koleksiyon içerisindeki en düşük fiyatlı ürünü saniyeler içinde bulabiliriz.
public class PriceComparator
{
public ProductPrice GetBestPrice(IEnumerable prices)
{
if (prices == null || !prices.Any())
throw new ArgumentException("Fiyat listesi boş olamaz.");
return prices.OrderBy(p => p.Price).First();
}
}
Bu metot, gelen listeyi fiyata göre küçükten büyüğe sıralar ve listenin ilk elemanını döndürür. ArgumentException kontrolü, boş liste gönderildiğinde uygulamanın çökmesini engeller.
Adım 4: Performans ve Ölçeklenebilirlik
Veri setiniz büyüdüğünde, karşılaştırma işleminin hızı önem kazanır. Büyük listelerle çalışırken Parallel LINQ (PLINQ) kullanarak hesaplamaları işlemci çekirdeklerine dağıtabilirsiniz.
public ProductPrice GetBestPriceParallel(IEnumerable prices)
{
// Çok büyük veri setlerinde performans artışı sağlar
return prices.AsParallel().OrderBy(p => p.Price).First();
}
AsParallel() metodu, sorgunun çoklu çekirdek üzerinde çalışmasını sağlar. Ancak, çok küçük listelerde bu yöntem ek yük (overhead) getirebileceği için yalnızca büyük veri setlerinde tercih edilmelidir.
Karşılaştırma Yöntemleri ve Özellikleri
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| LINQ (OrderBy) | Okunabilir ve basit | Büyük veride yavaş |
| PLINQ (Paralel) | Yüksek performans | Küçük veride overhead |
| Döngü (Foreach) | Düşük bellek kullanımı | Kod karmaşıklığı |
Adım 5: Hata Yönetimi ve Güvenlik
Dış kaynaklardan gelen veriler her zaman güvenilir olmayabilir. SQL Injection veya XSS gibi saldırılara karşı verileri her zaman valide etmelisiniz. Ayrıca, API'den gelen verileri doğrudan sisteme almadan önce tip dönüşümlerini kontrol etmelisiniz.
Kritik Güvenlik Uyarısı: Dış API'lerden gelen verileri asla doğrudan veritabanı sorgularınızda veya kullanıcı arayüzünde (HTML çıktısı) doğrudan kullanmayın. Mutlaka "Sanitize" (temizleme) işleminden geçirin ve tip güvenliğini (type safety) her aşamada koruyun.
public bool IsValidPrice(decimal price)
{
// Negatif fiyat veya aşırı yüksek değer kontrolü
return price > 0 && price < 1000000;
}
Sıkça Sorulan Sorular
Fiyat karşılaştırma algoritmasında neden LINQ kullanmalıyım?
LINQ, C# içerisinde veriyi sorgulamak için standartlaşmış, okunabilir ve tip güvenli bir sözdizimi sunar. Kod bakımını kolaylaştırır ve hata yapma riskini azaltır.
Çok fazla kaynaktan veri geliyorsa sistem nasıl hızlandırılır?
Veri çekme işlemlerini Task.WhenAll kullanarak asenkron (async/await) yapıda kurgulamalısınız. Böylece kaynaklardan veri beklerken ana iş parçacığınız (main thread) kilitlenmez.
Para birimi değişimlerini nasıl güncel tutabilirim?
Kur verilerini yerel bir veritabanında saklamak yerine, güvenilir bir finansal API'den (örneğin TCMB API) periyodik olarak (cache mekanizması ile) çekip güncellemelisiniz.
Veri tutarsızlıklarını nasıl yönetirim?
Her kaynağın verisini alırken bir "Validation" katmanı oluşturun. Beklenen formatta olmayan verileri loglayarak (Serilog gibi kütüphanelerle) sistemin dışında bırakın.
Bu algoritma gerçek zamanlı çalışabilir mi?
Evet, ancak gerçek zamanlı sistemlerde "Race Condition" (yarış durumu) oluşmaması için ConcurrentBag gibi thread-safe koleksiyonlar kullanmanız önerilir.
İleri Seviye Optimizasyon: Paralel İşleme ve Asenkron Sorgulama
Fiyat karşılaştırma algoritmaları, doğası gereği I/O (giriş/çıkış) yoğunluklu işlemlerdir. Eğer onlarca farklı kaynaktan veri çekiyorsanız, standart foreach döngüleri sisteminizi darboğaza sokacaktır. C# tarafında Task.WhenAll kullanarak tüm kaynakları eş zamanlı sorgulamak, toplam yanıt süresini (latency) en yavaş olan tek bir kaynağın süresine indirger.
public async Task GetPricesParallelAsync(IEnumerable sourceUrls)
{
var tasks = sourceUrls.Select(url => FetchPriceFromSourceAsync(url));
var results = await Task.WhenAll(tasks);
return results.Where(r => r != null).ToList();
}
private async Task FetchPriceFromSourceAsync(string url)
{
try
{
using var client = new HttpClient();
var response = await client.GetStringAsync(url);
// Burada HTML parse işlemleri yapılır
return ParsePrice(response);
}
catch (HttpRequestException)
{
return null; // Hatalı kaynakları sessizce atla
}
}
Birim Testleri ile Fiyat Doğrulama Stratejileri
Fiyat karşılaştırma motorlarında en büyük risk, hatalı parse edilen verilerin kullanıcıya yanlış fiyat olarak dönmesidir. Bu durumu engellemek için "Boundary Testing" (Sınır Değer Testleri) uygulamak kritiktir. Özellikle para birimi dönüşümlerinde veya indirim hesaplamalarında oluşabilecek kayan nokta (floating point) hatalarını önlemek için decimal veri tipini kullanmalı ve birim testlerinizde beklenen değerleri kesin olarak tanımlamalısınız.
Aşağıdaki örnek, algoritmanızın mantıksal doğruluğunu test etmek için kullanabileceğiniz temel bir xUnit yapısını göstermektedir:
public class PriceEngineTests
{
[Fact]
public void CalculateDiscount_ShouldReturnCorrectValue()
{
// Arrange
var engine = new PriceComparisonEngine();
decimal originalPrice = 100m;
decimal discountRate = 0.2m;
decimal expected = 80m;
// Act
var result = engine.ApplyDiscount(originalPrice, discountRate);
// Assert
Assert.Equal(expected, result);
}
}
Veri Tutarlılığı İçin İpucu
- Caching: Sık sorgulanan ürünleri
IMemoryCachekullanarak bellekte tutun. - Circuit Breaker: Bir kaynak sürekli hata veriyorsa, belirli bir süre o kaynağı devre dışı bırakmak için Polly kütüphanesini kullanın.
- Logging: Fiyat değişimlerini
Seriloggibi araçlarla loglayarak, hangi kaynağın hatalı veri gönderdiğini geçmişe dönük analiz edin.
Bu ileri seviye yaklaşımlar, uygulamanızın sadece bir "script" olmaktan çıkıp, kurumsal düzeyde bir fiyat takip motoruna dönüşmesini sağlayacaktır. Özellikle Polly kütüphanesi ile hata toleransı eklemek, üretim ortamındaki kararlılığınızı %99'un üzerine çıkaracaktır.
Sonuç
C# ile özel bir fiyat karşılaştırma algoritması geliştirmek, veriyi doğru modellemek ve doğru araçları kullanmakla başlar. Bu rehberde, veri modellerinden performanslı sorgulama tekniklerine kadar temel bir yapı kurduk. Bir sonraki adım olarak, bu algoritmayı bir ASP.NET Core Web API projesine entegre ederek, gerçek zamanlı fiyat takip eden bir mikro hizmet mimarisi oluşturmayı deneyebilirsiniz. Unutmayın; iyi bir yazılım, sadece çalışan değil, aynı zamanda bakımı kolay ve ölçeklenebilir olandır.
Yasal Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Üretim ortamında kullanılacak finansal uygulamalar için gerekli güvenlik denetimlerini (pen-test) yaptırmanız ve veri gizliliği yasalarına (KVKK/GDPR) uygun hareket etmeniz sorumluluğunuzdadır.


Yorumlar (0)
Yorum Yaz