0

I guess this question could be related to any evented system like Event sourcing / DDD / Lambda architecture, ESB, Actors... I tagged the question so that people experienced with these systems could answer.

I'm currently experimenting with my startup an original way to build user interfaces, by using concepts often used in DDD / Event sourcing world but applied to a javascript single page application. What I want is a purely functional UI, where I can replay the in-memory event log to restore the UI state (the event log is not persisted on browser close, it is just to make things easy to reason about and potentially enable cool features like UI undo/redo for free, time travelling debugger like in ELM...)


I just wonder sometimes how to choose the right level of abstraction for events as it seems to me there may be multiple "interpretations" of something that just happened.

Basically, in a JS SPA, many events are triggered after an user has clicked on a button, on a link or something like that. So I could add an entry to my event log being this low-level event (after managing to make it serializable). But this event can also be interpreted as a representation of what the user really has done in a high level abstraction.

To give an exemple, let's say I have on my UI a popup that is displayed at some point. When the user clicks anywhere outside of the popup, it should be closed. Let's imagine now the user clicks to a div outside of the popup to close it. What event abstraction level am I supposed to add to the event log?

  • User has clicked on div ?
  • User has clicked outside of the popup ?
  • User has closed the popup ?

These 3 event abstractions seems correct to me: they describe in the past something that happened, but at different abstraction levels. So I'm asking myself some questions like:

  • Do I have to choose one of the 3 abstraction level? If so how to choose?
  • Can or should I fire all 3 events? If so, wouldn't the event log becomes a bit messy?
  • Should I use concepts like DDD Saga, so that when receiving a "user clicked div" event, the Saga could fire a "close popup" command or something?
Community
  • 1
  • 1
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419

1 Answers1

0

In an example described, I would suggest to not generate any events at all, because you are not performing any command (action which changes application state). You may want to have such event only in situation when there is actually a practical value of saving it, or you can think of it becoming valuable in the nearest future, so you can use all this information to generate some kind of report which will become valuable for your business.

There is no hard and fast rule behind that, it's just a matter of common sense. What kind of problem are you trying to solve? If it's implementing redo/undo, event sourcing is not the first thing that you should look for, "command" pattern would probably be a better choice. You will not get undo/redo "for free" with just event sourcing. Consider splitting your answer into multiple ones and be more specific about practical goal.

Also, my advice would be to stay away from SAGAs as long as you can. It's always better to perform things synchronously where possible, otherwise your code will quickly become a mess (less readable, growing semantic distance). If you have to make it async, the better alternative would be utilizing "continuation passing style","promises". Sagas should be considered as a last resort and used when all other approaches failed to work ... but such scenarios are more likely to crop up on a server side, when your lovely noSql thing does not support ACID transactions, for example :p.

Correct me if I'm wrong, but looks like you just want to play with a "new trendy approach" and try it without any practical reason. It's fine, as long as you are ok with making your application more complex than it should be. (more expensive to develop and support)

IlliakaillI
  • 1,510
  • 13
  • 25
  • ILICH to give some context, we already have a production running application using these concepts with great success and much more easy to develop and reason about that our former production app using Backbone. We already use libraries like Q to handle async operations. – Sebastien Lorber Dec 29 '14 at 11:35
  • You talk about "generate some kind of report" but actually the UI presented to the user is (kind of) that report: we "query" the state to redraw the UI. So anything that changes the state, and thus changes the report/UI should come from an event (here the overlay click should close the popup, so that overlay click event actually does change some state). I am trying to transpose backend concepts to UI development so I took some liberty like assuming there are some "self validating commands". For exemple if a user types some char in a text input, is it worth firing a command for that? – Sebastien Lorber Dec 29 '14 at 11:40
  • About undo/redo for free, actually we do have it in our production application: we can restore any UI that was previously displayed (for this we can use event-sourcing, or even state-sourcing, as the projection of events is not updated during a browser session). However this may not be an undo/redo in the sense you talk about, as we only restore a view to a former local state, but we do not "revert" an user intent: when doing an undo, the backend API is never called so you may end up displaying a stale UI. So the interest is limited (see https://www.youtube.com/watch?v=DMtwq3QtddY) – Sebastien Lorber Dec 29 '14 at 11:46
  • By the way, I think you are true about Sagas: it introduces complexity and are harder to reason about than synchronously handled events. But in some scenarios for the UI it seems an appropriate usecase. The place where I find it the most useful is for our app onboarding: the user can perform real actions in this onboarding (not just a carousel presenting the app) but there is some extra logic added by the Saga that should only be used while the onboarding is running. – Sebastien Lorber Dec 29 '14 at 11:50
  • >>For exemple if a user types some char in a text input, is it worth firing a command for that? I think the answer would be - if you want to perform "redo" operations up to single chars, then yes. But what is the point of firing separate commands and producing separate events for each char if you will never make use of those events? – IlliakaillI Dec 30 '14 at 01:22
  • I don't necessarily need "redo" feature, it's just an extra that comes with my system. And using commands is not necessary too, just events! I have undo/redo with single char precision without having any command fired when user is typing. Think of my undo not like a command undo but to go back to a previous snapshot. – Sebastien Lorber Dec 30 '14 at 09:26
  • `But what is the point of firing separate commands and producing separate events for each char if you will never make use of those events?` -> This is totally false: when the user type a char in an input, the char should get displated in that input to the user, so the state of the UI should changed! I listen to that event to modify my app state, that will trigger an update of the DOM and make the char appear to the user. Think `2-way data binding` here, or read how React handle inputs here http://facebook.github.io/react/docs/forms.html#controlled-components – Sebastien Lorber Dec 30 '14 at 09:28
  • @SebastienLorber Your question is very subjective and completely dependent on use cases. The appropriate level is the highest abstraction level you can afford. Just like an API, you only want to expose the bare minimum that still offers a good balance between flexibility, simplicity and maintainability. It all depends on the problem you are trying to solve. – plalx Dec 31 '14 at 15:18
  • @plalx I know it is subjective but I think your comment could be easily a valid generic answer! another question coming from this is: is it a big deal to have an event log with different abstraction levels? Your answer makes me think of this Travis Brown answer: http://stackoverflow.com/a/12309023/82609 -> `it's just a solid development practice to use the least powerful abstraction that will get the job done. In principle this may allow optimizations that wouldn't otherwise be possible, but more importantly it makes the code we write more reusable.` – Sebastien Lorber Dec 31 '14 at 15:49
  • @SebastienLorber well, it depends on how your application is implemented, I was thinking about firing command/event after finishing editing field. If that is not an option with your framework, then you really have no choice and I don't get your problem. But why would you want to fire 25 events after editing text field instead of 1 in the situation when you can just fire one "field updated" event? There should be a business case for this, otherwise there is no point of doing this. Agreed with quote from Travis Brown that you've mentioned. – IlliakaillI Jan 01 '15 at 17:19