03.fb3d0d5e numaralı fikir

CQRS: Faydalar ve Değerlendirme.

CQRS, okuma ve yazma işlemlerini birbirinden ayırarak özellikle orta ve büyük ölçekli uygulamalarda daha esnek bir mimari sunar. Doğru kullanıldığında performans, ölçeklenebilirlik ve sürdürülebilirlik açısından önemli avantajlar sağlayabilir. Ancak beraberinde gelen karmaşıklık, nihai tutarlılık ve veri çoğaltma gibi konular da göz ardı edilmemelidir. Bu yazıda CQRS yaklaşımının güçlü ve zayıf yönlerini, gerçek hayattan örneklerle birlikte değerlendiriyoruz.

CQRS: Faydalar ve Değerlendirme

CQRS: Faydalar ve Değerlendirme

Önceki yazılarda CQRS'nin ne olduğunu ve temel çalışma mantığını ele almıştık. Peki bu mimari yaklaşımı gerçekten ne zaman tercih etmeliyiz?

İnternette CQRS çoğu zaman her projeye uygulanması gereken "en iyi mimari" gibi anlatılıyor. Oysa pratikte durum biraz farklı. CQRS, doğru senaryoda oldukça güçlü bir çözüm sunarken, gereksiz kullanıldığında uygulamayı gereğinden fazla karmaşık hale de getirebilir.

Bu nedenle CQRS'yi sadece avantajlarıyla değil, getirdiği maliyetlerle birlikte değerlendirmek gerekir.

Ölçeklenebilirlik

CQRS'nin en büyük avantajlarından biri okuma (Query) ve yazma (Command) işlemlerinin birbirinden bağımsız olarak ölçeklendirilebilmesidir.

Çoğu kurumsal uygulamada okuma işlemleri yazma işlemlerinden kat kat fazladır. Örneğin;

  • Bir e-ticaret sitesinde ürünler milyonlarca kez görüntülenir.
  • Sipariş oluşturma işlemi ise görüntülemeye göre çok daha az gerçekleşir.

Tek bir veri modeli kullanıldığında hem okuma hem yazma aynı altyapıyı paylaşır. Bu durum özellikle yoğun trafik altında darboğaz oluşturabilir.

CQRS sayesinde;

  • Okuma tarafı cache kullanabilir.
  • Ayrı bir veritabanından beslenebilir.
  • Gerektiğinde farklı sunuculara dağıtılabilir.

Yazma tarafı ise tamamen veri bütünlüğüne odaklanmaya devam eder.

Bu ayrım özellikle yüksek trafikli sistemlerde ciddi avantaj sağlar.

Performans

CQRS'nin önemli avantajlarından biri de her modeli kendi kullanım amacına göre optimize edebilmesidir.

Yazma modeli;

  • İş kurallarını uygular.
  • Validasyon yapar.
  • Transaction yönetir.
  • Veri bütünlüğünü korur.

Okuma modeli ise bunların hiçbirini yapmak zorunda değildir.

Sadece hızlı veri döndürmeye odaklanabilir.

Örneğin bir yönetim panelinde aşağıdaki gibi birçok tabloyu birleştiren karmaşık sorgular bulunabilir.

SELECT
    o.OrderNo,
    c.Name,
    p.ProductName,
    s.StatusName
FROM Orders o
JOIN Customers c ON c.Id=o.CustomerId
JOIN Products p ON p.Id=o.ProductId
JOIN Status s ON s.Id=o.StatusId

CQRS kullanan bir yapıda bu bilgiler önceden hazırlanmış bir Read Model içerisinde tutulabilir. Böylece kullanıcı ekranı tek sorguyla çok daha hızlı cevap verebilir.

Özellikle dashboard, raporlama ve listeleme ekranlarında bunun ciddi katkısı görülebilir.

Endişelerin Ayrılması (Separation of Concerns)

Büyüyen projelerde en büyük problemlerden biri aynı sınıfın hem veri güncellemesi hem de veri okuması yapmaya başlamasıdır.

Bir süre sonra servisler şu hale gelir:

  • Sipariş oluşturur.
  • Sipariş günceller.
  • Sipariş listeler.
  • Dashboard üretir.
  • Rapor oluşturur.
  • İstatistik hesaplar.

Bu durum kodun okunmasını ve bakımını zorlaştırır.

CQRS ise bu sorumlulukları doğal olarak birbirinden ayırır.

Command tarafı yalnızca değişiklik yapar.

Query tarafı yalnızca veri okur.

Böylece;

  • Kod daha okunabilir olur.
  • Test yazmak kolaylaşır.
  • Yeni geliştiricilerin projeye adapte olması hızlanır.
  • Değişikliklerin etkisi daha rahat analiz edilir.

Esneklik

Okuma ve yazma katmanlarının birbirinden bağımsız olması geliştirme sürecinde de önemli bir esneklik sağlar.

Örneğin;

Bugün SQL Server kullanan bir sistemde yazma işlemleri devam ederken, okuma tarafını Elasticsearch veya Redis ile desteklemek mümkün olabilir.

Ya da yalnızca raporlama ekranları için farklı bir veri modeli oluşturabilirsiniz.

Bu değişikliklerin yazma tarafını etkilememesi CQRS'nin önemli avantajlarından biridir.

Bunun yanında ekipler de paralel çalışabilir.

