jdumont
CQRS with Commanded - Return directly from aggregate
Afternoon all, I’m back with another ES/CQRS question that’s perhaps more philosophical (for lack of a better word) than technical.
Event-sourcing with Elixir and @slashdotdash 's Commanded actually seems a little different than it is in other languages thanks to the BEAM. Each of the aggregates in our app actually exist as an individual process, and they hang around until they are stopped.
I have an aggregate in my app that builds workouts — I’m back on this CrossFit app — and whilst they are being created they exist as a process and my projection in the db is effectively a mirror, just with some computed fields added which aren’t relevant during the workouts creation. Once the status of a workout changes from "draft" to "published" I’ll be stopping the aggregate as-per Commanded’s docs and the latest post from Bruno, and just the projection of it should suffice.
However, whilst I’m building the workout, it would be really handy to just return the current state of it from the aggregate, rather than the projection. My projection literally just copies out the aggregates state and I don’t need to rely on the projection for unique validations, so I don’t see a huge difference in just returning the aggregate rather than the projection. It should be faster as eventual-consistency wouldn’t be an issue and there should be no issues with validating commands as I’m quite literally working from the canonical source of truth.
This is why my question is more philosophical than technical. What I’ve just described goes against CQRS as I understand it, but it seems to make more logical sense?
Most Liked
benwilson512
I think @slashdotdash 's explanation does a good job of noting why this is at odds with the traditional CQRS mantra of having distinct read and write models.
The approach I took with https://github.com/cargosense/fable leans slightly more towards what you’re asking for by eschewing CQRS in favor of a simpler implementation of Event Sourcing.
Basically you have database table, say “shipments”, and Fable guarantees that each event you emit for a given shipment row is handled serially by that shipment row. There may well be other database tables that are affected by that same event (containers or products in that shipment) and in that way the “shipments” table acts a lot like an aggregate. All changes to the shipments table and the containers table should happen because you cut an event, and then the event handler for that event makes changes to the various tables based on the event.
However with Fable as written today you still just read from the database normally when it comes to querying data, and it doesn’t push you to maintain a separate read vs write model. This is either a feature or a big deficiency depending on how wedded you are to CQRS.
Sadly Fable is still alpha stage and missing any useful documentation
Nonetheless I think there’s a “market” for a middle ground for a more minimalist library that supplies event sourcing guarantees without requiring buy in to the entire CQRS world view.
jdumont
I’m going to go ahead and answer myself after half an hour playing around with this idea…I shouldn’t / can’t return the state of the aggregate directly. Commanded doesn’t seem to allow for it, which must be for good reason.
This is why I’ve enjoyed working with CQRS so far, whilst there’s a lot more procedure, it keeps me from shooting myself in the foot! 
slashdotdash
Commanded allows you to directly access an aggregate’s state via the undocumented Commanded.Aggregates.Aggregate.aggregate_state/2 function:
alias Commanded.Aggregates.Aggregate
%BankAccount{..} = Aggregate.aggregate_state(BankAccount, account_number)
The reason why this isn’t exposed publicly is because an aggregate’s state should be an internal implementation detail. Instead, CQRS promotes the concept of two models: one for writes (aggregates) and one for reads (projections). Commands are handled by the write model and queries are handled by the read model.
In your example you have noticed that the projection (read model) and aggregate state (write model) are very similar, so it might save you some time and effort to use the aggregate state instead of creating a separate read model. This works until the needs of the two models starts to diverge, due to differing data access patterns. At which point you either migrate to a separate read model, or extend the aggregate state to store data which isn’t necessary for command handling. Investing the effort from the outset by implementing the two separate models should payoff as your model becomes richer in behaviour.
jdumont
Thanks for the reply, I’ll certainly take a look at Fable. I do agree that there’s an opportunity for an ES-lite option that doesn’t require a lot of the additional complexity that CQRS brings.
In my case I have tried to navigate that middle ground as there’s certainly bits of my app that don’t benefit from CQRS and even those that do wouldn’t be impossible without it. However, I’ve relented and gone “full ES/CQRS” just because it’s been enough of a stretch to understand the concepts without trying to work out which parts I need and which I don’t. I know that’s a terrible reason to adopt an architecture, but in the interest of flattening out my learning curve I thought it was a good idea.
My interest in the whole topic stemmed from the functional nature of event sourcing and how it suited the later parts of my app which are very easy to think about as a series of events (athletes completing workouts and movements). I found that without ES the app started taking a distinctly OO turn, starting to rely on lots of relations in the DB and even things that looked like class inheritance.
Event sourcing is a very simple pattern to understand and use, but I found that it was the persistence of the resulting state that complicated things. I like the idea of Fable and it certainly looks like it would be a good middle ground where the two models don’t need to be drastically different.







