A quanto ho capito, l'idea alla base di CQRS è avere 2 diversi modelli di dati per la gestione di comandi e query. Questi sono chiamati "modello di scrittura" e "modello di lettura".
Consideriamo un esempio del clone dell'applicazione Twitter. Ecco i comandi:
- Gli utenti possono registrarsi.
CreateUserCommand(string username)
emetteUserCreatedEvent
- Gli utenti possono seguire altri utenti.
FollowUserCommand(int userAId, int userBId)
emetteUserFollowedEvent
- Gli utenti possono creare post.
CreatePostCommand(int userId, string text)
emettePostCreatedEvent
Mentre uso il termine "evento" sopra, non intendo eventi di "sourcing di eventi". Intendo solo segnali che attivano gli aggiornamenti del modello di lettura. Non ho un negozio di eventi e finora voglio concentrarmi sullo stesso CQRS.
Ed ecco le domande:
- Un utente deve vedere l'elenco dei suoi post.
GetPostsQuery(int userId)
- Un utente deve vedere l'elenco dei suoi follower.
GetFollowersQuery(int userId)
- Un utente deve vedere l'elenco degli utenti che segue.
GetFollowedUsersQuery(int userId)
- Un utente deve vedere il "feed degli amici", un registro di tutte le attività dei suoi amici ("il tuo amico John ha appena creato un nuovo post").
GetFriedFeedRecordsQuery(int userId)
Per gestire CreateUserCommand
ho bisogno di sapere se un tale utente esiste già. Quindi, a questo punto, so che il mio modello di scrittura dovrebbe avere un elenco di tutti gli utenti.
Per gestire FollowUserCommand
ho bisogno di sapere se userA segue già userB oppure no. A questo punto voglio che il mio modello di scrittura abbia un elenco di tutte le connessioni user-follow-user.
E infine, per gestire CreatePostCommand
non penso di aver bisogno di nient'altro, perché non ho comandi simili UpdatePostCommand
. Se avessi quelle, avrei bisogno di assicurarmi che quel post esistesse, quindi avrei bisogno di un elenco di tutti i post. Ma poiché non ho questo requisito, non ho bisogno di tenere traccia di tutti i post.
Domanda n. 1 : è effettivamente corretto usare il termine "modello di scrittura" nel modo in cui lo uso? Oppure "scrivi modello" significa sempre "negozio di eventi" in caso di ES? In tal caso, esiste un tipo di separazione tra i dati di cui ho bisogno per gestire i comandi e quelli di cui ho bisogno per gestire le query?
Per gestire GetPostsQuery
, avrei bisogno di un elenco di tutti i post. Ciò significa che il mio modello di lettura dovrebbe avere un elenco di tutti i post. Manterrò questo modello ascoltando PostCreatedEvent
.
Per gestire entrambi GetFollowersQuery
e GetFollowedUsersQuery
, avrei bisogno di un elenco di tutte le connessioni tra utenti. Per mantenere questo modello ho intenzione di ascoltare UserFollowedEvent
. Ecco una domanda n. 2 : è praticamente OK se uso l'elenco delle connessioni del modello di scrittura qui? O dovrei creare un modello di lettura separato, perché in futuro potrei aver bisogno di avere più dettagli rispetto al modello di scrittura?
Infine, per gestire GetFriendFeedRecordsQuery
avrei bisogno di:
- Ascoltare
UserFollowedEvent
- Ascoltare
PostCreatedEvent
- Scopri quali utenti seguono quali altri utenti
Se l'utente A segue l'utente B e l'utente B inizia a seguire l'utente C, devono essere visualizzati i seguenti record:
- Per l'utente A: "Il tuo amico utente B ha appena iniziato a seguire l'utente C"
- Per l'utente B: "Hai appena iniziato a seguire l'utente C"
- Per l'utente C: "L'utente B ora ti sta seguendo"
Ecco la domanda n. 3 : quale modello dovrei usare per ottenere l'elenco delle connessioni? Dovrei usare il modello di scrittura? Dovrei usare read model - GetFollowersQuery
/ GetFollowedUsersQuery
? O dovrei fare in modo che il GetFriendFeedRecordsQuery
modello stesso gestisca UserFollowedEvent
e mantenga il proprio elenco di tutte le connessioni?