Hey,
Rinat I saw you will give a talk at DDD belgium next week about DDD / CQRS in the frontend
This seems to go in the same direction as what I'm trying to achieve (except maybe you agree better with Flux?)
I discussed with a facebook React dev and he told me that they developed Flux internally even before using a system like React, and that when they "opensourced" it they were quite surprised to see so many implementations, as they know themselves it is not so perfect even if it works quite well for them.
So I guess you understand that I'm not trying to create a "mapping" between a CQRS backend and a CQRS frontend or something like that, but rather having a CQRS / DDD inspired frontend running against a black box REST API.
And I guess this is what you will present in this talk too right?
I hope it will be recorded!
If you can I would like to continue this discussion to understand better how to apply CQRS / DDD concepts to the browser.
What is bothering me with Flux is that stores as originally described can depend one on another, and the application order of events to these stores do matter.
They are not really supposed to contain "denormalized" data but would rather look like collection of items.
They are also supposed to contain the data that we render to the user.
So for me it's not really clear if a store should be compared to a repository, an aggregate root, a reporting vue...
Some of my thought:
- A browser runs on a single computer, so adopting a distributable architecture like CQRS/DDD also means that we can make all the formerly eventually consistent components consistent. I mean we can easily update 2 components state in the same transaction in an atomic way (using something like STM / immutable data structures) without any major performance bottleneck as there's no IO involved.
- On the backend, we construct reporting views (eventually consistent). Flux stores are used to "draw" the UI. I think drawing the UI is the equivalent of "reporting" on the browser. I tend to think a Flux store is then a "reporting database". This is why I denormalize data into flux stores and make them independant like in the backend. So I created "widget stores" that will contain everything for a widget to render. Each widget has its own reporting database (there's also a widget to drive the layout). Then I just have to create an UI which is an aggregation of all my widgets. A bit like creating a consolidated report.
Flux for me seems to create a single huge "reporting database" (composed of all the stores) and then rendering it. This means that all the developers must understand that huge reporting database, and the rendering function so not sure it scales better...
- The domain of an UI app is not necessarily the same as a backend application domain. In your UI domain, commands and events such as "contactBarHovered" or "submitForm" are also part of the domain. Reports can only be updated by listening to events, and drawing the UI is the main reporting need of the browser. Thus is hovering the contact bar makes a new item to be shawn, this is a valid application event.
- Anothing interesting thing to notice is that it seems to me some events are "self-validating" in a sens of if the browser triggers a "hover" dom event, the event already happened, so it does not make any sens to issue a "hoverContactBarCommand". Also, it does not make sense to allow the user to click on a button if that action is not allowed so for now I didn't really find any usecase for command validation. If an user command is supposed to fail, if is preferable to disable the button generating that command
- It is not so often that the client/browser is considered a "part of the distributed system" and is (eventually) consistent with the backend by an event log system. Most often we use APIs, and it's common that not all the data is stored locally because of storage capacity issues. Then many times, the client has probably stale data locally. Business commands can't be validated safely locally because the validator state can be stale and does not give any guarantee so it seems better to not validate locally and send the command to the server. As far as I understand the safest place to do validation in CQRS/DDD is at the aggregate root level. So basically I didn't find any need for local command validation until now.
- Sagas can be helpful too. I used them for things like app onboarding, infinite scrolling...
A basic exemple would be: on scroll event if selected view is of type timeline, issue command to load more items.
So in my current app I don't really have anything for aggregate root. Don't know how to apply this to the frontend yet...
Does all this make any sense to you?