Then, for a traditional relational DB, it is 'normal' to define a view using SQL and as they are merely
functions over what is stored rather than additional copies, having multiple views of the same
data does not introduce any new issues. However it also does not give us the performance
boost we hope for. What we are thinking about is to do the filtering/joining/arranging up front
in an eager manner so that when the query comes in it runs quickly.
To get that we would need some sort of
maintain-view-as-a-cache-table option in the datastore.
We also might desire to make these read only views distributed/shared (via Events)
and maintained and scaled 'locally' to the query microservices.
If that maintain-view-as-a-cache-table option did not exist then we are down to
user code to maintain that Reporting Database cache table for the Query.
When does that code get run?
...when 'poked' by an Event.
There is no point in the event
just saying 'something has changed' so the Event has to be particular to the row/tuple that has
changed.
There are choices for what domain the Event is in terms of, i.e. how 'raw' it is, it could be at the level of:
1.The Command service's triggering API Point of View [This is the command+parms that occurred]
2.The Command internally generating a data model event [So not necessarily Command specific but still in the users app data model domain of entities rather than raw tables]
3.The datastore table changes [So particular raw 'normalised' values have changed]
4.Something close to the tuple that is present in the view that is consuming the event
Notes:
Level 1. If the Command was event driven 1. is easily available but consuming would mean duplicating the
early logic of the command so seems like a bad option.
Level 2. Sounds like me rephrasing what you were saying - in that this could be considered
part of the Command services interface that it emits these events based on the Command
logic's outcome/path.
Level 3. How would this work if a command updated multiple elements (columns or rows) -
it would only be sensible to generate these in 'lumps' - perhaps demarcated by the end of
command event processing or some micro-txn? Views would have to subscribe to these.
Level 4. This is similar to 3 but the system does the subscription based on the submitted
view definitions. This is the Event equivalent of a ReportingDatabase as there could be >1
view based synthetic event, each 'sent' to remote event sourced view databases.
On pondering this, it appears to me that only 2 and 4 can be argued for with any
structure, but which is best?
Thinking about what you said, mostly 2, but in the context (CQRS) I think it is CQRS that actually
helps solve this problem:
Perhaps there are two types of event -
those that are used to feed further sub-commands and active services
Command destined Events
and those that are used to feed passive state distribution for query consumption.
Query destined Events (i.e. feeding Event sourced RepostingDatabases)
For the Events which trigger actions and further commands what you said about
"
lose the intent of the event
...you still have to write code that manually reserve engineers
events from state changes, and this can be an error prone and tedious process"
makes sense - so it seems we want to keep the flow of such events in terms
of the application domain data model verbs
(which may be close to the commands service's triggering interface for simple commands)
But for query supporting views maintenance - if this is all we had we would need subscribing
logic to catch these (normalised/vanilla) data model verbs events and translate
these to the particular view - but this code would add little value. It might have to
catch multiple events and has to track the logic of any view definition (for event sourced
views it IS the operational view definition (expressed in code). The generation of these types of Events
and the processing of them could perhaps be automated by the middleware and this would
be CQRS value add.
So to net this out :-)
I am basically persuaded by what you said but
the discussion has generated, for me, something I have been looking out for - perhaps a
potential concrete MicroProfile CQRS feature on:
Maintenance of ReportingDatabases (Query supporting views):
a specific class of Event that allowed for their distributed (event sourced)
maintenance. The generation and consumption
of those events to be automated value add
via the MicroProfile Reactive Messaging (Kafka etc)
spec. Triggering generation of these at the correct point
without it being done by user code is an interesting problem
but one that would indeed be easier to solve if I could have a
tailable cursor/trigger as a stream source.
I will go and have a read on what other systems (Axon etc) do in this
space.
Thanks for your thoughtful and persuasive reply James.
in fact I read
here/
here after typing most of the above and I
think that I have arrived, eventually, at a similar conclusion.
I really like the idea of the generation of Events
occurring via a txn isolated write to the database
(in an Event log table) and thus subject to
commit/rollback in the same txn as the data update
before being cascaded.
Some generated events (sub-commands) we want to send out
inside any local txn and some generated events we only want to
send out if the local work 'commits'/ends unexceptionally. cf
this
I wonder if these two types of Events correlate with Command-feeding-Events
and Query-feeding-Events?
Gordon.