Fork me on GitHub

Is there any guidance/advice/tools for composing single events from functionality in multiple independent namespaces? One could, for example:

  (fn [coeffects event]
    {:fx [ [:dispatch [::foo/update-thing :potato]]
           [:dispatch [::bar/herp-the-derp :derpderp]]
           [:dispatch [::routing/go-to-page :blah]]
However these will all take place at some uncertain future time, and not necessarily at the same time (especially if the sub-dispatches also call :dispatch, etc.), which can lead to unresponsive UIs, or non-atomic UI updates (eg. a brief flash of old data before the appdb is updated by another event) - neither of which is desirable IMO. What I'd like to be able to do is perform all necessary actions in the processing of a single event, something like:
  (fn [coeffects event]
    (fx-> coeffects
      (foo/update-thing :potato)
      (bar/herp-the-derp :derpderp)
      (routing/go-to-page :blah)
Which on the surface seems like the functions could be fairly straight-forward, but I'm not so sure given that, among other concerns, each function may want to introduce its own interceptors? :thinking_face: Anyone have any insight?


The function composition approach is the way to do. Each function will be just that - a function. As such, they won't care or even know about interceptors.


I just recently wrote something like. I'm not at liberty to share the code, but it was simple and fun to implement 🙂 Plus my implementation was most likely buggy and awful. You take the cofx map and reduce over a collection of functions, which each take the latest cofx and return a map of effects. And then you just make sure the db in cofx is updated at each iteration. (but we didn't use per-event interceptors etc)


@U2FRKM4TW My point about interceptors is that, if a pure function expects a coeffect which is supplied by an interceptor, the composing event needs to know that and make sure to apply that interceptor itself - which essentially requires the composing event to know about and be kept in sync with an implementation detail. 😕


@U0178V2SLAY do you return the coeffects map from each function? I feel that that could lead to unexpected/hidden issues, since coeffects != effects? :thinking_face:


no, the reducing function takes the returned fx and checks if there's a db inside and then updates the cofx if necessary


That is true, so far there's no any easy mechanism to overcome that. Should be relatively easy to make one though, it you make an event into something first-class. I myself use like 3-5 interceptors in any given project, so motivation to make something like that is nonexistent.


Yeah, parts of our codebase use a bunch of sub-injection interceptors, so we have quite a few to deal with 😅


Right, I never use sub injection myself - I always simply access the values from the DB.


@UD9ECLVDL I always use the :db and :fx forms and then i have a mechanism for composing events that take db and return db and fx


for the interceptors thing...yeah mostly avoid them


only exception has been for "the current time", but even that isn't strictly needed