AshEvents: Event Sourcing Made Simple For Ash

Hey folks!

AshEvents Release

We’ve just released the first version of AshEvents, an Event Sourcing tool for Ash Framework apps.

Check out the blog post for the announcement! Thanks to @Torkan for building this package and for writing a guest post for the Alembic blog to share!

AshEvents: Event Sourcing Made Simple For Ash — Alembic :tada:

Logo

36 Likes

The first thing I looked up in the docs, before reading anything, was “snapshot” – and the search returned nothing. Still looks interesting though, I’m going to read more :slight_smile:

1 Like

One of my first thought when I was reading the announcement was that it’s great, but also I don’t think it’s event sourcing. Ability to replay the state is great, but it seems that the state is still a primary concept and events are secondary.

Still great though. I would just avoid marketing it as event sourcing (as the readme does).

Which to me is the practical event sourcing. Going all the way I never found very productive. Getting the actual state of things as of right now became a chore. Just obstacles.

What you said is what would sell me to “event sourcing”.

1 Like

Event sourcing might be not productive for certain apps, especially if they are mostly CRUD. And it’s totally fine. I don’t see the reason to call something that is not an event sourcing an event sourcing. Why would one do that? To ride a hype wagon?

1 Like

To sell it better and achieve wider usage, I’d say.

In my case, I see a lot of value-add in “CRUD apps with extended history and potential state reconstruction if needed”. Would you not agree that that could be a compromise case for CQRS without having to resort to aggregates just to get an answer on “hey, what is in fact the current value of this shopping cart”?

1 Like

The term may not be as strictly defined as you think :slight_smile:

Lets cite some sources:

The fundamental idea of Event Sourcing is that of ensuring every change to the state of an application is captured in an event object, and that these event objects are themselves stored in the sequence they were applied for the same lifetime as the application state itself.

There are a lot of ways to interpret and implement the concept of “event sourcing”, but the most important property is that you can delete all of the projections from the event store, and then rebuild them all by playing forward an event log.

AshEvents has this property. What we’re doing, however, is persisting to the projections directly while persisting to the authoritative event log, which is just an implementation detail.

Could you perhaps restate this in terms of a concrete benefit that you get by having events as “primary” and state as “secondary”? Like a capability of an application that you have by doing that that you don’t have if you don’t do that? Regardless, I’d say that AshEvents is not putting one first or second, it is a middle-ground design pattern that gets you the best of both worlds (if you’re willing to adopt some constraints).

I think it’s very reasonable to invert the pattern that AshEvents uses, and would not take a significant amount of change to implement it. What we would do is add a piece of context that is set that tells us to actually run any hooks on an action, and default it to false. Then you can hook something up to your event resource (something like EventStore — EventStore v1.4.8) that runs it on a loop and reruns that event with that context set to true.

Ultimately, there is just no need for us to add that layer of indirection to have all of the same benefits. But if someone else wants it, then PRs welcome :slight_smile:

What we’re going for is not having to restructure the entire application like an event stream/handler system (often putting side effects far away from their cause, and making understanding a system without “just running it and finding out” really difficult) to get the benefits of event sourcing.

While I appreciate the concept, I definitely wouldn’t intentionally misuse a technical term just for marketing purposes :smiley:. If someone convinced me well enough that this really doesn’t qualify as event sourcing (i.e by no definition of the term does it fit), then I’ll happily ensure the blog post is updated.

7 Likes

I definitely commented a touch too quickly (a personal flaw that still gets the better of me occasionally; my apologies).

I meant this more like “As the CQRS / Event Sourcing is indeed not as clear-and-cut defined, why not ‘sell’ a subset of it better, especially since it solves real problems?”. Because like yourself, I am not convinced CQRS / Event Sourcing has super clear boundaries on its definition.

Could be my own ignorance, admittedly.

For sure, I read your good intentions/meaning I just wanted to clarify :heart:

We had a conversation before launching about this (i.e “some people will say this is not event sourcing”) and ultimately decided that it fits the need, and fits enough definitions for the term for us to say “this is one way to do event sourcing with Ash”.

2 Likes

That might be true. However it still has “sourcing” in the name, meaning that the events are actually the source (what I meant by primary vs secondary). Since you brought up Fowler’s article, let me quote two things from it:

Introducing Event Sourcing adds a step to this process. Now the service creates an event object to record the change and processes it to update the ship.

What I understand here is that a record of a change (an event) is then processed to update the state. Not the state is updated and then an event is stored. This also echoes later in the article, when he writes that just having a log of changes is a relatively small gain, which can be achieved otherwise, without event sourcing.

