Basit bir CRUD uygulamasında “CQRS uyguladık” denen bir kod tabanı gördüm. Tek bir “kullanıcı oluştur” işlemi için bir Command, bir CommandHandler, ayrı bir okuma modeli ve bir projection vardı. Bütün bu tören, sonunda tek bir satır INSERT ediyordu.

CQRS bazı sistemlerde gerçek bir netlik kazandırır. Bu uygulamada kazandırdığı tek şey, iki kat koddu.

CQRS nedir, kısaca

CQRS — Command Query Responsibility Segregation — tek bir fikre dayanır: yazma modeli ile okuma modelini birbirinden ayırmak.

Klasik yaklaşımda tek bir model hem yazılır hem okunur — aynı Order sınıfıyla hem sipariş oluşturulur hem ekranda gösterilir. CQRS bunu ikiye böler: yazma tarafı kuralları zorlayan, normalize bir model; okuma tarafı ekrana göre şekillenmiş, denormalize bir model.

Dikkat: bu mutlaka iki veritabanı demek değildir. Çoğu zaman iki model demektir — aynı veritabanında bile olabilir.

Read replica ile karıştırmayın

Sık yapılan bir karışıklık: CQRS ile read replica aynı şey sanılır. Değiller.

  • Read replica (read/write splitting) bir altyapı kararıdır: aynı model, farklı sunucu. Okuma yükünü ölçeklemek için.
  • CQRS bir modelleme kararıdır: farklı model, aynı ya da farklı yer. Okuma ile yazmanın şekli ayrıştığı için.

Birini diğeri olmadan kullanabilirsiniz. Read replica’nız olur ama tek modeliniz vardır; ya da CQRS yaparsınız ama tek sunucuda.

CQRS neyi kazandırır

CQRS, yazma modeli ile okuma modeli gerçekten ayrıştığında değer katar. Bu, karmaşık domain’lerde olur: yazdığınız şekil ile okuduğunuz şekil birbirinden uzaklaşır.

Yazma tarafı normalize, değişmezleri (invariant) zorlayan, iş kurallarıyla yüklü bir modeldir. Okuma tarafı ise ekranların ihtiyacına göre düzleştirilmiş, önceden hesaplanmış, hızlı sorgulanan bir modeldir. İkisini tek bir model olmaya zorlamak, ikisini de orta karar yapar.

Basit CRUD’da gereksiz yük

Sorun şu: basit bir CRUD uygulamasında yazma modeli ile okuma modeli zaten aynıdır — ikisi de o satırın kendisi. Orada CQRS uygulamak, var olmayan bir ayrımı modellemektir.

Sonuç: iki model, senkron tutulması gereken iki yapı, iki kat kod — ve karşılığında sıfır kazanç. Bu, spekülatif genelliğin desen ölçeğindeki hâlidir: bugün olmayan bir karmaşıklık için bugünden bedel ödemek.

Hafif CQRS

CQRS “yapmak” için event sourcing’e, ayrı veritabanlarına, projection altyapısına ihtiyacınız yok. Bunlar CQRS’in en ağır biçimidir, zorunlu hâli değil.

Hafif bir başlangıç: yazma tarafını normal Eloquent modelleriyle bırakın, okuma tarafı için ekrana göre şekillenmiş bir DTO döndüren ayrı bir sorgu sınıfı yazın. Yazma ile okuma yolu kodda ayrılmıştır — bu zaten CQRS’in özüdür. Ağır altyapıya ancak gerçekten gerektiğinde geçin.

Ne zaman gerçekten gerekli

CQRS’i ciddiye almak için şu sinyaller olmalı:

  • Domain karmaşıklığı yüksek — yazma tarafı ciddi iş kuralları taşıyor (Clean Architecture’ın değer kattığı türden bir domain).
  • Okuma ile yazmanın şekli ve yükü belirgin biçimde farklı.
  • Çoğu zaman event-driven mimari ile birlikte — okuma modeli, yazma tarafının yaydığı event’lerle güncelleniyor.

Bu sinyaller yoksa, tek model ve gerektiğinde ayrı bir okuma sorgusu fazlasıyla yeter.


CQRS bir olgunluk rozeti değil, belirli bir problemin — okuma ile yazmanın gerçekten ayrışması — çözümüdür. O problem sizde yoksa, kazandırdığı tek şey ikinci bir modeli senkron tutma zahmetidir.

Modeli ayırmadan önce, okuma ile yazmanızın gerçekten ayrı olup olmadığına bakın.