DDD'siz ve (veya?) ES olmayan CQRS - yazma modeli nedir ve okuma modeli nedir?


11

Anladığım kadarıyla, CQRS'nin arkasındaki büyük fikir, komutları ve sorguları işlemek için 2 farklı veri modeline sahip olmak. Bunlara "model yazma" ve "model okuma" denir.

Twitter uygulama klonunun bir örneğini ele alalım. İşte komutlar:

  • Kullanıcılar kendilerini kaydedebilirler. CreateUserCommand(string username)yayarUserCreatedEvent
  • Kullanıcılar diğer kullanıcıları takip edebilir. FollowUserCommand(int userAId, int userBId)yayarUserFollowedEvent
  • Kullanıcılar yayın oluşturabilir. CreatePostCommand(int userId, string text)yayarPostCreatedEvent

Yukarıdaki "etkinlik" terimini kullanırken, "etkinlik kaynak bulma" etkinliklerinden bahsetmiyorum. Sadece okuma modeli güncellemelerini tetikleyen sinyalleri kastediyorum. Bir etkinlik mağazam yok ve şimdiye kadar CQRS'nin kendisine odaklanmak istiyorum.

Ve işte sorgular:

  • Bir kullanıcının yayınlarının listesini görmesi gerekir. GetPostsQuery(int userId)
  • Bir kullanıcının takipçilerinin listesini görmesi gerekir. GetFollowersQuery(int userId)
  • Bir kullanıcının takip ettiği kullanıcıların listesini görmesi gerekir. GetFollowedUsersQuery(int userId)
  • Bir kullanıcının "arkadaş özet akışını" görmesi gerekir - tüm arkadaşlarının etkinliklerinin bir günlüğü ("arkadaşınız John yeni bir gönderi oluşturdu"). GetFriedFeedRecordsQuery(int userId)

Bu CreateUserCommandtür bir kullanıcının zaten var olup olmadığını bilmek gerekir. Bu noktada, yazma modelimin tüm kullanıcıların bir listesine sahip olması gerektiğini biliyorum.

İşlemek için FollowUserCommandben userA zaten userB izler olup olmadığını bilmek gerekir. Bu noktada yazma modelimin tüm kullanıcı-takip-kullanıcı bağlantılarının bir listesini olmasını istiyorum.

Ve son olarak, CreatePostCommandbaşka bir şeye ihtiyacım olduğunu düşünmüyorum, çünkü benim gibi komutlarım yok UpdatePostCommand. Bunlara sahip olsaydım, yazının var olduğundan emin olmalıyım, bu yüzden tüm yayınların bir listesine ihtiyacım olacaktı. Ancak bu gereksinime sahip olmadığım için, tüm yayınları izlememe gerek yok.

Soru # 1 : "Yazım modeli" terimini kullandığım şekilde kullanmak doğru mu? Yoksa "yazma modeli" ES durumunda her zaman "etkinlik deposu" anlamına mı gelir? Eğer öyleyse, komutları işlemem gereken veriler ile sorguları işlemem gereken veriler arasında herhangi bir ayrım var mı?

İşlemek için GetPostsQuerytüm yayınların bir listesine ihtiyacım var. Bu, okuma modelimin tüm yayınların bir listesine sahip olması gerektiği anlamına gelir. Dinleyerek bu modeli koruyacağım PostCreatedEvent.

Her iki işlemek için GetFollowersQueryve GetFollowedUsersQueryben kullanıcılar arasındaki tüm bağlantıların bir listesini gerekir. Bu modeli korumak için dinleyeceğim UserFollowedEvent. İşte bir Soru # 2 : Burada yazma modelinin bağlantı listesini kullanırsam pratikte sorun olmaz mı? Ya da ayrı bir okuma modeli oluşturmalıyım, çünkü gelecekte yazma modelinden daha fazla ayrıntıya sahip olmak isteyebilir miyim?

Son olarak, işlemek GetFriendFeedRecordsQueryiçin:

  • Dinlemek UserFollowedEvent
  • Dinlemek PostCreatedEvent
  • Hangi kullanıcıların hangi kullanıcıları takip ettiğini bilin

A kullanıcısı B kullanıcısını takip ederse ve B kullanıcısı C kullanıcısını takip etmeye başlarsa, aşağıdaki kayıtlar görünmelidir:

  • A kullanıcısı için: "Arkadaş B kullanıcısı C kullanıcısını izlemeye yeni başladı"
  • B kullanıcısı için: "C kullanıcısını yeni kullanmaya başladınız"
  • C kullanıcısı için: "B kullanıcısı sizi takip ediyor"

İşte Soru # 3 : Bağlantıların listesini almak için hangi modeli kullanmalıyım? Yazma modelini kullanmalı mıyım? Okuma modeli kullanmalı mıyım - GetFollowersQuery/ GetFollowedUsersQuery? Ya da GetFriendFeedRecordsQuerymodelin UserFollowedEventtüm bağlantılar listesini kendi idare etmesini ve korumasını sağlamalı mıyım ?


CQRS sistemlerinde, Sorgu veri modeli ve Komut veri modelinin farklı veri tabanlarından veri tüketebileceğini unutmayın. Ve her iki model de birbirinden bağımsız yaşıyor olabilir (farklı uygulamalar). Olduğu söyleniyor, cevap "bağlıdır" (her zamanki gibi). İlginizi
Laiv

