Ever tried to hold a writhing slippery eel in your hands? In case you haven’t, its hard. Building a UI for a CQRS system needn’t be that tricky but you do need to contend with some interesting challenges:
- The commands ‘complete’ far faster than you may expect –  compared to a consistent application.
- The read model is ‘eventually consistent’.
But what is ‘eventual consistency’? ‘Eventual consistency’ is when a read of the data store may return stale results. That is a command has completed but the data store is not yet reflecting the change. This state in a typical line of business application can last for ten’s to the mid hundreds of milliseconds. The actual time is dependant on the specifics of the application. This presents a challenge for designing the user experience. Here are 4 possible approaches to solving this issue.
1. Disable then refresh after editing
A brute force approach is to acknowledge receipt of a command by disabling the edit controls. Then after a specified delay, reload the screen to reveal the updates. While solving the eventual consistency issue, this approach breaks into the flow of a user can lead to frustration. This approach is easy to develop and is worth considering in the light of this trade off.
2. Use a confirmation screen
By far the simplest approach is to send the user to a confirmation or ‘thank you’ screen. Given the typical delay for consistency to return, when the user navigates away from the screen the read models will be up to date. This works well for end of process screens like completing a sale or booking tickets.
3. Fake it
When the client receives confirmation the command completed, it can assume the new state of the read model. This is because you validated your commands before sending. The domain should also reject commands if they would fail or break a business rule. As a result the client can predict changes to the view. This approach requires careful thought to how you manage the version number. If you are building a web front end then javascript promises are a convenient structure to handle this process. This approach is, more time consuming, but results in a much smoother user experience.
4. Use polling or sockets to subscribe to events
You can make use of the many libraries and services available to transport real time data such as SignalR, firebase or hubnub. This makes it much more realistic to supply your UI with a stream of events as they happen. This does add an extra development overhead. It is important establish if live updating is in fact needed (apart from it looking cool). It is also important to be aware that not all events and not all fields on all events should be sent over the wire. You can overcome this with a filter ensuring sensitive information is not leaked.
The problem with this approach is that it can undo all the good work of your performant UI in waiting for updates to arrive.
Conclusion
My preference is to fake it. Faking it is good for user experience. You can always enhance later with SignalR or similar technology. As always be weary of premature optimisation. You may find sophisticated users want this type of synchronization. I have found that for the majority of users in the majority of use cases, they are happy when the application doesn’t get in their way. This is one of the great strength’s of a CQRS based system.