ANN: re-frame 0.1.7 Initial Release

599 views
Skip to first unread message

Mike Thompson

unread,
Feb 25, 2015, 6:52:23 AM2/25/15
to clojur...@googlegroups.com
A Reagent Framework For Writing SPAs, in ClojureScript.

README and source code: https://github.com/Day8/re-frame

"Derived data, flowing" in a two-stage, FRP loop.

Absolutely no Cursors!!

--
Mike

Jane Dampney

unread,
Feb 25, 2015, 6:19:05 PM2/25/15
to clojur...@googlegroups.com
Wow! No Cursors, indeed.

Really well thought out, and nicely explained.

Appears similar to https://github.com/evancz/elm-architecture-tutorial
but not the same. I like the use of middleware and love the possibility of using statecharts.





Marc Fawzi

unread,
Feb 25, 2015, 6:49:03 PM2/25/15
to clojur...@googlegroups.com
Hi Mike,

Thanks for answering my question on the Reagent list about "this.props"

With respect to the no-cursor architecture, I'm currently having a problem in trying to keep my "reusable input component" both generic, so not specific to the data structure since that would kill re-usability, and at the same time avoid re-rendering all instances of the component on the page which happens which the cursor carrying the data structure sub-tree meant for input fields on the page is changed. So when I change the value in one of the re-usable input components all input components are re-rendered because the cursor that holds that sub-tree is dereferenced inside the component.

How would your cursor-less architecture help this case? If it's hard to visualize or vague I would be happy to document it in a video.

Thank you Mike and hope to chat with you at some point about ideas I have for Reagent. I wonder if Dan is on this list too and has time to chime in?

Marc






--
Note that posts from new members are moderated - please be patient with your first post.
---
You received this message because you are subscribed to the Google Groups "ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojurescrip...@googlegroups.com.
To post to this group, send email to clojur...@googlegroups.com.
Visit this group at http://groups.google.com/group/clojurescript.

Colin Yates

unread,
Feb 26, 2015, 3:29:49 AM2/26/15
to clojur...@googlegroups.com
The Terry Pratchett quote along gets my vote.

This looks great, it really does. The intro alone adds value. My only
criticism is that of timing - where was this last year when I started
with cljs and om :). Ironically I have ended up with something pretty
close in nature, if not elegance to this and yesterday started
implementing a very similar model on the server.

Anyway, well done Mike. From all our previous correspondence this is
marked down as one to take seriously. From reading the intro that is
confirmed.

gvim

unread,
Feb 26, 2015, 7:20:38 AM2/26/15
to clojur...@googlegroups.com
At long last. I got so tired of React's "this only addresses the view
layer" or words to that effect.

gvim

Jeremy Vuillermet

unread,
Feb 26, 2015, 10:38:54 AM2/26/15
to clojur...@googlegroups.com
Really interesting !

Mike Thompson

unread,
Feb 26, 2015, 7:55:29 PM2/26/15
to clojur...@googlegroups.com
Indeed, Elm was an inspiration. As was the terrific Hoplon, which doesn't get nearly enough praise.

We all know that immutable data let's you manage "time" better, right? We're able to ignore (isolate ourselves from) the effect of time on data.

FRP is another dimension in the same process. FRP allows us to model the "flow" of data over "time". It allows us to manage the process of producing "Derived Data" (materialised views) over time. Again, it is all about doing the "time/data” thing better.

That was a big learning for me (I worry that everyone else already knows this already, and I'm just very late to the party).

Perhaps the biggest moment for me was seeing Pete Hunt (Facebook) talking at reactconf. In his talk, he referenced a particular StrangeLoop video, mentioning how it had had a big influence on the way Facebook looked at things these days, and then he talked about how it was all about "Derived Data".

When I watched the video, a small nuclear explosion went off in the back of mind. The penny suddenly dropped for me about FRP.

At that point, I suddenly understood what I had been trying to achieve with re-frame, and why I found it so pleasing to work with. It all made sense.

The key thing for me is: JUST. DON'T. USE. CURSORS. There I said it. They appear convenient, I know. They are a way of achieving reference transparency, I know. But I think they are a “local optimum”. Their use seems to get in the way of a more important data flow paradigm and they seem to encourage "control" into all the wrong places (components). At least that's my experience (I did try to love them, really I did :-)).