The key to Event Sourcing is that we guarantee that all changes to the domain objects are initiated by the event objects.

Here, again, the change (of state) is initiated by an event.

This is how I understand it, which might be a wrong understanding of course. I have no credentials to gatekeep what is really ES or not. It was just my reaction when I read the announcement. No need to change it just because of that :wink:

This is a bit tricky. For me the biggest benefit is that the application has just one track to do things: always start with an event. I have seen systems that bragged that they can replay, but they actually could not, because nobody used that feature for a long time and it stopped working, because direct changes to the state made it incompatible.

I would guess there might be some cases with race conditions, where writing an event and then replaying state is more reliable than concurrent updates of the state, but I have no proof here.

Just to be clear, I am completely fine with that. I don’t think ES is some kind of a silver bullet for every application. Most of them probably don’t need it. But having “actionable” events (i.e. a structure in the storage, not just text logs) is always better than not having them.

1 Like

Right, so with AshEvents, an event is always committed first, transactionally, representing exactly what changes are about to occur in the projection: ash_events/lib/events/create_action_wrapper.ex at v0.1.1 · ash-project/ash_events · GitHub

I think there is definitely a way that you can sort of “accident” your way out of the benefits (just like folks could accidentally change the source code of an event handler in a more standard implementation of event sourcing), and likely as the package is used more widely or internally we’ll find improvements to be made to the pattern itself (i.e checking automatically for backwards incompatible changes/the need to add event version adapters).

2 Likes

I’m inclined to agree with @zachdaniel here: if the interface and observable behaviour are the same—and in this case, not strictly defined to begin with—the implementation detail of the persistence model shouldn’t disqualify.

Admittedly, when I first learned about the pattern I myself was nerd sniped by the persistence mechanism turning how I’d thought about state management to that point on its head. But this implementation seems like a pragmatic compromise that works elegantly with Ash fundamentals and avoids some of the expensive projection work laid out in the OG recipe, so I’m more than fine with it.

4 Likes

What would happen if event persisting succeeds, but the original action itself fails?

They would roll back together.

1 Like

If I am able to construct a given piece of information from the events alone, and the state of my system is derived by it, call it whatever you want.

It is totally fine to have some event sourced systems that guarantees transaction with some piece of State and Event Log; some shortcuts for optimization sake, still, I would personally avoid it, but meh, “It Depends :trade_mark:

That also means that “state” is second class citizen and I should be able to delete it at any time.


From Greg Young incoming Book (unedited):

Event Sourcing says that all of our current state is derived off of the events that we store. That is it.

It only states that every piece of state that we have is derived off of this series of events which are structured into (a) log/logs.

It does not matter if we are discussing say a piece of state such as a domain object in memory or whether we are discussing a piece of state such as a table off in a database. ALL of that state is directly derived off of the log of events. Beyond this, any of that state can be thrown away at any moment and rebuilt from scratch by replaying those same events as they are by definition derived off of the log of events. The state is in fact a direct “interpretation”.


Have been over half a decade in exclusive event sourcing systems in Elixir so I am happy to see a bit more movement around the topic. Hopefully Ash understand of event sourcing wouldn’t cause problems. Definitely having fun over the weekend with it.

My immediate comment is that I do not see a way to have multiple events, or how to control the event types. Without it, it would be more CDC (Change Data Capture) than Event Sourcing, the event type dimension and control its data is extremely important to understand intent.

5 Likes

Hello, since EventSourcing has been a really important stepping stone in my career and I’ve invested significant time to understand and implement it I want to throw in my 2 cents. First I should note that I may be biased, but in my head EventSourcing (ES) and Domain Driven Design (DDD) are linked, even though one may use ES without DDD or DDD without ES they only have substantial impact when together. Without DDD, ES can be easily replaced with CDC (Change Data Capture) having less effort and effectively the same benefits. As such when I mention ES, it is assumed DDD is present.

I’ve done some form of ES in 4 companies so far, of which I must say only 1 saw substantial benefits using it, the other 3 had almost no benefit and in some cases I would argue it slightly hurt them. The reason? The business did not care for ES (even though they hired engineers to implement it).

The longer I’ve been working with EventSourcing and CQRS the more it has been becoming clearer that it’s not primarily a software architecture per say (even though it certainly is one) but rather it’s a business strategy. To successfully implement it you need you need 3 things ordered by importance:

  1. A complex domain and Domain experts who understand it
  2. Business who sees ES as their competitive advantage
  3. A technical implementation

