Pelo que entendi, a grande idéia por trás do CQRS é ter dois modelos de dados diferentes para manipular comandos e consultas. Eles são chamados de "modelo de gravação" e "modelo de leitura".
Vamos considerar um exemplo de clone de aplicativo do Twitter. Aqui estão os comandos:
- Os usuários podem se registrar.
CreateUserCommand(string username)emiteUserCreatedEvent - Os usuários podem seguir outros usuários.
FollowUserCommand(int userAId, int userBId)emiteUserFollowedEvent - Os usuários podem criar postagens.
CreatePostCommand(int userId, string text)emitePostCreatedEvent
Embora eu use o termo "evento" acima, não me refiro a eventos 'sourcing de eventos'. Quero dizer apenas sinais que acionam atualizações de modelo de leitura. Eu não tenho uma loja de eventos e até agora quero me concentrar no CQRS.
E aqui estão as perguntas:
- Um usuário precisa ver a lista de suas postagens.
GetPostsQuery(int userId) - Um usuário precisa ver a lista de seus seguidores.
GetFollowersQuery(int userId) - Um usuário precisa ver a lista de usuários a seguir.
GetFollowedUsersQuery(int userId) - Um usuário precisa ver o "feed de amigos" - um log de todas as atividades de seus amigos ("seu amigo John acabou de criar uma nova postagem").
GetFriedFeedRecordsQuery(int userId)
Para lidar CreateUserCommand, preciso saber se esse usuário já existe. Portanto, neste momento eu sei que meu modelo de gravação deve ter uma lista de todos os usuários.
Para lidar FollowUserCommand, preciso saber se o usuário A já segue o usuárioB ou não. Neste ponto, quero que meu modelo de gravação tenha uma lista de todas as conexões usuário-usuário-usuário.
E, finalmente, para lidar com CreatePostCommandisso, acho que não preciso de mais nada, porque não tenho comandos como UpdatePostCommand. Se eu os tivesse, precisaria garantir que a postagem exista, portanto, precisaria de uma lista de todas as postagens. Mas como não tenho esse requisito, não preciso rastrear todas as postagens.
Pergunta # 1 : é realmente correto usar o termo "modelo de gravação" da maneira que eu o uso? Ou "modelo de gravação" sempre significa "armazenamento de eventos" no caso de ES? Em caso afirmativo, existe algum tipo de separação entre os dados necessários para manipular comandos e os dados necessários para manipular consultas?
Para lidar GetPostsQuery, eu precisaria de uma lista de todas as postagens. Isso significa que meu modelo de leitura deve ter uma lista de todas as postagens. Vou manter esse modelo ouvindo PostCreatedEvent.
Para lidar com ambos GetFollowersQuerye GetFollowedUsersQuery, eu precisaria de uma lista de todas as conexões entre usuários. Para manter esse modelo, vou ouvir UserFollowedEvent. Aqui está uma pergunta 2 : é praticamente bom se eu usar a lista de conexões do modelo de gravação aqui? Ou devo criar melhor um modelo de leitura separado, porque no futuro posso precisar de mais detalhes do que o modelo de gravação?
Finalmente, para lidar, GetFriendFeedRecordsQueryeu precisaria:
- Ouvir
UserFollowedEvent - Ouvir
PostCreatedEvent - Saiba quais usuários seguem quais outros usuários
Se o usuário A seguir o usuário B e o usuário B começar a seguir o usuário C, os seguintes registros deverão aparecer:
- Para o usuário A: "Seu amigo usuário B acabou de começar a seguir o usuário C"
- Para o usuário B: "Você começou a seguir o usuário C"
- Para o usuário C: "O usuário B agora está seguindo você"
Aqui está a pergunta nº 3 : qual modelo devo usar para obter a lista de conexões? Devo usar o modelo de gravação? Devo usar o modelo de leitura - GetFollowersQuery/ GetFollowedUsersQuery? Ou devo fazer o GetFriendFeedRecordsQuerypróprio modelo manipular UserFollowedEvente manter sua própria lista de todas as conexões?