NooB Questions

Hi

Apologies in advance, I have tried to find the answers to these questions but haven’t succeeded so decided to ask them here…

I’m currently in the process of evaluating CQRS as a pattern, and Axon Framework as a framework to support that.

I have managed to put together a working example based on snippets of code from around the web using MongoDB as the event store so have a reasonable idea what is going on.

The specific questions are more related to best practice and wondered if anyone could give me some advice:

Q1. A lot of sample code I have seen spends a lot of time handling the commands and generating/handling events, but seems to skip over the read side of the pattern.

What is the best practice for building a read-model that queries can operate against?
Is it to use tables in an RDBMS to denormalise the aggregate into a form that is applicable to the readers?
If I update an RDBMS table in the event handler (annotated with @EventSourcingHandler) what happens if the event or write to the RDBMS fails? How do I best handle that?

Q2. When I execute a command the aggregate is rebuilt from all of the domain events to-date. If I have an update of the RDBMS read model in each event handler as well (based on the question above) it will be doing lots of potentially un-necessary inserts/updates.

Is that just a side-effect of the pattern that this needs to happen, because the aggregate is always built from prior domain events first?
I understand that if you need to recreate the read-model from the stored domain events then that’s all needed, but for just applying just one more event seems overkill.
Is snapshotting the best way around this (so that the read-model is recreated with less events)?

Thanks Steve

Hi Steve,

No apologies necessary if you’d ask me, you should be able to answer simple questions as well.

Now, to answering them:

  1. I’ll chop this answer up in several bits, as you’re asking multiple things as well:

  2. There is not necessarily one best practice, as how you set up your read model is up to the needs of your queries. Do you want to store a view object to be easily pulled for your front-end? Then a denormalized view in (maybe) a JSON format makes sense. Is your query side a search engine, like Elastic Search? Then you’ll most likely have different requirements from the example above. Additionally, your view model is not required to be a one-to-one copy of your aggregate. It might just as well be an accumulation of several aggregates, or just a subset of events from your aggregate.

  3. Note that you’ll not use @EventSourcingHandler in your query side. That annotation is typically used to annotated the handlers in your Command Model / Aggregate from which you’ll source it.

  4. What do you exactly mean with ‘an event fails’? Which part fails where? The first thing Axon tries to do once an event is applied, is store it. All consecutive usages of that event, so the event handlers, which might fail, is the event handling code failing, not your event.

  5. A failure of storing your view models is typically not that big a deal, as you’ve got the events from which you can recreate them. A failure occurring on this side has several reasons, so solving that issue is very specific for you use case. But trying to get that view model in your for example RDBMS a second time will mean you’ll perform a replay.1. An aggregate is not necessarily rebuild from your events, that’s only the case of you decide to use Event Sourcing as well. I take the stance though that you will, as otherwise your question wouldn’t point this out.
    A part from that, I get the idea that you assume that recreating your Aggregate, so handling your events a second time, also means your Event Handling Components which update your views will handle the events a second time. This is not the case however. If an Aggregate is Event Sourced in Axon, that will be done by reading a stream of events for that exact aggregate and calling all the @EventSourcingHandler annotated functions on your Aggregate.
    Any other components on your query model which update your views will not be called in such a scenario.

I hope this helps you out, and feel free to ask additional questions!

Cheers

Steven

Thanks very much for your fast response and guidance.

OK, so I understand a little bit more now but have some follow-ups :wink:

Per 1.3 of your response, the example that I followed (a simple bank account example - https://blog.novatec-gmbh.de/event-sourcing-spring-boot-axon/) has an @EventSourcingHandler defined on the BankAccount aggregate as follows:

``

@EventSourcingHandler
protected void on(MoneyDepositedEvent event) {
`this.balance += event.amount;`
log.info("<EVENT> ACCOUNT BALANCE NOW : {}", this.balance);
`view.setAccountBalance(this.id, this.balance); // I added this bit to update the view!`
}

In this handler you can see that I added a simple method to update a view (a simple RDBMS table of bank accounts and balances). Is this an acceptable way to do it, or is there a better alternative?

I agree that the event has already been stored at this point and is then published and picked up by this method; my specific worry was what happens if the RDBMS write fails in some way as the Read Model would then be out of sync with the aggregate in memory but I’m guessing there’s not a lot that can be done about this…

For your response 2. I added some breakpoints to each @EventSourcingHandler in the class and it’s called for every event stored in the EventStore DB for that aggregate ID including the current event that has been posted (via the CommandHandler invocation). Hence my concern that each time I post a new command as well as the internal logic running (which in the example of this Bank Account is pretty small) it will be writing to the Read Model which could be expensive.

My question I guess is, is there a better way of doing this - I must confess that trying to find a single source of truth for Axon is proving quite difficult based on a number of changes to the API over it’s previous versions in which the API seems to have changed quite substantially.

Thanks again
Steve

Hello,
While I’m still relatively new to all this as well, I thought it might help to share something I’ve done. It’s not a production-grade app, but perhaps it will give you something simple to tinker with.

sample-user-service.zip (14.6 KB)

Hi Steve,

Ah, I see what’s bothering you right now.

You’re mixing the command model and the query model at this point.

Would you should do for updating your views (the query model), is introduce a separate component with @EventHandler annotated functions on it.

Axon (in a Spring environment) will automatically wire any Spring beans which have the @EventHandler annotation to Event Processor, which in turn receive their events from the EventBus/EventStore.

You’ll thus decouple your write model, the aggregate in this case, from your read model.

I’ve you’ve got the time, you can see me create a sample project in Axon Framework/Spring Boot with CQRS in mind over here.

At around 26min, I start introducing the query side of the application.

Next to that, Brians input might also definitely proof valuable.

Hope this helps!

Cheers,

Steven

Thanks Brian, this will prove to be very useful I think!

Kind regards
Steve

Hi Steven

Yes, I think you (and me if I’m honest!) have got to the nub of my concerns!

I’ll review the video that you’ve linked to and see where that leads me…

Thanks ever so much to you and to Brian for your support!

Kind regards
Steve