Merhaba,

Bugün CQRS ‘den bahsedeceğim. Yeni projemizle beraber özellikle Clean Architecture, async ve bunlarla beraber CQRS üzerine yoğunlaşmışken, konuyla ilgili öğrendiklerimi yazıya dökmek istedim.

Bir junior olarak öğreneceğim her yeni kavramda sorduğum ilk soru: “Neden X’e ihtiyacımız var ?” oluyor. “Öncesinde ne kullanılıyordu, X’in eksik kaldığı noktalar nelerdi, projemize neler katacak ya da neleri değiştirecek ?” sorularına cevap bulmadan (bazen kafama yatması uzun sürse bile :))ilerlemiyorum çünkü neyi neden kullanacağımı bilmeden kodlamayı sağlıklı bulmuyorum. Dolayısıyla, CQRS için de, önce bu sorulara cevap vereceğim, daha sonra konuyu detaylandıracağım.

CQRS’ e neden ihtiyacımız olduğuyla başlayalım : uygulama ne kadar kompleks olursa geleneksel yazılım mimarileri & modelleri, sürekli gelişmekte ve değişmekte olan piyasa ihtiyaçlarını karşılamak konusunda o kadar eksik kalıyor ya da karşılarken zaman,maliyet, scalability (ölçeklenebilirlik),traceability (izlenebilirlik) gibi birçok önemli özellikten ödün verilmesine neden oluyor. Bu dinamik pazarda rekabet edebilmek için de uygulamaların geleneksel yöntemlere alternatif daha esnek, daha bağımsız ; zaman, maliyet, dependency gibi metrikleri dikkate alan daha yeni yapılar kullanması (zaman zaman geçiş yapması) gerekebiliyor. CQRS (Command and Query Responsibility Segregation), adının birebir karşılığı olarak, command ve query’leri ayırmamız gerektiğini söylüyor. Daha açık olmak gerekirse, aynı data modeli üzerinde hem query hem CRUD operasyonları yapılması yerine datanın okunduğu ve yazıldığı modelleri birbirinden ayırıyor. Read işlemleri için ayrı write işlemleri için ayrı data modellerinin kullanılması prensibini benimsiyor.

Peki bu yapıyı kullanmazsak uygulamamız neler kaybeder ? Öncelikle CQRS’in hangi senaryolarda avantaj sağladığına değinelim :

  • Proje büyük ve kompleks operasyonlar içeriyorsa,
  • Business logic değişken ise ; projenin heading noktası tam olarak bilinmiyorsa,
  • Bir takımın yazma modelinin parçası olan karmaşık etki alanı modeline, başka bir takımın da okuma modeline ve kullanıcı arabirimlerine odaklanabileceği senaryolar,
  • Scalability (ölçeklenebilirlik) sorunları varsa,
  • Eğer uygulama write-oriented ise ; yani bizim uygulamamız kendi datasını okumuyorsa, bu işi bizim yerimize başka uygulamalar yapıyorsa,
  • Diğer sistemlerle entegre çalışan, alt sistemlerdeki geçici arızaların diğerlerinin kullanılabilirliğini etkilememesi gereken bir uygulamaysa.

Yukarıdaki durumlarda zaman zaman data modelleri yetersiz kalabilir. Ancak, CQRS sayesinde domain ve infrastructure katmanları karıştırılmadan yönetilebilir.

Microsoft bu durumlardan bazılarını ve sonuçlarını şu şekilde açıklamış :

https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs

  • Ek sütunlar ya da bir işlemin parçası olmayan ancak doğru şekilde güncellenmesi gereken propertyler : bu gibi verilerin read ve write gösterimleri arasında genellikle bir uyumsuzluk olabilir,
  • Komutlar (commands) sync olarak işlenmek yerine, async olarak işlenmek için queue’de olabilir,
  • Her entitiy, verileri yanlış contex’te gösterebilecek read ve write işlemlerine tabidir ;bu da güvenlik ve yetki (security & permission) işlemlerini yönetmeyi zorlaştırabilir,
  • İşlemler aynı data set üzerinde paralel olarak gerçekleştiğinde veri uyumsuzluğu (data contention) ortaya çıkabilir,
  • Geleneksel yaklaşım, data store ve data access layer üzerindeki yük ve bilgi almak için gereken sorguların kompleksliği nedeniyle performans üzerinde olumsuz bir etkiye sahip olabilir.

İşte CQRS pattern bu durumlara bir çözümdür. Evet bir patterndir ; command ve query sorumluluklarını genelleştirilmiş ve sistematik bir yapı ile read & write data modelleri üzerine yükler ve ayrı ayrı yürütür.

CQRS kullanımının uygun olmadığı bazı case’ler ise aşağıda verilmiştir :

  • Eğer projemiz basit CRUD operasyonlarını içeriyorsa CQRS kullanmak gereksiz yere karmaşıklığı arttırabilir. Bu yüzden uygulamanın senaryosu dikkate alınmalı ve kompleks işlemlerin olmadığı yerlerde CQRS kullanılmamalıdır. Ayrıca CQRS yapısı tüm mimaride kullanılmak zorunda değildir. Büyük bir yazılım mimarisinin alt gruplarında, daha küçük parçalarında ihtiyaca yönelik olarak kullanılabilir.
  • CQRS mantık olarak oldukça basit görünse de, uygulamayı daha karşmaşık hale getirebilir. Kullanımında bu durum göz önünde bulundurulmalı ve senaryo iyi analiz edilmelidir..
  • Read data modeli write modelindeki değişiklikleri yansıtacak şekilde güncellenmelidir. Kullanıcının eski okuma verilerine dayalı bir request’i bu durumu olduğunda tespit etmek zor olabilir.Yani , CQRS de tutarlılık sağlanmalıdır.

Sonuç olarak CQRS command ve query sorumluluklarını birbirinden ayıran, kompleks projelerde, sürekli değişen business logic’lerinde kullanılan bir patterndir. Uygulamanın performansını, ölçeklenebilirliğini ve güvenliğini arttırır.

Mathematical Engineer & Software Developer | www.linkedin.com/in/beyza-celep

Mathematical Engineer & Software Developer | www.linkedin.com/in/beyza-celep