Yanıtlar:


7

Greg Young (2010)

CQRS, daha önce yalnızca bir tanesinin bulunduğu iki nesnenin oluşturulmasıdır.

Bertrand Meyer'in Komut Sorgu Ayrımı açısından düşünürseniz, modelin biri komutları destekleyen ve diğeri sorguları destekleyen iki ayrı arabirime sahip olduğunu düşünebilirsiniz.

interface IChangeTheModel {
    void createUser(string username)
    void followUser(int userAId, int userBId)
    void createPost(int userId, string text)
}

interface IDontChangeTheModel {
    Iterable<Post> getPosts(int userId)
    Iterable<Follower> getFollowers(int userId)
    Iterable<FollowedUser> getFollowedUsers(int userId)
}

class TheModel implements IChangeTheModel, IDontChangeTheModel {
    // ...
}

Greg Young'un görüşü, bunu iki ayrı nesneye ayırabileceğinizdi

class WriteModel implements IChangeTheModel { ... }
class ReadModel  implements IDontChangeTheModel {...}

Nesneleri ayırdıktan sonra, artık nesne durumunu bellekte tutan veri yapılarını ayırma seçeneğiniz vardır, böylece her durum için optimize edebilirsiniz; veya okuma durumunu yazma durumundan ayrı olarak saklayın / devam ettirin.

Soru # 1: "Yazım modeli" terimini kullandığım şekilde kullanmak doğru mu? Yoksa "yazma modeli" ES durumunda her zaman "etkinlik deposu" anlamına mı gelir? Eğer öyleyse, komutları işlemem gereken veriler ile sorguları işlemem gereken veriler arasında herhangi bir ayrım var mı?

WriteModel terimi genellikle modelin değiştirilebilir temsili olarak anlaşılır (yani: kalıcılık deposu değil nesne).

TL; DR: Bence kullanımınız iyi.

İşte bir Soru # 2: Burada yazma modelinin bağlantı listesini kullanırsam pratikte sorun olmaz mı?

Bu "iyi" - ish. Kavramsal olarak, aynı yapıları paylaşan okuma modeli ve yazma modeli ile ilgili yanlış bir şey yoktur.

Uygulamada, modele yazma işlemleri tipik olarak atomik olmadığından, bir iş parçacığı ikinci bir iş parçacığı onu okumaya çalışırken modelin durumunu değiştirmeye çalışırken bir sorun olabilir.

İşte Soru # 3: Bağlantıların listesini almak için hangi modeli kullanmalıyım? Yazma modelini kullanmalı mıyım? Ben okuma modeli kullanmalıyım - GetFollowersQuery / GetFollowedUsersQuery? Yoksa GetFriendFeedRecordsQuery modelinin kendisi UserFollowedEvent'i işlemeli ve tüm bağlantıların kendi listesini tutmalı mıyım?

Yazma modelini kullanmak yanlış cevaptır.

Her birinin belirli bir kullanım durumuna göre ayarlandığı birden fazla okuma modeli yazmak tamamen mantıklıdır. Biz, "okuma modeli" demek, ama orada belirli bir kullanım durumunda için optimize edilmiş, her biri birçok okuma modelleri, olabilir ve yok anlaşılmaktadır değil o mantıklı değil vakaları uygulamak.

Örneğin, bazı sorguları desteklemek için bir anahtar / değer deposu ve diğer sorgular için bir grafik veritabanı veya bu sorgu modelinin anlamlı olduğu ilişkisel bir veritabanı kullanmaya karar verebilirsiniz. Kurslar için atlar.

Deseni hala öğrendiğiniz özel durumunuzda, önerim tasarımınızı "basit" tutmak olacaktır - yazma modelinin veri yapısını paylaşmayan bir okuma modeline sahip olmak.


1

Kavramsal bir veri modeliniz olduğunu düşünmenizi tavsiye ederim.

Daha sonra yazma modeli, işlemsel güncellemeler için optimize edilmiş olan bu veri modelinin bir materyalizasyonudur. Bazen bu normalleştirilmiş ilişkisel veritabanı anlamına gelir.

Okuma modeli, uygulamalarınızın ihtiyaç duyduğu sorguları gerçekleştirmek için optimize edilmiş aynı veri modelinin gerçekleştirilmesidir. Daha az birleşme içeren sorguları işlemek için amaçlı olarak normalleştirilmemiş olsa da yine de ilişkisel bir veritabanı olabilir.


(# 1) CQRS için yazma modelinin bir olay deposu olması gerekmez.

(# 2) Okuma modelinin yazma modelinde olmayan bir şeyi saklamasını beklemem, çünkü CQRS'de hiç kimse, okuma modelini, değişikliklerle senkronize tutan yönlendirme mekanizması dışında okuma modelini güncellemez. yazma modeli.

(# 3) CQRS'de, sorgular okuma modeline aykırı olmalıdır. Farklı yapabilirsiniz: tamam, sadece CQRS'yi takip etmiyorum.


Özetle, sadece bir kavramsal veri modeli vardır. CQRS, komut ağını ve yeteneklerini sorgu ağından ve yeteneklerinden ayırır. Ayrılma göz önüne alındığında, yazma modeli ve okuma modeli performans optimizasyonu olarak çok farklı teknolojiler kullanılarak barındırılabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.