CQRS (Command Query Responsibility Segregation) Nedir?

Sefik Can Kanber
4 min readFeb 5, 2021

CQRS, ana odağı write (yazma) ve read (okuma) sorumluluklarının ayrıştırılmasına dayanan bir mimari tasarım modelidir. CQRS mimarisi, CQS ilkesi baz alınarak kurulmuştur. CQS’in ana fikrinden bahsetmek gerekirse; bir metot objenin durumunu değiştirmelidir ya da geriye bir sonuç dönmelidir, ancak 2 işlemi birden yapmamalıdır. (Detaylı bilgi için bknz.)

Uygulamalarınızda CQRS mimari modeline göre oluşturursanız; uygulamanızın performansını, ölçeklenebilirliğini ve güvenliğini en üst düzeye çıkarabilirsiniz.

Bu yaklaşımda metotlar 2 farklı modele ayrılmalıdır:

  • Commands: Objenin veya sistemin durumunu değiştirir.
  • Queries: Sadece sonucu geriye döner herhangi bir objenin veya sistemin durumunu değiştirmez.

Commands

Yeni bir veri eklemek ya da var olan veri üzerinde güncelleme yapmak için kullanılır. Örnek vermek gerekirse; Insert, Update, Delete. Geriye veri döndürmez. Örnek olarak;

Queries

Veritabanından veri almak için kullanılır. Geriye sadece belirtilen modeli döner ve veri üzerinde herhangi bir değişiklik yapmaz. Oluşturacağımız Query’lerimiz genellikle ‘Get’ ön eki ile isimlendirilir. Örnek olarak;

CQRS Ne Zaman Kullanılmalı ?

  • Birbirinden ayrı sistemlerde olası bir servisin hata vermesi durumunda bu hatanın sistemin akışına olumsuz yönde etkisi olmuyorsa kullanılabilir.
  • Kompleks iş kurallarının olabileceği veya iş kurallarının sık sık değiştiği yapılarda kullanılabilir.
  • Yüksek veri trafiğinin olduğu sistemlerde kullanılabilir.

CQRS’i Ne Zaman Kullanmamalıyız ?

  • İş kurallarının basit ve çok değişmediği sistemlerde,
  • Basit CRUD işlemlerinin yapıldığı sistemlerde

CQRS kullanılması önerilmez.

CQRS’in Avantajları

  • Read ve write operasyonlarının ayrılması performansı, ölçeklenebilirliği ve güvenliği artırmaya yardımcı olabilir.
  • Read ve write işlemleriniz için farklı veritabanları kullanabilirsiniz.(Örneğin, yazma işlemleri için MySQL kullanırken okuma işlemleri için Couchbase kullanabilirsiniz).
  • Read ve write işlemleri ayrıldığı için, herhangi yapılacak bir read işleminde write işlemini beklemek zorunda kalmayız.
  • Her ekibin farklı Domain Logic’i üzerinde çalışabileceği bir yapı kurulmasına yardımcı olabilir.

CQRS’in Dezavantajları

  • Kod karmaşıklığını arttırır.
  • Event bazlı bir yapıya sahipseniz, uygulamanızın queue’da yer alan hataları ve tekrarlanan işlemleri yönetebilmesi gerekmektedir. Olası failover senaryolarını düşünmediğinizde veri kaybı veya daha büyük sorunlarla karşılaşabilirsiniz.

Örnek projemizi, .NET Core ile geliştireceğim ve MediatR kütüphanesini kullanacağım. Kısaca, MediatR’ın ne olduğundan ve MediatR ile kullandığımız Mediator Design Pattern’dan bahsedersek;

MediatR: Mediator Pattern’inin kullanılmasını sağlayan bir kütüphanedir.

Mediator Pattern: Aynı interface üzerinden türeyen nesneler arasındaki iletişimi, tek bir nokta üzerinden sağlar. Örnek vermek gerekirse; uçakların hepsi kule ile iletişime geçer, birbirleriyle doğrudan iletişime geçmezler. Bu örnekte, Mediator nesnesi kule, uçaklar da türeyen sınıflar diyebiliriz.

.Net Core Web Api projemizi oluşturup MediatR kütüphanesini ve bağımlılıklarını yükleyelim:

dotnet add package MediatR --version 9.0.0
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection --version 9.0.0

Startup sınıfında ConfigureServices metodunda MediatR’ı ekleyelim:
services.AddMediatR(typeof(Startup));

İlgili kütüphaneler yüklendikten sonra projemizin yapısı aşağıdaki şekilde olacaktır. Burada, yönetimin kolay olması için Queries, Handlers ve Commands dosyaları içinde ilgili sınıflar olacak şekilde geliştirme yapmaya çalıştım.

Örnek olarak, GetByIdQuery ve CreateCustomerCommand sınıflarımız ile bu sınıfları handle ettiğimiz GetByIdQueryHandler ve CreateCustomerHandler sınıflarımız aşağıdaki şekilde olacaktır.

Aşağıdaki, CustomersController’da yer alan endpointler bir request aldığı zaman MediatR, Send yardımıyla ilgili metot için yazılan handler’a request’i gönderir.

Peki oluşturduğumuz handler bu request’leri nasıl yakalayıp yönetebiliyor ?

Request için handler tanımı IRequestHandler ile yapılıyor. Ve bu interface’e TRequest,TResponse tipleri veriliyor.
Send metodu, ilgili tipte bir request gönderirse bunu ilgili handler yakalayacak şekilde yönetiyor.

Oluşturduğumuz projeden örnek vermek gerekirse;

GetCustomerByIdHandlers, IRequestHandler ile handler tanımlaması yapılıyor. Send burada yönetimi yaparken request’imiz olan GetCustomerByIdQuery’e bakıp hangi handler’a yönlendirmesi gerektiğine karar veriyor.

Event üzerinden işlemlerin yürütüldüğü sistemlerde transactional bağımlılık olmadığı için okuma ve yazma eylemleri birbirlerini beklemezler. Bu sebeple de CQRS altyapısı performansın önemli olduğu yerlerde kullanılmaktadır.

CQRS ile yazılım geliştirme maliyetli bir yöntemdir. Doğru yerde kullanılması halinde, geliştirilen sistemin bakımının yapılması ve sürdürülebilir şekilde olması daha kolay olacaktır. Bu sebeple, her yazılım geliştirme deseninde olduğu gibi gerektiği yerde kullanılması gerekmektedir.

Örnek olarak oluşturduğum projeye bu linkten ulaşabilirsiniz.

Faydalı olması dileğiyle.

İyi çalışmalar.

--

--