Fork me on GitHub

Looking for advice from folks who have had experience with re-frame at scale. There's a couple libraries out there that encourage subscriptions of the form:

(subscribe [:q [:attr1 :attr2] [:uuid uuid]])
This is clearly not the thing that is warned against in the reframe docs (this declarative data specification is agnostic of the actual form of the underlying data): This results in only a few general subscriptions, which would appear to be good. But now subscriptions are no longer named. They all show up as :q, which makes debugging much more difficult in something like re-frame-trace. Would it be better to have named subscriptions like:
(subscribe [:some/data uuid])
And then have each subscription explicitly defined with a reg-sub?


@zalky If :attr1 and :attr2 have some namespace, then it should be easy to link it to a particular kind of entity. Also, I think it makes sense to use these very generic subscriptions only for the actual data - not some state.


@p-himik: thanks for the response! Could you clarify the distinction you're making between "only for the actual data - not some state"?


@zalky E.g. my app has a bunch of globally available panels, which in turn have some state specific only for them. The currently active tab, whether some element is selected or expanded - stuff like that. I've read somewhere that these things should be stored within some atoms that reside outside of app-db, but I don't like such approach since hot reloading messes things up, and it's much harder to understand what's going on when you don't have everything in one place, like app-db. So, I store all that state in app-db. And all "data-data" I store there as well - like the list of users, the list of permissions, the list of other items. All these data reside under a certain key in app-db so I can easily distinguish what's the state and what's the data. And subscriptions like :q have access only to the data. I don't want to let :q deal with the state because the state is too specific. Like one panel has tabs and a table. Another panel has a bunch of plots. The third panel has only static data. There's no way to generalize it all in a useful way that would also be suitable for stuff like :q. So for the state I just create needed subscriptions manually - like :current-panel and :items-panel/selected-tab.


@p-himik: I see what you mean, thanks for the clarification! Focusing on the domain data then (user lists), I'm finding that debugging tools rely on the event id, understandably, as the main identifier of subscriptions. So something like re-frame-trace, which I've found indispensable, suddenly becomes less helpful for debugging domain data. The different domain data subscriptions all get listed as the same :q, and while it's possible to dig deeper and try to identify the specific subscription based on it's query attributes, or return value, having named subscriptions makes debugging much easier. Was wondering if other folks had run into this and weighed the tradeoffs. Sounds like you're not finding it a problem?


@zalky the :q pattern still looks to me to be just about exactly what recommended against. Is that what you were saying previously?


@mikerod: well, tbh, I was kind of thinking the opposite. The :q pattern isn't really telling you anything about how the data is stored, it's just a specification of what data you want, not how to get it. You could change the underlying db implementation and still keep the pattern. And in fact this pattern is common to a lot of different db implementations (datomic, datascript, subgraph, etc...). It is data agnostic to a certain extent, and so I'm not sure it fits the description in the link you and I shared. Maybe I'm wrong on that? However, I do find it problematic for other reasons, mainly that having named subscriptions can be very useful, and the :q spec gets rid of that.'


@zalky I can see the difference in that you may still abstract away from the underlying db structure


I think that’s a fair point. However, I do agree with the not-useful-name issue though as well.




One solution I was just playing with was having the subscriptions be really dumb, as is generally recommended, and then defining a new subscription registration function that abstracts away some boilerplate.

(subscribe [:selected/player player])

(reg-pull :selected/player
  (fn [player]
    [[:uuid :name :age] [:uuid player]]))
Here the reg-pull definition would reference :q.


@zalky you mean something like passing that query vec from the fn to the :q subs in some way?


yeah, something like:

(defn reg-pull
  [id spec-fn]
  (f/reg-sub-raw id
    (fn [_ [_ & args]]
      (let [[spec ref] (apply spec-fn args)]
        (f/subscribe [:q spec ref])))))


Makes sense


Well, I think it does at least. Haven’t thought too hard on it still.


I am just digging into re-frame hacking on its todo-mvc and for fun thought I would put up a modal dialog if they add a duplicate todo warning them and asking them to confirm. What is used for modals? I found — are there other options? Thx.


@hiskennyness: I've been using this bootstrap/reactstrap port and it has worked really well so far:


It's not out-of-the-box re-frame, but that part is not that much work tbh.


@hiskennyness re-com might be useful, if using it for fun. Although it is easier to use it when everything is already re-com-ed