Fork me on GitHub
#re-frame
<
2018-12-04
>
pyr09:12:38

@polymeris very nice, thanks

lmergen18:12:51

when composing subscriptions, can you effectively not generate the same functionality as reagent cursors ? e.g. rather than doing (r/cursor db [:foo :bar]) do this the re-frame way:

(reframe/reg-sub :foo (fn [db] (:foo db)))
(reframe/reg-sub :bar [:<- :foo] (fn [foo] (:bar foo)))
what are the different tradeoffs here ? is the reagent cursor more performant for some reason ?

lmergen18:12:36

(the reason i'm asking is that i just saw the cursor-based approach in the wild at https://github.com/HealthSamurai/re-form/blob/master/src/cljs/re_form/core.cljs#L18, and i'm wondering why they chose to do so)

mikethompson20:12:11

First difference is that cursors are read/write, subscriptions are read only. Second difference is that subscriptions allow you to create a "materialised view" of the data (ie perform a computation on the data), whereas cursors are just for "extraction" from app-db which places responsibility onto the view to do the data reshaping which we prefer to avoid.

achikin16:12:10

But most of the time we consume "raw" vaules from the db. Actually you have an abstraction like this, called "layer one subscriptions" that are supposed to fetch "raw" data from the db, if I understood that correctly. Why not leverage that and create some kind of subscription-cursor? As a bonus it will be free of side-effects by default....

mikethompson21:12:07

Sorry, not following. I must be missing something key here. Why add another abstraction when we already have a single one that does all the jobs? And "most of the time" is not "all of the time". And, also, I don't understand the bonus you talk about because subscriptions are side effect free already? Finally, I'd point out that you can use cursors with re-frame if you want. I wouldn't do it because I think subscriptions are a more elegant, flexible and efficient alternative. But absolutely nothing is stopping cursor use (read-only, I assume) if you like the concept more, although doing so would confuse me because the entire purpose of cursors is to be read/write.

achikin13:12:37

> subscriptions are side effect free already Subscription handlers are clojure functions, so they are not side effect free.

achikin13:12:58

> we already have a single one that does all the jobs IMO this abstraction is too broad. That's why you have "level 1" and "level 2" subscriptions.

achikin13:12:22

> And, also, I don't understand the bonus you talk about because subscriptions are side effect free already? (r/cursor db [:path :in :db]) vs (rf/reg-sub :path-in-db some-sideeffecty-function)

achikin13:12:50

> But absolutely nothing is stopping cursor use (read-only, I assume) What happens if I use cursors in rw mode?

achikin13:12:41

Reagent did a good job on separation of concerns: fetch data with cursors, perform calculations on data with reactions.

achikin13:12:17

One huge upside of writing through cursor vs event is that cursor has limited scope and you have no temptation to update some unrelated piece of data through cursor.

mikethompson23:12:30

> Subscription handlers are clojure functions, so they are not side effect free. Hmm. We're down to splitting hairs which doesn't feel productive. > IMO this abstraction is too broad. That's why you have "level 1" and "level 2" subscriptions. Even if I accept your interpretation, there'll still be two abstractions either way, right? You like your two abstractions, I like mine. Moving on. But, for the record, I only partially accept your interpretation. You are focused on implementation. I'm much more interested in "use". From the perspective of "use" there is only one abstraction - a subscription. The user of a subscription doesn't know if it is "level 1" or "level 2". That's the way I like it. > (r/cursor db [:path :in :db]) vs (rf/reg-sub :path-in-db some-sideeffecty-function) In my experience, some-sideeffecty-function is not side effecty at all. I'm a little puzzled by some of your claims - have you actually used re-frame? > What happens if I use cursors in rw mode? In that case, you are using a technique previously known as "two way binding" and you are not using event handlers for mutations, in which case I wouldn't bother using re-frame. I'd recommend committing 100% cursors, so as to avoid getting stuck straddling the fence, because that's an uncomfortable place to be. But again, this feels like an odd question for you to ask of me if you have experience using re-frame. It is very particular and careful about controlling where and how mutations happen. That's a big part of the design. Introducing something like cursor-based mutations would defeat the entire purpose of using re-frame. > Reagent did a good job on separation of concerns: fetch data with cursors, perform calculations on data with reactions. That seems to be rewriting history. Cursors were not originally a part of Reagent. They were retrofitted after they appeared in OM (2014). And reactions were effectively not a part of Reagent either originally ... they were buried as part of the implementation (not a part of core). When i was writing re-frame, I found them, explained them and promoted them, somewhat to Dan's surprise. (2015) Either way, "fetch data with cursors, perform calculations on data with reactions" strikes me as a slightly jarring/insufficient summary of the Reagent way, even today. > One huge upside of writing through cursor vs event is that cursor has limited scope and you have no temptation to update some unrelated piece of data through cursor. I've seen two way binding lots of times over the decades, most recently in Flex/Flash. You end up with the same problems each time. Sorry, but you'll have zero chance of convincing me about their "huge upside" (outside of super simple apps). re-frame takes a CQRS-like approach. GraphQL has gone a similar way. But, hey, the good news is that you don't need to listen to me because cursors are right there for you to use in Reagent. Given your perspective, it seems best if you avoid using re-frame. It doesn't seem a good fit for your technical aesthetics - and there's no point in fighting a framework - just use Reagent as a base and develop your own. This may interest you: https://github.com/Day8/re-frame/blob/master/docs/FAQs/DoINeedReFrame.md

mikethompson00:12:17

I'm now over and out on this discussion. Out of time. I hope this all helps. Good luck!

mikethompson21:12:51

There'll be other reasons, but those two will do @lmergen ^^

achikin16:12:10

But most of the time we consume "raw" vaules from the db. Actually you have an abstraction like this, called "layer one subscriptions" that are supposed to fetch "raw" data from the db, if I understood that correctly. Why not leverage that and create some kind of subscription-cursor? As a bonus it will be free of side-effects by default....