I know this is a controversial opinion within ClojureScript right now. OM has such an overwhelming mindshare. David is a very compelling and important character.

Anyway, I'll finish off the todomvc over the weekend. That will make re-frame a bit more real and easy to Grok.

--
Mike

Marc Fawzi

unread,
Feb 26, 2015, 9:06:01 PM2/26/15
to clojur...@googlegroups.com
Mike, 

Do you want to give a talk about it? ;)

I'm looking for speakers (local or remote) for our first Reagent meetup in SF. 

Back to cursors and enabling re-usable components. I'm not sure how isolating control outside of components can lead to re-usable components. Can you explain, please?

I'm now passing finely grained cursors to the factory returned function to avoid re-rendering every instance of a reusable input component due to the previously coarse cursor we were using. It shifts the overhead to the usage context where the user of the component has to split the atom to single-use slices and pass the the corresponding instance of the component. Do you know what I mean? I can clarify.

So far the cursor based architecture has not failed me, where my goal is to build re-usable Reagent components. 

But you know a lot more than I do about both Clojure and Reagent. So feel free to enlighten. In fact, I look forward to your explanation on building re-usable components. I'm not sold on any SPA framework where the components are hard to re-use. 

Looking forward to more chat!

Marc



Gary Trakhman

unread,
Feb 26, 2015, 9:22:23 PM2/26/15
to clojur...@googlegroups.com
I don't think cursors were really ever recommended that strongly.  It seems like query solutions like datascript/Relay seem to be the way things are going.  I think it's the next stop on the declarative decoupling train that we're all so fond of.  This project and others like it are exciting!

Marc Fawzi

unread,
Feb 26, 2015, 9:46:01 PM2/26/15
to clojur...@googlegroups.com
By re-use I mean sharing outside of the project! Angular components are hard to re-use (not that I ever used it but that's what I heard from people who have) Reagent components I'm building with cursors are easy to reuse and share via maven repo managers like Clojars. Artifactory, etc. I'm sure React components are shareable via some NPM based library. But when you talk about moving "control" outside of components are you saying that program logic is not simply a function of components coordinating among themselves? I find the Reagent cursor specially appealing because of the setter-getter function and the fact that it can serve as a callback to an async notification mechanism. 

Could you, would you eat it with a mouse? --from Dr Seuss Green Eggs and Ham


Sven Richter

unread,
Feb 27, 2015, 3:13:31 AM2/27/15
to clojur...@googlegroups.com
Hi Mike,

This looks good :-)

Do you consider releasing a library with some convenience functions and an exposed API for this?

Best Regards,
Sven

Geraldo Lopes de Souza

unread,
Feb 27, 2015, 7:32:14 AM2/27/15
to clojur...@googlegroups.com
Mike,

Could you link the StrangeLoop video ?

Geraldo

Martin Klepsch

unread,
Feb 27, 2015, 9:14:08 AM2/27/15
to clojur...@googlegroups.com

Erik Price

unread,
Feb 27, 2015, 9:44:52 AM2/27/15
to clojur...@googlegroups.com
On Thu, Feb 26, 2015 at 7:55 PM, Mike Thompson <m.l.tho...@gmail.com> wrote:
 
The key thing for me is:  JUST. DON'T. USE. CURSORS. There I said it. They appear convenient, I know. They are a way of achieving reference transparency, I know.  But I think they are a “local optimum”.  Their use seems to get in the way of a more important data flow paradigm and they seem to encourage "control" into all the wrong places (components). At least that's my experience (I did try to love them, really I did :-)).

I'm fairly new to Reagent, so as far as I can tell, cursors look great. But it sounds like you've run into situations in which they aren't helpful. Can you elaborate?

e

Mike Thompson

unread,
Feb 27, 2015, 4:06:17 PM2/27/15
to clojur...@googlegroups.com
On Friday, February 27, 2015 at 7:13:31 PM UTC+11, Sven Richter wrote:
> Hi Mike,
>
> This looks good :-)
>
> Do you consider releasing a library with some convenience functions and an exposed API for this?

