In the examples given in both series of blog posts on projections, streams are categories (“ponies”, “github-commits”, “strategy”), which may then be partitioned into more specific streams. As far as I can tell there are a couple of potential problems with this:
If commands need to know the current state of an aggregate to calculate the outcome of a command then the command service will need some sort of cache of the current state of all the aggregates, to avoid having to read in all events in the category for every command to find the current state.
If the write service is scaled horizontally (i.e. multiple writers) then either writes need to use ExpectedVersion.Any, or otherwise they rely on subscribing to all events from other writers to keep track of the current version.
Some possible solutions to these issues are:
a) Use a separate stream name for each aggregate (projections may still be used to aggregate streams within a category). (1) is then solved because each aggregate can be rebuilt at the time of each command from its own stream. (2) is partly solved as simultaneous commands on the same aggregate are less likely than simultaneous writes on the same category, though it will still sometimes happen unless writers are sharded by aggregate.
b) The reverse of the above, use a stream per category but then use projections to create a stream per aggregate. This mostly solves (1), but not (2).
c) Combine command and query services, and then keep a shared in-memory read model for use by both commands and queries. This solves (1) because commands can use the same cached read view as the queries, and (2) is somewhat solved because the command services are now reusing the same subscriber logic as the query service to keep track of the current version. Though even then simultaneous writes are possible, which will still result in expected version exceptions.
d) Avoid commands that need to know the current state of the aggregate, which can solve (1) - e.g. changing a name could be considered to always succeed, without needing to check the current state of the aggregate.
d) Avoiding multiple writers and only scale query services solves (2), but this may not always be possible or desirable for scalability or reliability reasons.
Is there some other solution? Is there any recommended best practice?
Finally, FWIW I’ve seen multiple people make the same mistake as me and not enabling projections at the command line before trying them out, and then being confused as to why their projection doesn’t work. Maybe the need to use a special command line argument should be made more prominent somehow, perhaps with a message in the UI?