Ana Sayfa / Blog / CQRS pattern: 3 gerçek senaryoda işe yaradığı, 5 senaryoda overengineering olduğu yerler

CQRS pattern: 3 gerçek senaryoda işe yaradığı, 5 senaryoda overengineering olduğu yerler

CQRS (Command Query Responsibility Segregation) her büyük mimari tartışmasında geçiyor. Gerçek projede nerede değer katıyor, nerede sadece karmaşıklık ekliyor?

CQRS ismini ilk duyduğumda 2013’te bir konferanstaydı. O zamandan beri 10+ yıl geçti ve hâlâ çoğu ekip bu pattern’i yanlış kullanıyor ya da gereksiz yere uyguluyor.

CQRS basit fikirli: read operasyonları ile write operasyonları farklı modeller kullansın. Ama bu basit fikrin altındaki karmaşıklık bazı projeler için kurtarıcı, bazıları için zaman kaybı.

CQRS gerçekte ne yapar?

Klasik yaklaşımda bir Order entity’n var, hem yazarken hem okurken aynı model. CQRS’te:

  • Command side: OrderCommand, validation, business rules. Output: state change event’i.
  • Query side: OrderView, sadece okuma için optimize edilmiş. Genelde ayrı tablo veya ayrı database.

İkisi arasında event bus veya direct sync. Command write yaptığında query store’u güncelleniyor.

İşe yaradığı 3 gerçek senaryo

1. Read ile write yükü çok farklı. Bir e-ticaret ürün katalogu: günde 10K write (yeni ürün, fiyat güncelleme), ama 10M read. Read-optimize edilmiş ayrı bir denormalized tablo yaparsan, query’ler 10-100x hızlanıyor. Write side normalize kalabilir.

Son büyük bir WooCommerce projesinde ürün katalogu read side’ını Redis + Elasticsearch’e çıkardık. Write side MySQL’de kaldı. Product search latency 1.5s’den 60ms’ye düştü.

2. Reporting ve analytics. Operational database’i raporlamak genelde felaket bir fikir. JOIN’ler yavaş, production trafiğini etkiliyor. CQRS ile analytics için ayrı bir OLAP store (BigQuery, ClickHouse, Snowflake) kurarsın, event’lerle beslersin. Raporlar operational performance’ı etkilemeden çalışır.

3. Complex business rules + simple read requirements. Finansal bir sistemde write side’da 50 validation kuralı var (regulatory compliance, fraud detection). Read side’da kullanıcı sadece “benim son 10 işlemim” görüyor. Bu iki model’i bir arada tutmak karmaşıklığı gereksiz yere artırıyor.

Overengineering olduğu 5 senaryo

1. Basit CRUD uygulamaları. Bir blog, bir admin paneli, bir form submission sistemi. Her yeri CQRS ile kurarsan 2 katı kod yazıyorsun ve hiçbir şey hızlanmıyor.

2. Read ile write yükü benzer olduğunda. Write/read ratio 1:3 veya daha az ise CQRS avantaj sağlamıyor. Ek event infrastructure maliyetini karşılamıyor.

3. Tek ekipli, küçük projelerde. CQRS iki model yönetmek, event pipeline kurmak, eventual consistency handle etmek demek. 3 kişilik ekip bu operational yükü taşıyamıyor.

4. Güçlü consistency gerektiğinde. Write’tan sonra hemen read lazım ise (“kullanıcı sipariş verdi, şimdi sipariş listesinde görmeli”) CQRS’in eventual consistency’si UX problem yaratıyor. Kullanıcıya “1-2 saniye beklemek” demek zor.

5. Prototip veya MVP aşamasında. Ürünün yaşayıp yaşamayacağı belli değilken 2 model sistemi kurmak para kaybı. Sonra simple CRUD’dan CQRS’e geçmek mümkün, tam tersi zor değil.

CQRS’siz benzeri avantajlar almanın yolları

CQRS’in tam karmaşıklığına girmeden benzeri fayda için:

Materialized views. PostgreSQL’in MATERIALIZED VIEW’ü veya MySQL’in denormalized tablosu. Write side aynı, ama read için optimize edilmiş görünüm. Gece batch refresh yeterli olabilir.

Read replicas. Database’in read-only kopyası. Ağır query’ler replica’ya, write’lar master’a. Tek model ama load ayrıştırılmış.

Cache layer. Redis veya Memcached’de read-heavy veriyi cache’le. Cache invalidation write sırasında. Tek model, ama sıcak data memory’de.

Bu 3 yaklaşım CQRS’in kazandırdığı performance advantage’ın %70-80’ini veriyor, operational complexity’nin %20’si ile.

CQRS’e geçiş yaparsan dikkat edilmesi gerekenler

  1. Event schema versiyonlama. Event’ler 5 yıl yaşayacak. Schema değişikliği backward compatible olmalı.
  2. Eventual consistency window. Read side write’tan kaç saniye sonra güncel? Bu UX’i nasıl etkiliyor?
  3. Replay stratejisi. Event’leri baştan replay etmek lazımsa infrastructure hazır mı? Re-materialize kaç saat sürüyor?
  4. Monitoring. Write ile read arasındaki sync lag’i izliyor musun? Lag 30 saniyeyi aştığında alarm var mı?
  5. Failure recovery. Event bus down olduğunda ne oluyor? Write side hâlâ çalışıyor ama read outdated. Kullanıcıya nasıl iletişim kuruyorsun?

Bu 5 konunun cevabı hazır değilse, CQRS daha kaos getirecek.

Pragmatik yaklaşım

Benim önerim: CQRS’i kısmi uygula. Tüm sistemde değil, performance bottleneck’i olan 2-3 kritik path’te.

Örnek: e-ticaret sisteminde order creation kritik write path (tight consistency), product catalog search kritik read path (high volume). Bu iki yeri CQRS ile kur. Geri kalan alan simple CRUD kalsın.

Böylece complexity’yi değer katan yerlere concentrate ediyorsun, her tarafa yaymıyorsun.

Sonuç

CQRS güçlü bir pattern ama silver bullet değil. Read/write yük farkı belirgin, farklı consistency gereksinimleri var, operational ekip taşıyabiliyor, ancak o zaman değer katıyor.

Basit projelerde materialized view, read replica, caching gibi daha hafif araçlar %80 benzer kazanç sağlıyor. Karar verirken hangi gerçek problem’i çözdüğünü sor. Cevap “aslında yok, ama cool geliyordu” ise uygulama.

Bu konuda bir projeniz mi var?

Kısa bir özet bırakın, 24 saat içinde size dönüş yapayım.

İletişime Geç