Sto prendendo in considerazione un progetto per migrare parte del nostro SOA basato su WCF su un modello di bus di servizio (probabilmente nServiceBus) e usando alcuni pub-sub di base per ottenere Comando-Query Separation .
Non sono nuovo per SOA, o anche per i modelli di bus di servizio, ma confesso che fino a poco tempo il mio concetto di "separazione" era limitato al mirroring e alla replica del database run-of-the-mill. Tuttavia, sono attratto dall'idea perché sembra fornire tutti i vantaggi di un sistema alla fine coerente mentre elimini molti degli ovvi inconvenienti (in particolare la mancanza di un adeguato supporto transazionale).
Ho letto molto sull'argomento di Udi Dahan che è fondamentalmente il the guru delle architetture ESB (almeno nel mondo Microsoft), ma una cosa che dice mi lascia perplesso:
As we get larger entities with more fields on them, we also get more actors working with those same entities, and the higher the likelihood that something will touch some attribute of them at any given time, increasing the number of concurrency conflicts.
[...]
A core element of CQRS is rethinking the design of the user interface to enable us to capture our users’ intent such that making a customer preferred is a different unit of work for the user than indicating that the customer has moved or that they’ve gotten married. Using an Excel-like UI for data changes doesn’t capture intent, as we saw above.
-- Udi Dahan, Clarified CQRS
Dalla prospettiva descritta nella citazione, è difficile discutere con quella logica. Ma sembra andare controcorrente rispetto alle SOA. Un SOA (e in generale i servizi in generale) dovrebbe occuparsi di messaggi a grana grossa in modo da ridurre al minimo le chatter di rete - tra molti altri vantaggi.
Mi rendo conto che le chatter di rete sono un problema minore quando si dispone di sistemi altamente distribuiti con un buon accodamento dei messaggi e nessuno dei bagagli di RPC, ma non sembra saggio smentire completamente il problema. Udi sembra quasi dire che ogni modifica di attributo (cioè l'aggiornamento del campo) dovrebbe essere il suo comando, che è difficile immaginare nel contesto di un utente che potenzialmente aggiorna centinaia o migliaia di entità e attributi combinati come spesso accade con un servizio web tradizionale.
Un aggiornamento batch in SQL Server può richiedere una frazione di secondo, data una buona query altamente parametrizzata, un parametro con valori di tabella o un inserimento di massa in una tabella di staging; l'elaborazione di tutti questi aggiornamenti uno alla volta è lento, lento, lento e l'hardware del database OLTP è il più costoso di tutti su scala / fuori.
C'è un modo per conciliare queste preoccupazioni in competizione? Ci sto pensando nel modo sbagliato? Questo problema ha una soluzione ben nota nel mondo CQS / ESB?
Se no, allora come si può decidere quale dovrebbe essere il "giusto livello" di granularità in un comando? C'è un punto "standard" che può essere utilizzato come punto di partenza - una specie di 3NF nei database - e deviare solo quando un'accurata profilazione suggerisce un beneficio prestazionale potenzialmente significativo?
O forse è una di quelle cose che, nonostante diverse opinioni forti espresse da vari esperti, è davvero solo una questione di opinione?