This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-10-20
Channels
- # aws-lambda (7)
- # beginners (113)
- # boot (17)
- # cider (4)
- # cljs-dev (4)
- # clojure (65)
- # clojure-greece (3)
- # clojure-italy (7)
- # clojure-russia (10)
- # clojure-spec (37)
- # clojure-uk (20)
- # clojurescript (76)
- # community-development (2)
- # cursive (24)
- # data-science (9)
- # datomic (9)
- # emacs (1)
- # fulcro (2)
- # graphql (11)
- # hoplon (13)
- # juxt (15)
- # leiningen (1)
- # off-topic (36)
- # om (1)
- # onyx (59)
- # parinfer (41)
- # pedestal (7)
- # portkey (60)
- # protorepl (4)
- # re-frame (345)
- # reagent (7)
- # ring-swagger (16)
- # shadow-cljs (121)
- # spacemacs (30)
- # sql (6)
- # uncomplicate (2)
- # unrepl (9)
- # vim (13)
- # yada (2)
Thanks @pesterhazy ! I was suspecting that a bit, but in that case I imagined the error would be re-frame: no :event handler registered for: :some-keyword
I'm looking at reframe to use over vanilla reagent and am trying to understand what problems it solves. First question is how a dispatch is a better abstraction than just having a component call another function to handle an event. Reading this guide, and under Event Queue the problem would just as easily be simplified by breaking up the function. https://purelyfunctional.tv/guide/re-frame-building-blocks/#event-queue
presumably you've read the most remarkable re-frame readme https://www.gitbook.com/book/d8/re-frame/details, @ajs, it's about structure for web application development, and might be best to see from another angle https://purelyfunctional.tv/article/why-re-frame-instead-of-om-next/
I've read the readme but I still don't see why you can't structure an app just as well in vanilla reagent. You can keep all your app state in one place without reframe if you want, and you can use reagent reactions instead of reframe subscriptions, and you can factor out user events as normal functions instead of reframe dispatches. What am I missing that reframe adds that justifies the extra complexity? The one I notice is automatic de-duplication, which is a nice performance optimization, but what else?
@ajs the benefits accumulate across a lot of dimensions. Don't go looking for one thing, notice the web of things. I'm in a bit of a hurry, so i can't comment fully, but this will help: https://purelyfunctional.tv/article/react-vs-re-frame/ de-duplicated subscriptions handlers is one thing you've noticed. Also have a look at effect handlers. Compare something like re-frame-async-flow with Redux-Saga etc.
Apart from anything, Redux etc is trying really hard to be functional, and use immutable data. With ClojureScript you don't have to try.
Like i said, there's a bunch of things which occur over many dimensions
Sorry
Bugger. I'm a bit out of time.
Sorry reading about Redux as we speak managed to confuse multiple source of imformation in my hurry
Reagent = works well in the small Add re-frame when apps get more complicated
That's rather vague. I don't yet see why you can't structure a reagent app well without reframe, as per my prior specific examples.
@ajs ^ yeah if it feels like you can do what you want with reagent, then probably best to use that. I'm very happy using re-frame now because of the structure it provides, but it's a personal thing. I came from another place where we used reagent, and we ended up with lots of different ways of doing things, and re-render issues e.g. because there was no common structure, every developer reinvented bits and pieces
if you can structure it well without reframe, then do it!
What kind of re render issues? You mean unnecessarily forcing re renders because too much state was passed into a function, for example?
yeah to take a specific example, we ended up using "higher order functions and templates" where we passed callbacks and render-fns into other functions.
however the passed in anonymous functions /callbacks don't compare equal, even when they are so we ended up with some cases where we were unnecessarily re-rendering
I think (after I left) they ended up passing in something like a reframe event vector
I guess I don't understand what the main reframe API adds that is not already quite possible and simple with the regular reagent API, for the most part.
Subscription tasks can be mostly just done with regular reagent reactions to solve some of the same issues in that thread, no?
and side effects with subscription https://github.com/Day8/re-frame/issues/255#issuecomment-299318797
@lovuikeng thanks for the links I will read over them today. The issue is about API complexity and adding it only when necessary, and many of reframe features are not that distant from regular reagent.
again, it's all about structure
, @ajs at the end of the day, yes, underneath it's still reagent/react, and then some
There are certainly many things that reframe forces that you can do quite easily without it. Perhaps some folks just need the discipline written into the tools to make things easier. But you can structure an app well if you have the features to do so, and reagent already provides those features.
you see, @ajs, re-frame isn't a new framework out of the blue, @mikethompson has done more than a wrapper around reagent, way more than it
@ajs how big is the team you are working on?
Just me. I currently have about a 20k line Om Now app, and am about to start another, but probably won't get as big. Researching practices now.
Did you have any problems with om now?
i like all the help i can get from my libraries to structure my project... it lets me concentrate on business features!
Om Now doesn't have reaction type stuff, but reagent does. Not sure why I'd need subscriptions on top of that. Reactions are a useful feature I wish I had in Om Now.
@ajs if you don't mind me asking what is the new app going to do, how big will it be, how long will you need to maintain it for, will you always be the sole maintainer, or will it need to be passed on to others at some point?
@mccraigmccraig my point is that I don't yet see what reframe is offering that is not already available and easy in reagent without extra API complexity, but I guess I'll keep reading. Not really getting specific answers here, but perhaps the issues tracker will illuminate things.
there isn't much API to deal with in re-frame, true? just dispatch
subscribe
reg-effect-x
that's all pretty much it
@danieleneal based on my Om work I'd guess it will be between 5k and 10k lines, probably just myself for a while. But you can structure a reagent app similarly to reframe without any extra effort? Put state mutation functions in one file, those are your events, call them from components. Use reactions, they can be specified in another file. Etc.
it sounds like you're quite disciplined so that will probably work well
I'm not trying to be an antagonist, I just want to understand the point of reframe beyond vague phrases like it "it's the best framework out there "
one extra specific bit you might like to borrow from reframe are the :effects
handlers. It's not immediately obvious when making a new reagent app that it would be beneficial to describe your side effects as data, and implement the side effecting bits separately. However it makes testing/mocking and introspection much easier, and this was something which we ended up doing, in our own roundabout way much later
And I just don't see what the reframe API adds that is not already offered in reagent. Edit: cool, ill look into effects to see what they offer.
don't worry you don't sound like an antagonist, it just sounds like you want to really understand the benefit before picking up an extra dependency
and that sounds totally reasonable to me
to me the main benefits are more cultural than technical
1) if someone else joins the team, I don't have to write the docs because there's already a bunch of material out there
2) If I hit a problem there's a chance that someone else has already encountered it and addressed it (see e.g the libraries async-flow-fx reframe-http-fx, the :effects
handlers described above, passing in vectors instead of callbacks etc), re-frisk for introspecting, re-frame-trace for performance, re-frame-test for testing
but if you're gonna be the only person on the team (1) is irrelevant, and if you're a strong developer (2) is probably also irrelevant
I've gotta run but thanks for the pointers. I'll do some reading up on those specific things.
@ajs Having experience in both vanilla reagent and re-frame, i definitely would go for re-frame. Few benefits: - As components get more complex, storing state in local atoms can become annoying, since you have to pass a lot of stuff down to child components, and then bubble stuff up through callbacks. This can become callback hell, unless you dirty your Views with lots of boilerplate. - With re-frame, you can make a set of subs/events that operate on the widget, and the view becomes a lot cleaner. - The events / subscriptions you register become a decoupled, separate API to your widget. So for example, you have a drag/drop widget, but outside of this render-tree you want to show the position of the mouse and whether or not the drag /drop collides with a div on the screen, ie. in some sort of overlay in the screen. Since you’ve already made a subscription for this, you can use the data from this on completely other places in the GUI. You could implement this stuff in an atom inside the component, but now you can’t get that value out of it, unless you provide a lot of callbacks.
I have 5 reasonably sized apps in production using re-frame, and at first at some points i was stubborn/lazy and stored state locally in an atom
but in lots of places i factored it out into events/subscriptions, and the code in my components is much simpler now. And it provides better flexibility/extensibility, since the state of the component can now be (in a controlled fashion) accessed from outside
Got a sub for a list of records, called :todos, nice. Now you want one that is sorted, you can make a dependent subscription. It’s just a little 2-3-liner that can do this
as my web apps become larger and the gui more complex showing the data in multiple fashions etc, re-frame helps out a lot
@ajs i am a full time cljs contractor, have used vanilla reagent in many large applications rather successfully. I have seen several code bases misuse re-frame and the result is quite opaque. Discipline is needed whether you use vanilla reagent or re-frame .. people are always going to reach for local atoms when the shouldnt or put effects where they dont belong. The things re-frame does fantastically well is it has a community and everything is represented as data.
@kah0ona do I understand that you mean the regular subscriptions and events that operate on the single global app state would also be used for manipulating what is conceptually just local data for particular component and its children? In other words, you're talking about taking state out of components and putting it into the global state, but with an easy way to deal with it as if it were just local. Or, are you talking about an entirely different place that this local state is being stored, but with the same API as dealing with global state?
No i mean, say you have a Todo-list view. Now, on the right top of the screen, completely outside the render tree, you want to show a widget showing ‘6 todo’s done, 7 todo’s open.’
since your todo-list widget already has a subscription (rf/reg-sub :todos ....)
, you can make a dependent one that returns a tuple of ’open todo’s and ’closed todo’s, and use that on a completely different part ofthe screen
@lovuikeng is re-frame-trace going in the template? If you open an issue i can try and add thay when i get a chance
these kind of reqs happened to me quite a lot, and often later than the first requirment
and hten you have to refactor it, but with re-frame it’s extensible without touching base code, yet fully reactive
if it’s in a global app db, it keeps persisting, so some wizard-widget that is in step 3 and you ’re working on it, stays in step 34
@kah0ona in your todo example, I wouldn't have ever put those into local state anyway, I would consider that global state. In which case pulling that out of global state from any widget would be straightforward, regardless of whether you're using reagent or reframe, wouldn't it?
@lovuikeng awesome, then in it goes 😊
I don’t remember saying that? Happy for it to be in there, but it’s a little way away still
yeah so it’s not that you can’t do it with reagent per se, not at all. But re-frame gives you really nice tools to work with this in a nice fashion
what i do, per set of widgets i create a separate file ‘subs’ and ‘events’ and i add handlers/subscriptions there specific to that part of the ui. My view becomes simpler, and the API ‘forms’ itself in the subs/events files.
The Elm architecture, for example, doesn't even have a concept of local state. All state for anything is stored in the global state. So some of these concerns simply go away once you accept that you shouldn't use local state.
might as well use re-frame then? because then you get some ofthe benefits as mentioned above (ie. the cascading subs, and the events with side effects (reg-event-fx)
How are composing subscriptions different from composing regular functions, where instead of subscriptions you just use regent reactions that are calling out to regular functions for query operations? Seems just as simple to me to separate concerns using good all practices of functional programming that we are all used to, I still don't see how reframe would give me a structure that I can't just as easily do without it.
I realize I am playing devils advocate but it may be the only way for me to get to the heart of the matter
And ill double down by saying reagent with discipline or re-frame .. also with discipline. Id rather read a vanilla reagent app of a lazy developer than a re-frame app of a lazy developer.... re-frame adds extra code. What that extra code buys you is testability, and predictable side-efffecting. However, a mangled re-frame app can lose benefits and just be a larger app that uses local ratoms for inputs and side effects happening in the wrong places.
yeah well for me the structure + sugar (if you wanna call it that) that re-frame adds yields a very nice end result in terms of maintainable code. Coudl it be done with vanilla? probably. But now with re-frame you also have a lot of docs + pointers on how to be smart about things.
but it doesn’t mean it’s particularly hard to be disciplined in using re-frame though
could very well be that the benefits of reframe won't really be apparent to me until i build out something significant in reagent, see what problems (if any) I hit, see how they'd be resolved with reframe. If I structure a reagent app where components just use reactions that are in their own file, and call regular functions that act as mutating events, then it should be easy to replace those with reframe's api without much refactoring later, if necessary.
My advice to @ajs is to use vanilla reagent, and there will be a moment when you reach for re-frame and itll make sense the subtle advtanges of data vs functions ... however, it may not be enough to persiade you and that is totally fine. If you do like re-frame at that point, the promising thing is the re-frame community will only have kept growing in the meantime :) As an aside, i personally write and prefer vanilla reagent because i am a 1 person developer. If i was on a team, id use re-frame.
I have an app that is pretty large now, ie. more than 1000 man hours of work in it, and one of my favourite things that hold up really well is the frontend code and the way i can reason about it
i've gotten to the point, probably from age, where the less code the better, the tinier the functions the better, the simpler the APIs, the better. so that's the bias I'm coming from.
so last 2 years clojure development rather than java already made stuff LOTS more simple
I see young devs in college or early 20's who jump in and go whole-hog on every latest framework. Well, great. But I'm reminded of Hickey's recent conj talk where he said young minds have more room to sit with puzzles. I just want to understand what I get from putting together the puzzle before I buy it.
though it is something that’s worth trying out though, ie. make a little test app with it
I'm coming from a 20k line Om Now codebase so I have a frustrating picture of the problems that quickly appear in large apps. For me, a lot of the issues in Om Now would be resolved with reactions that don't require parent components to pass in state, which Reagent, Re-frame, Om Next all provide in their own way (reactions, subscriptions, queries). So about 85%+ of my frustrations are already resolved just in vanilla reagent.
@ajs if you take architecture and community off the table, re-frame buys you a simpler unit testing experience
I'm a failure at unit testing. i just hate it and rarely do it. Hopefully there are no recruiters that just saw me write that. But i've had a successful career in enterprise with Om Now without doing much testing. (yikes!) (or... yikes?)
Most cljs devs, myself included, slack on tests so youre not alone ... but maybe youd be delighted to do so if it was low hanginf fruit ;)
didn't I read or hear somewhere, that Rich himself took awhile to be convinced on the benefits of unit testing? I seem to recall a talk he gave where he put it in the same category as static typing, claiming that all bugs in the wild passed a type checker and also passed testing.
To each his own on the perspective and degree of unit tests, but re-frame gives you the option (at any point)
unit testing a UI-based or UI-heavy codebase seems like a lot of work. How to capture human behavior in testing? I'd rather give my app to a few users, myself included, everyone plays with it aggressively, that's about the best testing I've done. Up to now, 4 years later of professional cljs development, it's proven to be enough.
Im more referring to unit tests for sorting or filtering logic or handling maybe cases, etc. Testing the actual rendering of the stuff, re-frame is no more special than reagent.
these days, I'd want to lean on spec to instrument functions or generate tests automatically. holloway recently tweeted out about how a well-spec'd function does't actually need a separate test. i like that kill-2-birds approach.
if you are going to go through the time to write tests, why not just write good specs instead?
incidentally, looking at reframe-trace, it looks a lot like an Elm Reactor demo I saw a few nights ago. I thought that was really cool, so a tool like that would be a convincing reason to use reframe, assuming something similar wasn't possible in just reagent.
@ajs if you haven't seen it yet, another cool one is re-frisk (works in both reagent and re-frame ... but more stuff for re-frame) https://github.com/flexsurfer/re-frisk
I was using re-frisk until i noticed it leaked metadata. I reported that and I think it was finally fixed, but I still haven't used it again.
^ what do you mean leaked metadata
cool thanks
I'm using re-frisk 😬 and rely on it heavily now 😄
ah cheers
as if not enough of ui testing already, here is one handy just in case https://github.com/brosenan/reagent-query
it certainly don't mean much to those battle-tested clojurians, but this piece really makes re-frame shine https://opensourcery.co.za/2017/02/12/using-semantic-ui-react-with-re-frame/
@lovuikeng have you seen soda-ash?
does anyone know if re-frame-trace has a remote mode for use with react native
if I were to clean up syntax for interacting with semantic UI, I think I'd rather write wrappers around soda-ash than interact directly with Closure and the raw components, but maybe that's because my JS foo is not strong
we all have our own "dream" frameworks, don't we? Unless we get the luxury in taking it up all alone, without a common community-based matured project to work on, it's very hard for a team to follow along... of course unless we're all created equal
@lovuikeng what would your preferred syntax be? Or do you just mean that you'd prefer kebab-case?
i personally find true FRP (like what Sodium is) harder to conceptualize than declarative stuff like React/Reagent/Re-frame
honestly, @gadfly361 i'm very new, too new, to clojure, I like the way opensoucery doing component, no wrapper magic... hahha
Rx stuff applied on top of OO libraries is equally perplexing to me, despite the popularity and claims of amazement. It's just hard to figure out at first.
@lovuikeng embrace the wrappers. clojurescript, after all, is basically a wrapper around JS 😉 (don't hit me)
hate to bring this up again, wouldn't it be great if we too have an event-driven based backend to clue our re-frame app?
@lovuikeng have you heard of Fulcro or Om Next ? I'm teasing of course, but that full-stack cohesive story is addressed in the community, but currently more in the Om world
i don't know what you mean about reddit but if you are interested in a React<->Server solution, you should at least look at Fulcro for fun reading material
Yeah I've read that thread a couple weeks ago but not sure what that has to do with your question about full stack integration with a front-end React app
I don't agree with 99% of the contents by the author, I do find frameworks like OM, fulcro don't help much for new comers, only bring confusion
I personally don't see the problem for there to be "competing" libraries that overlap in functionality. Om Next and Re-frame take different approaches with different compromises and workflows, and it's nice to have choices depending on a project. If your concern is fragmentation, I consider that a healthy benefit of an active community.
Just like I don't want to be forced to used re-frame if I can work well in reagent, it would'n make sense for one library to "take over" if another one offers alternative solutions better for some tasks
of course, this is partly why Elm is popular among those who use it -- it is a single, opinionated way to do a bunch of things in a cohesive and very simple language, without choices over libraries, frameworks. and that works very well for a lot of things, but then you are left with those situations when you need something that goes outside that box, and it becomes more involved.
re-frame is definitely a lot more complicated (and powerful) than Elm. You can learn and be very productive with Elm in one day.
productive including learning the language and all its features for virtual dom rendering
True, but elm isn't parasitic 🙂 https://www.youtube.com/watch?v=roYaikwyaKw
re-frame is relatively complicated than elm mainly because we need to know clojurescript+closure+reagent, but elm is elm
David discusses his admiration for Elm in that talk. He seems to be making the case that it is parasitic.
i have given it a spin, but as I mentioned earlier, i'm going to go with vanilla reagent for awhile to see what, if any, obstacles I get. i still think that nearly all the key architectural foundations in re-frame are just good practice regardless of framework and no particular library is needed. but for a couple of points mentioned earlier, if I find that certain behavior is desired, I might make a switch later
@ajs This is almost an FAQ, and I really need to create an entry for it because I always have the same response :-) I'm copy and pasting here ...
You can absolutely use Reagent by itself if your application is simple enough. BUT if you just use Reagent by itself then you only have the V bit of an application. As your application starts to get larger and more complicated, you will start to create an architecture which adds control logic and state management - let's call them the M and C parts of MVC, even if we aren't using MVC - and you'll be creating the architecture even if you don't think you are, you are.
So then the question becomes: is your architecture better than re-frame's or not? And some people prefer their own architectures and would answer "yes" :-) Fair enough. Basic Reagent has some help in the form of track
etc. You can certainly build up from there.
I think the only danger arises if this process is not conscious and purposeful - if someone creates a dogs breakfast of an architecture and doesn;t even know they've done it.
I've had MANY people (20?) privately admit that's what happened to them ... and then they swapped to re-frame to get some structure back.
So, my advice is .... if your application is a little more complicated, be sure to make a conscious choice around architecture, because one way or another you'll be using one. You will be creating "an alternative re-frame"
This is a really useful answer definitely worth an FAQ entry if there isn't one..
if someone creates a dogs breakfast of an architecture and doesn;t even know they've done it.
-- definitely seen that happen 😄 shhhTo put that another way ... if your thought is ... "I'll just use Reagent" and your app is larger .... then you'll be creating something "in addition" to Reagent. This "additional" something is what re-frame normally supplies.
Thanks Mike. Here's basically where I'm coming from. I've worked on a rather large (about 20K lines) Om Now enterprise app for the last 3 or 4 years. Om Now doesn't have the architecture features of either Om Next or Re-frame (except for the single global app state), but it works well. Nonetheless, for the same reasons specified by the famous CircleCI blog post, it suffers from the lack of component independence from an app state tree. Reagent's reactions solve this issue in many ways. My argument is, if I have a file of reactions instead of a file of re-frame subscriptions, and if my UI components call out to a file of regular functions, instead of a file of re-frame events, and I use a single ratom, then I'm getting right there a big boost to productivity over Om Next and many of the benefits of a re-frame-style workflow, but without the specifics of re-frame. I don't get access to certain tools that might be useful later, like the nice FX libraries or de-duplication, but if I don't need the optimization or those specific FX, then I'm basically there. I can always refactor such a style of pure reagent app later to use Re-frame because it mirrors how re-frame does things. But if I don't need the extra stuff, it's still quite easy to do this kind of basic architecture in reagent without an added dependency and an added API layer.
Sounds like you have a pretty clear path mapped out.
It would seem to me that if you sit down to use plain Reagent but with these three stipulations, you basically get most of a re-frame-style architecture: 1) Only use 1 global ratom. 2) use reactions in components. 3) don't directly mutate that global atom in your components, instead only mutate it using functions that your components can call.
1) Reagent reactions vs subscriptions: it looks like reactions alone work just fine. E.g. compare re-frame subscriptions to reactions only code: https://github.com/Day8/re-frame/blob/master/examples/todomvc/src/todomvc/subs.cljs https://github.com/metametadata/carry/blob/master/examples/todomvc/src/app/view_model.cljs But maybe I miss the "de-duplication" feature. 2) Side-effects as data/DSL is a more opinionated part of the framework. Personally, I prefer to use functions for side-effects and then in unit tests apply all the usual mocking techniques.
single state atom is a very good idea, for sure
@ajs @metametadata yeah, the first version of re-frame asked the programmer to use reaction
(in fact, re-frame invented the technique). But, with experience, I found there were some subtle gotchas and it felt clumsy and not pure, etc. Subscriptions was my solution ... along with the recommendations around using Layer 2 and Layer 3). Paper cuts avoided.
But, as I explained above ... many love to cut their own tracks ... which is an approach I understand very well.
i'm not thinking or wishing to re-invent any wheels, my argument is just that it seems that much of a healthy architecture model is already possible in the wheels reagent provides on its own, without any major work. though i'd be curious how you mean the semantics around reactions significantly vary to subscriptions.
Coming from different angle/perspective: I'll just say I've come from react+redux background and I knew I wanted something like re-frame, and I'm pretty happy about it. I'm not really concerned about conceptual overhead over reagent, I find the fact that re-frame suggests a certain architecture rather nice, I like the fact that re-frame has opinions about app structure, it allows me to sleep an night any not worry (or worry less) about keeping discipline with plain Reagent.
@ajs Hmm. Well, you've said exactly the thing that warn against above. :-)
But it is midnight here ... time for bed
but the way, I came from coldfusion (CFML), later Spring, and I've found re-frame too attractive to ignore
that's cool, but these are the kinds of vague comments without specifics that don't really help point out exactly what you are getting in re-frame that a simple, well-defined architecture in reagent doesn't already allow you.
I also like to use r/track instead of subscriptions personally, I don't see any downsides
The main benefit of subscriptions is that they're beautifully documented in the re-frame docs – a big advantage when working in a team
Could be that there is a lack of clear writing on the benefits of re-frame that are specific to that library on a technical level. There is a cultural embrace of it but I don't see much discussed as to why, and that's all I'm trying to figure out. For example, the re-frame readme has vague wording about magic and doing physics, but not a lot about what it achieves that is not already straightforward in reagent. If I turn elsewhere, I see the PurelyFunctionalTV tutorial which does worse: it shows a convoluted input function that mutates state inline with its click handler and appropriately says that is bad, which it is, then it says the proper solution is to use re-frame events. Except, the solution it provides is no better than just following good programming practice of not asking one function to do too much, and simply using a regular function that handles state mutation for you, and having your input component call that function instead, is the heart of the solution, which is independent of re-frame; it's just good programming practice.
You could generalize your arguing to everything though; by good programming practices you indeed never need a framework. But when you apply all these good practices, you probably end up with a mini framework you just made. So I guess you are right in this sense, but that does not mean that re-frame in itself is pointless. If it helps provide structure and a certain idiom on how to do things, that provides guidance and keeps productivity up without making a mess of it.
there is a difference between writing well-organized code and writing a framework; organizing a reagent app well is not the same as writing your own re-frame-like library. you can organize a reagent app well without writing special wrappers or anything like that. no need to re-invent, as you said in the other thread. but i'm not trying to convince you of the need for re-frame for most app development, i'm trying to convince myself. sounds like from several others here, i'm on the right track to proceed as i am.
Not sure I agree - I think of re-frame more as a tutorial on good practices when writing UIs with reagent, and it accomplishes that goal well
IIRC it started out as a Readme without any library code
this is interesting -- if you think of re-frame almost like an example architecture for using reagent, then that makes a lot of sense, and also proves my point that reagent already gets you really far for a good app model on its own
Right
@pesterhazy I do love the genesis of a good myth. But the README didn't come first, it came with the code. @ajs I'm beginning to feel you never read my original response.
@mikethompson I'll stick with my story then! 🙂
@mikethompson if you are talking about the MVC comment, yeah i read that. I guess I don't see how simply writing a reagent app with reactions in one file, functions that mutate in another file (for example) is as big as "inventing an architecture"; after all the re-frame template basiscally does this for you, you end up with good app separation of concerns either way. reagent remains the backing. i'm not trying to be antagonistic, I just don't see how a good (and simple) reagent setup is so inferior to what re-frame is providing, when the fundamental mechanics are similar.
i can understand if a developer has never written a react-type app before, re-frame can impose some important discipline. but it's easily learned discipline, is my point, just good architectural advice.
anyway perhaps there is more magic to re-frame than is apparent to me now, and after working a lot in reagent it will become clear what i'm missing.
I actually agree on the docs part, it was hard to start for me, I had to look into code. and "compile" it in my head
this is interesting -- if you think of re-frame almost like an example architecture for using reagent, then that makes a lot of sense, and also proves my point that reagent already gets you really far for a good app model on its own
@ajs As far as I can tell it comes down to this. Reagent gives us the wheel, engine, doors and steering wheel. You are coming from a standpoint where you feel that “since Reagent gives you all the parts to build a car, why don’t use just build the car. There is no reason to use a pre-built car with certain restrictions.” That is a perfectly valid stance and no one is saying you shouldn’t do that. However, re-frame has already built the car, so those of us who don’t want to build a car, we just want to drive one can choose to do so. We’re willing to accept the restrictions that re-frame introduces for the convenience of having a standardized ready built car.
So metaphor aside, if you think you can build up the equivalent structure using pure reagent that’s absolutely true, but many of us, myself included, don’t want to. So we turn to re-frame.
and my argument is, why is it a car? it's not so complex as a car. it's just separating out concerns for functions like you should do in any good program.
As for the tangible benefits you seem to be seeking that pertain to re-frame vs reagent I think you are answering your own question. If you use the pieces of reagent together in a way that models the re-frame architecture you end up with a decent model which is why re-frame is beneficial. The issue lies in the fact that reagent does not dictate how you put the pieces together and as such can end with a “dogs breakfast” of an architecture.
i agree and i feel like re-frame is the better option for someone who has never worked in the React space before. but if you have, a lot, then you already know the (basic) steps to take to avoid a messy architecture, and they are not so complicated as a car 🙂 it's just good program design.
This is exactly the point @mikethompson was making. If you are proficient and feel you can make something better then go for it. I don’t want to and I feel that in terms of complexity re-frame is not complex as compared to when I was trying to learn Angular (several years ago mind you). There is no “ultimate” framework, they all make tradeoffs and decisions for you. Lot’s of us feel that re-frame achieves the desired balance for us. If you think it takes too much, then it’s just not for you.
I guess the confusion for me is that various writings or conversations suggest that re-frame is solving really big problems, and I don't see what those problems are, or why they are so big, and that confuses me. but that could just be because of writing Om code for so long that the challenges feel like old hat and the solutions seem simple. perhaps the experience is different for someone new to the space.
Seems like a common problem with frameworks: they glue together a number of patterns but don't always convincingly explain why the patterns were chosen in the first place and how they are better than the alternatives (@ajs main question). Examples from the top of my head related to re-frame: interceptors vs. HOF/middleware, reactions vs. subscriptions vs. Rx vs. ..., plain functions vs. FX as data, multiple apps vs. a singleton app. Examples common to Clojure: error handling patterns (return values vs. exceptions vs. Slingshot exceptions vs. monads vs promises vs. conditions), argument passing patterns (positional vs. keyword), functions vs macros, etc. etc. The good thing (at least with well established frameworks like re-frame) is that you can be sure all the prepackaged mechanisms will work nicely together in the long run and the edge cases are well-known. I thinks this is one of the points @mikethompson made: one can always come up with the custom architecture but devil is in details and the problems can arise several weeks in the project. E.g. you can suddenly understand that your architecture doesn't work nicely in async scenarios, you can't add a time-travelling debugger because there's no notion of events, etc.
And now that I typed it I can see that I mostly reiterate what was just discussed.
@ajs It is solving really big problems … the issue is … you’ve also already solved them so to you they aren’t problems any more. Re-frame development to me was a massive shift in my thinking about how to structure and maintain large scalable applications
ha @metametadata no that's good, a synopsis of details is always good in a discussion that is 90% lacking in specifics. i think that evangelism and emotion are natural human expressions that crop up in discussions like this, and tend to obscure or entirely omit hard raw technical specifics, which is what i've been after
You could generalize your arguing to everything though; by good programming practices you indeed never need a framework. But when you apply all these good practices, you probably end up with a mini framework you just made. So I guess you are right in this sense, but that does not mean that re-frame in itself is pointless. If it helps provide structure and a certain idiom on how to do things, that provides guidance and keeps productivity up without making a mess of it.
It's easily to see that in a couple of months those who worked on reagent would think it's only this thingy , why that?
i don't see the point of debating if we only try to convince ourselves that we are simply better than others
you don't go to a family and say it's pointless to keep the family since there already exist some others
I really have enjoyed reading this “why re-frame
discussion. I’ve thought about similar things. One thing that hasn’t been mentioned that I was surprised by was the “event handling” architecture in re-frame
Normal dispatch is not synchronous, it can be delayed to a later point, also there are interceptors directly supported here - which was briefly mentioned
Also, I may be wrong, but I saw an issue in re-frame
not long back that discussed the possibility of being decoupled from reagent
and just using it more as a possible backing implementation. I think that may be a stretch too of course, but I can’t find the re-frame
related issue, bu there is https://github.com/chpill/re-frankenstein
That is at least interesting to me that re-frame
could sort of be an abstraction over this. However, I like reagent
@mikerod those are some good points, thanks. yes i like discussions like this too, it's important to question why particular tools are in place from a technical standpoint rather than just a cultural one. i've received some good feedback on both "sides" of the debate.
thanks, that is reassuring. my intention is not to make anyone feel like they should defend their workflow, but rather for me to understand it, without all the vague hyperbole.
I will say that I had a few messes I created for myself with reagent
and not managing these things well. the re-frame
docs provided me with a lot of inspiration on how to rethink some of my issues I was having - in just pure reagent
but some solid good details have emerged sporadically in the discussion, which has been excellent
@mikerod ohhh, thanks for that!! As someone with very superficial re-frame knowledge, this whole thread was reading like: > "I don't want to use re-frame, I just want to - (goes on explaining exactly what I thought re-frame did)" 😅
However, I’m increasingly getting a bit more convinced that I may buy into re-frame
. I have a fairly large reagent
only app now. I’ve been trying too experiment with converting and see waht things I liked or find to be advantages. However, I think you have a strong point that there is a middle-ground of just using structured usage of reaction
and event functions.
there are some tools available in the re-frame world that -- if you need them (and by the looks of it on github, not a lot of people need a lot of them), then re-frame is a no-brainer. but if you don't need them, the decision becomes more nuanced.
I think you may get less, from that approach and may end up solving some tricky issues that re-frame
solves already, but you get that at the benefit of just less “stuff” to understand when you get into the weeds on a tricky situation.
re-frame
does seem to have some pretty nice tooling now, as was discussed in this thread
Also, there may be some care to take to avoid leaking reactions (not having them properly disposed), I can’t say I can give you examples though hah
I just know it is something to think about. It has came up in re-frame
issues before and I think some of the patterns help avoid such things
I haven’t switched to re-frame
yet though. Just experimenting and wanting to try to understand the tradeoffs. So this has been a great conversation to read.
A question I have that isn’t entirely related, but does anyone know of any example “real world” sort of apps out there that are open-source with re-frame
? I think things like this are hard to find in general, but it’d be awesome to be able to see some code like that that showed it being used for non-todo-list sort of things (good examples for tutorials and starters, but limited).
although the funny thing is, i now have some pretty complicated UI going in my apps (proprietary unfortunately), but it’s very mostly of a similar complexity as a todo-list example. Just more of it
I did make this last week, need it for a new project, which features a few more complex subscriptions, although to be fair it’s alright complexity wise https://github.com/Kah0ona/re-dnd
some things i like about re-frame - [1] sub deduping is awesome - it makes form-2 components essentially redundant and eliminates some very subtle reaction interdependency bugs [2] interceptors - logging, pervasive schema-checking of app-db
there was a developer from the Khan Academy who did a talk about various React-related frameworks, including Redux, Elm and Re-frame, and how they worked internally. I can't find the video just now, but he made a comment about re-frame's system getting out of sync in some tricky situations. Maybe that is related to the "leaking" @mikerod mentions
Would be interested to learn more, I’ve never heard about re-frame getting out of sync and am not sure what that would even mean?
I think this is the video: https://m.youtube.com/watch?v=-jwQ3sGoiXg I cannot watch it right now so I can't remember the exact issues he presented. I don't think he went into much detail other than mentioning a complication in passing
realworld re-frame app https://juxt.pro/blog/posts/clojure-in-yapster.html
that's my app @lovuikeng 🙂 but it's not open-source
I know there are a few companies using it and have sites to look at, but that hides all the fun part
In general, I think it is a bit hard to find open-source real-world-web-app impl’s though, so it’s just a shot in the dark. I was just curious. I like reading code like that just to see interesting patterns/situations emerging etc
mind sharing "internal" @mccraigmccraig?
sorry @lovuikeng i can't do that
> tricky situations I know it sounds unfair, but ... just don't get into tricky stuff.
I know when I'm in tricky situation it is because I was trying to outsmart myself
being too smart can be actually pretty dumb
like if you're showing off
i think you are making an assumption about what is meant by the phrase "tricky situation", which vague as it is, does not suggest an attempt at explicit cleverness
There's a lot of evangelism in the software community in general, so it's quite healthy and wise to be a bit skeptical and at least do due diligence before jumping in to the latest hyped framework.
@yury.solovyov in this line of work, lots of things are tricky, and there is no library that solves all the problems that crop up in browser development.
yeah, my comment was framework-agnostic
Yeah, I agree with not trying to be too fancy and clever, but patterns/situations do come up that you haven’t seen before, haven’t heard about, and don’t know that you have a clear path to solving. Also, your selected libs/frameworks further may make it difficult to see the path forward since knowing the implications of a choice may not be that clear without perhaps analyzing the implementation.
I agree I was vague, that’s because I couldn’t think of a specific example. Probably not worth discussing without one. So sorry for the dead-end comment.
That's why I love CLJS community - so easy to get philosophical 🙂
Here is a situation that I’m coming across in re-frame
that has concerned me and my use of it (this applies to if I were using just reaction
s in reagent
too @ajs :P)
A lot of my subscriptions seem to require extra query vec args, like (rf/subscribe [:my-stuff some-id])
Most app-state look up are really partitioned by identifying information. I think that’d be pretty normal though.
Then I also end up getting a lot of “layer 3” (materialized views) subscriptions. Lots of data transformations are happening there and the “signal graph” seems to get pretty complex. Subscriptions depending on 2 or 3 others to materialize some higher-level aggregate view etc. Along with that, since I have to look things up with id’s all the time, this also applies to the signal graph dependencies:
(rf/reg-sub
:higher-level/thing
(fn [[lookup-id] _]
;; Sort of joining different data for `lookup-id` together
[(rf/subscribe [:ui/thing lookup-id])
(rf/subscribe [:data/thing lookup-id])])
(fn [[ui-thing data-thing] _]
(transformation-stuff ui-thing data-thing)))
I feel that most of my app complexity is really in the signal graph subscription layer. I’ve often read that most complexity would be in the “event handling” and it always seemed like people were suggesting the subscription stuff was mostly trivial. To me I am not feeling this way.
The question: Is this normal? I hope I explained this well enough.interestingly at first my event handlers were more complex, but i now tend to make my subscriptions less trivial (ie. do sorting, filtering, aggregating etc), and i’m liking it better
then i can hide/submit the submit button if validate-all returns false, but the form itself responds to validate-touched. sort of
bit contrived explanation, but to me it was a better implementation than my previous approach
in response to "is this normal" - it depends on the problem. joining data in subs so that the view has little left to do apart from destructure seems like a fine approach - subs are much easier to test than views
@kah0ona that is an interesting concept of shifting from events to subs for certain transformations, I guess that was the direction I was going
The db was more “unstructured” perhaps you could say, and subscriptions did the, on demand transformations where needed
@mccraigmccraig yeah, one goal I’ve been trying to stick with is to not do much more than the derefs in components. I think that idea of re-frame
seems like a good one. More confusing to do a bunch of transformations and hiccup gen at the same time.
There's a lot of evangelism in the software community in general, so it's quite healthy and wise to be a bit skeptical and at least do due diligence before jumping in to the latest hyped framework.
Zimpler, Smyrna using re-frame
http://2016.euroclojure.org/speakers
codebase looks available @ https://github.com/nathell/smyrna Fairly simple, but nice to see. thanks for pointing it out.
and companies recruiting re-frame developers https://www.glassdoor.com/Job/woodbridge-clojure-it-jobs-SRCH_IL.0,10_IC1127049_KW11,18_KO19,21.htm
NextJournal, even Rails Girls picks re-frame
https://railsgirlssummerofcode.org/blog/2017-07-06-introducing-team-clojurians
Would be interested to learn more, I’ve never heard about re-frame getting out of sync and am not sure what that would even mean?
I wonder if they mean about reagent data not re-rendering if you get your form-1/2 components wrong?
Hi all. I’m new re-frame
, but I’m not new to the React + Redux architecture. I’m having trouble understanding ReFrame subscriptions… I’m using clairvoyant
and re-frame-tracer
to trace my Events, Subs, and Views, and I’m sort of surprised by what’s being logged… Specifically, I expected subscriptions to fire during the view rendering process, but it seems that my event dispatching is firing first. Can anyone help me understand what’s happening? I’ve read through the Dominos README and I’m still troubled
I expected a call like @(rf/subscribe [:something]
to block the process rendering my View and return the result of the query. Instead of seeing the query logs, however, I’m seeing the event dispatch logs, which are downstream from my query function. This makes me think that @(rf/subscribe [:something])
isn’t blocking… that feel wrong though
I feel like React + Redux is easier to grok since the App State is passed as an argument into the View rendering function…
Yes, it doesn't block, it provides you a "view" of the data, that can be nil. It is your job to decide where in the app you want to guard from empty state
Thanks for the response, @yury.solovyov
sub fns are run outside of your view @wpcarro, and the results of the sub fns (have they changed since previous invocation?) are used to determine which components to re-render
@mccraigmccraig after looking at an infographic of the Signal Graph, things are starting to make a little more sense… I understand that view fns are downstream from subs in the graph. What I don’t understand is how ReFrame knows specifically which view fns to call when the result of a sub fn is returning a different value from the previous invocation
eg. I have something like (let [x @(rf/subscribe [:something] ...)
that resides inside of some component’s render
fn. But I’m trying to figure out how it knows to run that block of code within the let
… am I assuming it’s doing more than it really is doing?
that's a trick of reagent - it keeps track of which reactions (re-frame subs end up as reagent reactions) are used by which components. it's been ages since i looked at that code though, so i can't give you anything but fuzzy detail
yes, reagent is providing the reactions... re-frame is using the reactions to build subs
I’m trying to debug why one of my components is re-rendering as a reaction when it shouldn’t be. Perhaps I shouldn’t be debugging ReFrame, but instead be debugging ReAgent..?
clairvoyant is usually plenty detailed enough to get to the bottom of any problems... presumably you are tracing the reaction fns ?
@mccraigmccraig I’m trying to, yes.
I understood that ReFrame would re-run all subs after the DB, changes, is this not true?
I’m triggering a toggle event on and off, and for one, ReFrame is calling 5/8 sub functions. For the other ReFrame is calling 7/8 sub functions. This is surprising to me
if you have subs which depend on other subs then maybe not all of them will be re-run
it will only re-run the dependent subs if it needs to, i.e. because the value they are depending on changed
@mccraigmccraig just to clarify… are you talking about subs that compute derived data?
ok. That’s good to know. My app omits that entire layer. I do have effect handlers though, but those are included in the 7 I mentioned
But if ReFrame is smart about knowing that some subs depend on other subs, then I can just assume that’s what is happening here
================================================= Regarding the discussion above, I've created an new FAQ entry. This issues comes up enough. The entry is fresh, so it will probably undergo multiple further revisions before becoming official. But I'm interested in feedback. But I have a presentation to put together for next week, so my responses to your feedback will be slow. https://github.com/Day8/re-frame/blob/master/docs/FAQs/DoINeedReFrame.md