Hi Sven,

The re-frame repo contains a reference implementation. It is in clojars.

WARNING: all still slightly alpha (a couple of names will get changed with the next release).

Look in re-frame.core for the API (or the docs). It is tiny. Examples landing soon.

--
Mike

Mike Thompson

unread,
Feb 27, 2015, 4:19:25 PM2/27/15
to clojur...@googlegroups.com
On Saturday, February 28, 2015 at 1:14:08 AM UTC+11, Martin Klepsch wrote:
> Strangeloop talk: https://www.youtube.com/watch?v=fU9hR3kiOK0

The talk is about "Turning The Database Inside Out", apparently nothing to do with FRP.

The discussion about "Derived Data" (streams everywhere) happens around 29:00. But it won't make sense unless you have watched everything beforehand.

re-frame tries to have Derived Data flowing in a loop -- it uses a single source of truth atom which acts like an in-memory database. The concept is the interesting part ... the implementation is embarrassingly easy.

--
Mike

Mike Thompson

unread,
Feb 27, 2015, 4:44:37 PM2/27/15
to clojur...@googlegroups.com
>
> How would your cursor-less architecture help this case? If it's hard to visualize or vague I would be happy to document it in a video.

Reframe is about overall (in client) architecture, not reusable components

We're releasing a library of reusable Reagent components in the next week or so (targeted at Chrome, so not for everyone). That will give you something to look at.


--
Mike

Marc Fawzi

unread,
Feb 27, 2015, 5:12:25 PM2/27/15
to clojur...@googlegroups.com
Will those components work within your SPA architecture and also work in pretty much anywhere where Reagent is used?



Mike Thompson

unread,
Mar 4, 2015, 4:15:04 PM3/4/15
to clojur...@googlegroups.com
Cursors are convenient. You'll get going pretty quickly with them, for sure.

But if your app gets a bit bigger you might find some code smell starting to appear.

- their use can sometimes distort the way you structure you data. Cursors want you to layout data hierarchically (which often fine) but one day you'll find yourself twisting your data structure so as to facilitate Cursor use.

- Cursors are simple extractors (which abstract away the path). But they are not about "Derived Data" or "Materialised Views". They don't deliver to your view a modified version of the data. Yes, you can modify the data in your view, but that means the view is doing too much. Take a view that needs to show the top 20 items in a vector, when sorted by attribute Y. Now imagine that you have two views on the same data each with different sort criteria. The underlying data can't be sorted two ways at once. So the view will have to start doing the sorting.

- the "write back" feature of Cursors is something I really don't like. As an app gets bigger, the control logic around updates gets more complicated. Using writable Cursors is a slippery slope towards more control logic getting put in the views.

Overall, I find that Cursor use encourages you to make views do too much, know too much, which tends to be a problem as apps get bigger.


--
Mike


. make your use of Cursors easy, rather than modeling the right way.

they can sometimes encourage you to structure your data in a tree-like way ... even though certain way.
- The main problem I have with Cursors is that they are writable.
I've found that they encourage control logic into views. I prefer my views to be very passive.


Marc Fawzi

