The Human Brain is a Vital Front-End Component
It was around 2011 and I was working for a small company with the ambitious goal of building the world's sexiest cloud CRM product. To build a great product, you need great technologies. Fortunately, one of my colleagues was a tech maven who tried hard to stay on top of the latest trends in software development.
One day he came back from London, having attended a course by some guy called Greg Young. The course was about Command Query Responsibility Segregation (CQRS), Domain-Driven Design (DDD) and Event Sourcing (ES) . A detailed description of these approaches would make this already long post far longer, but I strongly urge you to follow these links to find out more.
The goal of these complementary approaches is to make hard choices about software architecture easier by establishing strict patterns about where to put your code. CQRS says essentially that we should have a regimented flow of data through the application, with writing data ("Commands") strictly separated from reading data ("Queries"). According to ES, all changes to application state are triggered by a stream of "Events" that can be logged, rolled back and replayed.
Anyway, my colleague came back from London full of excitement. I'm not sure he fully grasped all the details of Greg Young's work, but the revolutionary potential of his approach was clear to both of us. This was in the early days of "full-stack development", and I was lucky enough to be working on both the back-end and front-end. But while Greg was targeting his ideas at complex server-side code written in Java or Scala, it seemed to me that they should be applicable on the front-end tier as well.
Unfortunately, at the time ExtJS was just about state-of-the-art for front-end development. (Boy am I glad those days are gone.) And ExtJS made it too hard to adopt alternate application architectures, particularly those with a dramatically different way of thinking.
Unidirectional Data Flow
Now it's 2015, and suddenly everyone is being inspired by functional programming concepts. FP languages are getting more and more popular (hello Clojure!). We have Elm, Om and even the amazing Babel transpiler, which has led to huge practical improvements in JavaScript, particularly when it comes to FP. Therefore all the hype is slowly creeping into the JavaScript ecosystem, and those fancy academic concepts are going mainstream. People are even stealing ideas from Haskell, which is really cool.
The most important thing to take hold of the software development world in recent years is a concept called "unidirectional data flow". Facebook was the pioneer in bringing this concept to JavaScript with its Flux architecture, which it recommends as a way to build applications around its React UI framework.
The first time I saw Flux, I realized that it's here! Finally, my beloved CQRS/ES/DDD has made its way onto the front-end! Formally it wasn't a strict implementation of those techniques, but it was clearly heavily inspired by them.
I attended few presentations where people claimed Flux as a form of CQRS, yet almost nobody mentioned Event Sourcing. Anytime I asked a presenter about why they saw Flux as a form of CQRS, their answer was always the same: "Actions are Commands and Stores are accessed using Queries".
Commands are not Events
You should distinguish between those two terms: the former stands for the intention to do something, the latter indicates that this intention has been carried out. Typically, a Command may result in one or many Events.
Front-end development is naturally event-oriented, as any interaction with the UI is basically an event. Think about it: whenever you want to observe some interaction with the UI, you always have to attach an event listener (addEventListener
).
But it's not only about Event listeners. In a well-designed front-end application with good UX, you never throw an exception while handling an Event since this wouldn't provide the user with any feedback. Showing an appropriate error message is a UI response as well. Therefore you can't "deny" the fact that some event has occured by throwing an exception. It has happened and there is no way to take it back unless the user performs some counter-action... which is again an Event.
We think of interaction on the back-end differently. Let's take creating an order as an example. Creating an order on the back-end is a typical Command which may eventually (depends on the implementation) result in many intermediate steps. First we create the order itself, then all the line items are added (triggering Events such as ORDER_CREATED
and LINE_ITEM_ADDED
). These events must be handled in a single transaction because we need atomicity on the back-end.
On the front-end, the user is responsible for the atomicity of the operation. They add those line items by filling in some text fields, and once they are done with the order they submit the form. You might say that all the Events happen in single "UI transaction", where a UI transaction is actually the user's intent to do something such as create an invoice.
It's quite common to perform business invariant assertion in Command Handlers on the back-end. The order example may throw an exception and stop its execution if some preconditions are not met (let's say one of the products being ordered is not in stock). Because the operation is atomic, none of the associated Events is emitted.
This can't simply happen on front-end. Consider two naive implementations:
a) The user adds a product that is not available. Once they try to submit the form, a validation error is shown. The user's decision to submit the form has already take place but the UI transaction failed.
b) The user can't even add the product because the UI displays it as unavailable. Again, this results in the UI transaction failing.
Get used to it: there should be no Commands on Front-End. It is far better to think about the interaction with the UI in terms of Events. As a result, we should consider Flux as more akin to Event Sourcing than CQRS.
The Human Brain is a Vital Front-End Component
In a typical back-end CQRS/ES/DDD implementation there are Commands which are handled by Handlers that emit Events. As previously discussed, we describe interaction with the application UI as Events rather than Commands. So where are the Commands in a front-end application?
This question bothered me for a long time. When I finally hit upon the answer, I found it both surprising and convincing: a person who is interacting with the user interface is actually responsible for creating the Command, and it occurs inside their head. When they go to click a button, it is this intention that is the Command. Once they click the button, there is no way to revert that action. It has already happened, and therefore the actual click is an Event.
Therefore the Human Brain is a vital front-end component that shouldn't be neglected in our application architecture. It makes perfect sense to treat UI interactions as Events and not as Commands, because this accurately describes the nature of both Events and Commands in the context of CQRS/ES/DDD.
This simple realization uncovers a few nice facts about front-end architecture based on unidirectional data flow (especially Redux) that could help us to find an elegant solution for a really hard problem: that of Side Effects. The Redux community is still struggling to find the right way to handle asynchronous effects such as API calls that are triggered by Events inside the application. This will be the topic of my next post.