Bir ekip yeni Command işlemleri geliştirirken başka bir ekip Read tarafını iyileştirebilir.

Artan Karmaşıklık

CQRS'nin en büyük dezavantajı ise mimariyi daha karmaşık hale getirmesidir.

Artık tek model yerine;

  • Command modeli
  • Query modeli
  • Handler'lar
  • DTO'lar
  • Event'ler
  • Mapping işlemleri

gibi daha fazla bileşen oluşur.

Küçük bir CRUD uygulaması için bu yapı çoğu zaman gereksizdir.

Örneğin yalnızca kullanıcı kayıtlarının tutulduğu basit bir yönetim panelinde CQRS kullanmak, sağlayacağı faydadan daha fazla bakım maliyeti oluşturabilir.

Bu yüzden CQRS'nin her projeye uygulanması gereken bir mimari olduğu düşünülmemelidir.

Nihai Tutarlılık (Eventual Consistency)

CQRS kullanan sistemlerde okuma modeli çoğu zaman yazma modeliyle birebir aynı anda güncellenmez.

Örneğin;

Kullanıcı sipariş oluşturur.

Sipariş başarıyla kaydedilir.

Ancak raporlama ekranında sipariş birkaç saniye sonra görünür.

Bu durum "Eventual Consistency" yani nihai tutarlılık olarak adlandırılır.

Bu davranış birçok dağıtık sistem için tamamen normaldir.

Önemli olan sistem tasarlanırken bu gecikmenin kullanıcı deneyimini olumsuz etkilemeyecek şekilde planlanmasıdır.

Örneğin finansal işlemlerde bu yaklaşım dikkatle değerlendirilmelidir.

Veri Çoğaltma

CQRS'de okuma modeli çoğu zaman yazma modelinden farklıdır.

Bu nedenle bazı veriler birden fazla yerde tutulabilir.

Örneğin;

Order tablosunda bulunan bilgiler, yalnızca listeleme ekranı için oluşturulmuş farklı bir Read Model içerisine kopyalanabilir.

İlk bakışta bu gereksiz gibi görünse de bunun amacı sorguları mümkün olduğunca hızlandırmaktır.

Elbette bunun karşılığında;

  • Daha fazla depolama alanı
  • Senkronizasyon ihtiyacı
  • Veri güncelleme süreçleri

gibi ek maliyetler ortaya çıkabilir.

Bu nedenle veri çoğaltma bilinçli yapılmalıdır.

C# Dünyasında CQRS ve MediatR

.NET ekosisteminde CQRS denildiğinde akla gelen ilk kütüphanelerden biri MediatR'dır.

MediatR aslında doğrudan bir CQRS kütüphanesi değildir. Bir Mediator (Arabulucu) Pattern uygulamasıdır. Ancak CQRS mimarisini uygulamayı oldukça kolaylaştırdığı için bu iki kavram sıklıkla birlikte anılır.

Basit bir Command örneği aşağıdaki gibidir.

public record CreateOrderCommand(string CustomerName)
    : IRequest<int>;

Handler tarafında ise işlem gerçekleştirilir.

public class CreateOrderCommandHandler
    : IRequestHandler<CreateOrderCommand, int>
{
    public async Task<int> Handle(
        CreateOrderCommand request,
        CancellationToken cancellationToken)
    {
        // Sipariş oluşturma işlemleri

        return 1;
    }
}

Benzer şekilde Query işlemleri de kendi Handler'ları üzerinden çalışır.

Bu yapı sayesinde Controller veya API katmanı doğrudan servislerle haberleşmek yerine yalnızca MediatR üzerinden ilgili isteği gönderir.

Sonuç olarak bağımlılıklar azalır ve kod daha modüler hale gelir.

Son yıllarda MediatR'ın lisanslama modeli ve alternatif kütüphaneler hakkında çeşitli tartışmalar yaşansa da, CQRS mantığını öğrenmek isteyen geliştiriciler için hâlâ oldukça anlaşılır ve yaygın kullanılan araçlardan biri olmaya devam ediyor.

CQRS Her Projede Kullanılmalı mı?

Bence bu sorunun cevabı net şekilde hayır.

Basit CRUD uygulamalarında CQRS çoğu zaman gereksizdir.

Ancak aşağıdaki senaryolarda ciddi avantaj sağlayabilir:

  • Trafiğin yüksek olduğu sistemlerde
  • Okuma işlemlerinin yazma işlemlerinden çok fazla olduğu uygulamalarda
  • Mikroservis mimarilerinde
  • Büyük ekiplerin çalıştığı projelerde
  • Karmaşık iş kurallarına sahip domain modellerinde

Mimari seçim yaparken önemli olan popüler olanı kullanmak değil, problemin gerçekten buna ihtiyaç duyup duymadığını değerlendirmektir.

Sonuç

CQRS, doğru yerde kullanıldığında uygulamanın ölçeklenebilirliğini, performansını ve bakım kolaylığını önemli ölçüde artırabilen güçlü bir mimari yaklaşımdır. Buna karşılık, getirdiği ek karmaşıklık ve nihai tutarlılık gibi konular da tasarım aşamasında dikkate alınmalıdır. Her proje için varsayılan tercih olarak görmek yerine, ihtiyaçları analiz ederek karar vermek uzun vadede çok daha sağlıklı sonuçlar verecektir.

Bu bilgiler yeterli gelmediyse yapay zekaya sorabiliriz.