carry

kauko 2016-08-16T06:56:35.000003Z

how do you handle multiple controllers btw @metametadata ?

kauko 2016-08-16T06:57:35.000004Z

if a component dispatches signals and the intended controller may be any one of N.. what do you do? Does a "parent" controller need to know the "child" controllers?

metametadata 2016-08-16T09:57:18.000005Z

Hey @kauko! Could you please give an example of "multiple controllers"? Because, stricly speaking, for each app there's only a single controller.

metametadata 2016-08-16T09:58:49.000006Z

Maybe you mean how one can define this controller using more smaller ones (i.e. like redux does with reducers)?

kauko 2016-08-16T10:04:36.000007Z

Maybe

kauko 2016-08-16T10:04:46.000008Z

Just need some way to split the controller into multiple files

kauko 2016-08-16T10:05:02.000009Z

otherwise any app of non-trivial size will have a 2k+ loc controller 😛

kauko 2016-08-16T10:05:21.000010Z

(well, maybe not, but splitting is a must IMO)

metametadata 2016-08-16T10:21:06.000011Z

Yeah, I agree. It's something I thought about but didn't prescribe in the framework yet.

metametadata 2016-08-16T10:28:48.000012Z

There could be different solutions. On top of my head: - define controller as multimethod, this way you can scatter signal processing across many files easily; but there may be problems with pattern matching now?.. - "Flux way": ensemble a controller from smaller controllers; when a "parent" receives a signal it sends the signals to all the children; this is also how Redux works if I'm not mistaken; - the "chain of responsibility"-kinda approach: ensemble controller from the smaller controllers; when it receives a signal it first sends it to the first child, if it wasn't handled - sends it to the second child, etc. until someone is able to handle the signal

metametadata 2016-08-16T10:29:39.000013Z

I recall I liked the last approach the most

metametadata 2016-08-16T10:30:30.000014Z

because in this case you can easily throw an exception if no handler was found for a signal. Redux in such situations silently ignores the error.

metametadata 2016-08-16T10:33:53.000015Z

Just in case, here's the Redux pattern explained by author: https://stackoverflow.com/questions/35667775/state-in-redux-react-app-has-a-property-with-the-name-of-the-reducer/35674297#35674297

metametadata 2016-08-16T10:39:58.000018Z

And here's a snippet for my liked approach:

;; spec

  ; only one controller will handle a signal
   :control    (ui/either #{app-control
                            router/control
                            files-logic/control
                            settings-logic/control})
(ns frontend.settings.logic
  (:require [cljs.core.match :refer-macros [match]]))

(defn control
  [model signal dispatch-signal dispatch-action]
  (match signal
         [:on-select-theme id] (dispatch-action [:select-theme id])
         ; ...
         :else :bypass)) ; <-------------------------------------------- let other controller handle the unknown signal
(defn either
  "Returns a function of any args which calls functions one by one while :bypass is returned."
  [fns]
  (fn either-fn [& args]
    (loop [f (first fns)
           next-fns (rest fns)]
      (when (nil? f)
        (throw (ex-info (str "No function was able to handle passed args: " (pr-str args))
                        {})))

      (let [result (apply f args)]
        (if (= result :bypass)
          (recur (first next-fns) (rest next-fns))
          result)))))

kauko 2016-08-16T10:43:05.000022Z

Yeah, I think that could work. It's important that the ability to give components custom controllers is retained, for testing for example. So avoid some register-controller functions that add a controller to some global thingy

kauko 2016-08-16T10:43:50.000023Z

and when I work on my view component and add some new signals, I want to add it to one place, not several places

metametadata 2016-08-16T10:46:05.000024Z

Sounds reasonable!

metametadata 2016-08-16T10:47:51.000025Z

this either function can be used to split a reconciler as well