ES exists to deal with complex problems, it’s a slow and steady approach. Technically we present the benefits of ES as enforced audit-log, async communication, having a time-machine and the ability to recreate state. But in fact the main benefit is the ability to handle ever increasing complexity on a logarithmic curve. Dealing with domain complexity however is not an engineering problem, it’s a business problem. ES/DDD requires a change in the methodology of how software is build, and it must start from the top, the business has to become an active part in designing the software, and that is done though defining Events and how they affect the state of the application.

So getting back to the subject of Ash Events, I think it’s a cool addition to the Ash ecosystem, but overall I don’t find that it will help businesses who want to adopt an ES/DDD strategy. Ash is pretty opinionated on how software is build (through Resources and Actions) that’s a far cry from Events, Aggregates and Handlers. The “Ash way” does not push you towards the change in methodology for building ES software, rather it makes it easier to write declarative resource oriented software (which is amazing in it’s own right).

In contrast, let’s take a look on Commanded, an ES/CQRS framework, it is also very opinionated, however it “pushes” you toward thinking about Events and how they affect the state of your application as the primary concern. Now don’t get me wrong, Commanded as any framework has it’s drawbacks, there are many times I found it was getting in the way of what we designed as a business, but with even with it’s flaws the intent on focusing on the right thing was there.

So in my opinion the “Ash way” is very different than the “ES/DD way” and I would not recommend it for a business that has decided to do ES. Nonetheless I am sure people will make use of some of the features AshEvents will provide to applications doing the Ash way.

All that being said I love Ash and it’s declarative way of doing things. That’s exacly why I choose to do my startup in Ash, “ES/DDD” is only really worth it when a particular business needs it.

11 Likes

I see the argument here, and ultimately I think we’re on the same page. AshEvents is predicated on “assuming you like what Ash code and design looks like, how can you opt into the other benefits of Event Sourcing”.

A fundamental concept with Ash is that your application should not need to be shaped as an architectural decision. If you’re using event sourcing as a code organization tool then:

  1. It’s not a strategy I would choose
  2. Ash doesn’t stop you from doing that at all

For example, it’s trivial to have an Event resource, and then a process action that routes events to event handlers, and those event handlers could even be Ash actions if you want.

3 Likes

People would need to give up to Resources being around Nouns, and make most of the Resources verbs-made-nouns (workflows) to be effective.

Consequently, Ash needs to provide a robust projection system to have different materialized views and have Resources without any operation that is a side effect (UPDATE, DELETE, INSERT), purely exposing information.

The projection and query side is where I was excited about Ash and its capabilities since it would reduce a lot of boilerplate code and simply a ton.

I feel that Ash could succeed for most business out there since it is a local decision to make, and that is awesome. Still, it requires education around it.

I am supportive of alternatives, while being very careful on misunderstanding what the problems could be in the future, almost 90% of blog posts out there complaining about Event Sourcing mentions some of the following.

  • Change Data Capture (the dimension of the granular event type and its data is gone, everything becomes a 1% CREATE, 1% DELETE, 98% UPDATE events, major red flag)
  • CRUD and Noun-Based Resources mindset instead of focusing on Workflows/Processes/Verbs
  • Kafka
  • Separate database
  • CQRS as a top-level architecture decision
  • Event Sourcing as a top-level architecture decision

When in reality, all event sourcing is about is having a ledger of events that I can reply at any point to have a projection into a given state I want.

DDD, CQRS, Event Consistency, Separate databases, etc; that is just noise added on top of what event sourcing is. That does not means it doesn’t play nice or they are bad things neither.

1 Like

Can anyone who has used event sourcing in a real application explain the purpose/advantages? I have had a hard time understanding the purpose of the pattern at the application level.

In particular, I don’t understand why anyone would ever “need” to replay events up to a particular state in this way. You already have the state, no?

I understand why someone would use ES as theory for, say, implementing a database on top of a shared log, or as a framework for building a CRDT implementation, and so on. But I don’t get the impression that’s what people are using these tools for.

I assume this is just ignorance on my part, and this seems like a good place to ask since a few individuals above appear to have actually done this :slight_smile:

1 Like

They would, but this doesn’t bother me too much if they are looking to model things in that way. Ash is ultimately a middle-ground domain & application modeling tool. If you want to think of your app in terms of events, it’s all good by me.

Ash provides everything you need to project side effects transactionally alongside application changes.

Agreed, meaning the AshEvents strategy qualifies for the term :+1:

2 Likes