Since I’ve mentioned it in the title, I guess you are familiar with Redux.
But did you know that this kind of architecture has been used in software development for more than twelve years now?
Actually, the idea itself is even older, but it was not until 2005 when Martin Fowler defined it as “event sourcing”.
Even though it’s not identical, Redux shares a lot of similarities with this model and I think there is still more we can learn from it.
In this post, I’ll describe the problem I faced and how it could’ve been avoided if I used event sourcing principles.
Using actions as events
In short, what I’m suggesting is using actions as events (facts describing what had happened) rather than commands which describes an intent of what should happen in the future.
I’m not the first person to suggest this or the first one that compared Redux with event sourcing.
Here are just a few resources describing similar ideas:
- Naming actions in past tense
- Is redux conflating actions with events?
- Redux and it’s relation to CQRS (and other things)
- Why do we need middleware for async flow in Redux?
For more then three years I’ve worked as a lead frontend developer on a browser-based code editor.
Like any other editor it has a lot of features which can be used in different ways.
One example is: “undo/redo”.
Obviously, for this feature, the editor has to support Cmd+Z and Cmd+Y shortcuts, but there are many ways to invoke the same action:
- Shortcuts (Cmd+Z, Cmd+Y)
- Main Menu (Edit -> Undo, Edit -> Redo)
- Toolbar (Undo/Redo icon)
- GoTo Anything (“undo”, “redo” typed command)
So, I did what most of us would probably do:
Every time “undo/redo function” is requested, a component would dispatch an “UNDO” or “REDO” type action.
And this worked just fine.
But after a year or so, the company asked me if I could provide analytics on how our app is used. What actions are used in a toolbar, how does this relate to shortcuts etc?
Well, when you are working on a large scale app, these kind of tasks (which usually affect multiple teams) are probably not the most desirable ones.
Especially, when you don’t know much about event-driven architectures…
So, let’s just say I made some wrong decisions.
What exactly can we learn from event sourced systems?
As the term “event sourcing” suggests — use events as your source of truth.
Rather than using a command “UNDO”, we can describe what actually happened:
If you don’t want to bloat your (or some other developer’s) reducers, you can also transform these actions in something with more generic type:
And we’re back where we started.
But now if your CEO wants you to generate analytics, you can do something like this:
What is a process manager?
This term is borrowed from CQRS/ES terminology where the same concept is also referred as “saga”:
a piece of code that coordinates and routes messages between bounded contexts and aggregates.
Redux middleware I used in these examples is one that I built myself — redux-orchestrate.
Everything has its trade-offs, so here are some disadvantages you should consider:
- Transforming actions requires middleware which has its own complexity
- Dispatching more granular actions results in more messages that need to be handled
Event -> Process Manager -> Command concept may not apply to every use-case. It’s not a silver bullet solution and you should use it where it makes sense to you.
By using commands you are predicting the future.
This is problematic because you never know how your app will grow, how many people will work on it and what features should be implemented in the future.
By using events you are describing the past — facts which are always true and which can be used in ways you currently can’t imagine.
Events can be coordinated by a process manager which can handle side-effects and transform actions before they hit the reducer.