unread,
Mar 4, 2015, 4:38:29 PM3/4/15
to clojur...@googlegroups.com
Not defending cursors (I'm new to it all, including ClojureScript), but someone has to play devil's advocate to your devil's advocate :) 

<<
- their use can sometimes distort the way you structure you data.  Cursors want you to layout data hierarchically (which often fine) but one day you'll find yourself twisting your data structure so as to facilitate Cursor use.
>>

Wait... are you saying that I can't have a transform function that processes my data from the server before putting it into the atom? After all, unless you have a BFF (backend for front-end) you'll almost always need to transform your data for the view.

<<
- Cursors are simple extractors (which abstract away the path). But they are not about "Derived Data" or "Materialised Views". They don't deliver to your view a modified version of the data.  Yes, you can modify the data in your view, but that means the view is doing too much. 
>>

Again... the "view" doesn't have to derive, you can derive in transform functions that can be used by any view and can be chained etc

So I'm still not getting it. Are you saying that cursors "encourage" rather than "require" and going cursor-less provides less incentive for writing bad code? I think writing bad code and cursors are two separate topics.





Erik Price

unread,
Mar 4, 2015, 5:47:52 PM3/4/15
to clojur...@googlegroups.com
Cool, thanks for following up, Mike. I agree with pretty much everything you describe, especially writing to cursors from within a Reagent component. We're using an approach that I'm really happy with (and may blog about at some point), which mitigates the problems you mention even though we are using cursors. Cheers!

e

Marc Fawzi

unread,
Mar 4, 2015, 5:57:27 PM3/4/15
to clojur...@googlegroups.com
Writing to cursors from within components (and generally changing app state from within a component) is not a good pattern. You want to have clearly defined places where state mutation can happen, and in the normal case you put those in event handlers (sitting outside the component but being passed the cursor from the component which can be specified during event setup)

So this is all about architecture choices, not cursors vs no cursors. 

Daniel Kersten

unread,
Mar 4, 2015, 6:52:00 PM3/4/15
to clojur...@googlegroups.com
I've been using Om (and therefore cursors) heavily for almost a year and am finding myself moving further and further away from cursor. The issue for me is absolutely the write-back - allowing your views to write to them encourages your code to do so and encourages a style where your ui/dom event handlers mutate data. I feel like this is an anti pattern that makes it difficult to properly manage your state as the application grows unless you are very disciplined. I much rather have unidirectional data flow and have ui/dom events only dispatch messages back. So view model data -> ui -> messages

The messages can then be handled to update the view model or whatever in a managed way. It's very similar to flux and similar architectures.

Mainly this buys you purer (in the functional sense) code, easier automated tests, easier to understand/reason about flow of data and ultimately a simpler design.

That's my opinion at least.

Marc Fawzi

unread,
Mar 4, 2015, 6:57:58 PM3/4/15
to clojur...@googlegroups.com
<<
 I much rather have unidirectional data flow and have ui/dom events only dispatch messages back. So view model data -> ui -> messages
>>

Ah! Enlightenment. 

Thank you.



Marc Fawzi

unread,
Mar 4, 2015, 7:26:31 PM3/4/15
to clojur...@googlegroups.com
btw Daniel, 

If you care to discuss more deeply, what we do is use fine-grained cursors so the two-way cycles are avoided (since each cursor updates only the data for the given component *instance* and not for any other component or any other instance) 

But I like centralizing state changes into a state manager and your idea of event handlers emitting state change events is very useful to make that work.

Thank you again for your input.

 

Daniel Kersten

unread,
Mar 4, 2015, 7:48:15 PM3/4/15
to clojur...@googlegroups.com
I do find cursors fantastic for reusable isolated components. For example if I have a widget that edits some data, I find it useful to give that widget a cursor that it may modify, but it needs to be managed by the parent so that what happens to the data is transparent to the widget. The parent might then actually dispatch messages and the cursor is only really for one layer on the boundaries. Reagents (r/wrap data func ...) seems ideal for this.

I hope that makes sense - typing on a phone right now. I'd be happy to discuss more tomorrow when I have a real keyboard.

Marc Fawzi

unread,
Mar 4, 2015, 8:06:14 PM3/4/15
to clojur...@googlegroups.com
I understand regarding nested components, makes lots of sense and r/wrap should help, but I've yet to use it personally since I'm just literally starting to write my first Reagent app....

I think the missing part of the picture you're painting is that components can have specialized instances, so a reusable input box may take first name, last name, or email or etc, and sending the whole form-data sub-tree for input to the input component (i.e. first name, last name, email, all that) means that typing the first name into the input box will cause all other instances of the input box (ones holding last name, email, etc) to update. So I tend to send down only the slice of the atom that is required by the given instance. 

I'll present a more comprehensive architecture including State Manager as a re-usable abstraction (!)

Please keep discussing to whatever depth necessary, I'm sure my thinking on this is still lacking. 

 p.s. the 1st meetup in SF will be announced tomorrow so a bunch of us can talk live about this stuff
Reply all
Reply to author
Forward
0 new messages