Fork me on GitHub

@ilmirajat I dont like abstraction. I like to see the plain old data. The normalization of the DB is a cool idea, and you get that stuff with om...but might be a solution looking for a problem? I'm sure there are cases when and where that is helpful. One of the good things about clojure is its data focus. Having the data out in the open and clear is also a SIMPLE benefit. A huge real gap in reframe, prior to 0.8.0, was non-UI reactions. 0.8.0 puts it in by subscribing to the abstraction of an event. I use re-frame with just the set/get handler/subscription, and now I just subscribe to data. This is simplicity at its max. Unless I find a burning need for some abstraction, I avoid it, because in the long run I just find it to be extra cognitive overload. Below is my 0.8.0 functionality, i.e. provide non-UI reactions. I provide an example of how it is used too. Have a look at it. It can be understood by simple inspection....there is 0 cognitive overhead. Maybe, I'm just an idiot. I'm old, I don't like things to be more complicated than I feel they need to be.


have one set/get handler like so:


all told < 100 lines of code... I like that.


@ilmirajat I'm not into the args you wrote up. (1) The interface between subsystems should be as semantic as possible within reasonable effort


we are using a global app-db. its the web. i build websites. I dont use reframe in libraries that other people are using...there aren't any sub-systems.


same for point subsystems here...


i agree with 3 but dont see how having simple setters/getters has anything to do with this.


for 4, the error about not having an event handler defined... as opposed to accidentally writing to a mispelled location.... these bugs get exposed instantly and have never been an issue for me...


5 is non-sense too...i dont just say set, i say set [data-path], i also log that data i absolutely know what has been set before some error.


i could hardly read the rest of it...the arguments just dont add up or make sense...just an example:


"You cannot easily check where :set is dispatched with vector "an relevent vector". And even if you know what is relevant vector it can be hard to find out where :set it dispatched with it. In the former case, you can use simple text search. In the latter case even a complex regex search that ignores comments, tabs and extra spaces etc. is not enough as the path can be in a variable."


i mean number one the english is hardly comprehensible, but trying to say its easier to find: :set-my-funky-thing than (dispatch [:set [:my-funky :path-location]]) is complete and utter non-sense...and to say that the path is in a variable and not the event name...are you just making ridiculous arguments for fun...why couldn't you put the event name in a variable... you'd have the same motivation one way or the other... Sorry to be so strong in my opinion...but....


@mbertheau I'm with you 100% everything you wrote above.


@ilmirajat Great write-up. Well articulated. Deserves to be stickied.


@fenton: I already know we have a bit different approaches to things, but I think there’s a development style that I use a lot that makes the subsystem argument pretty relevant for building web apps. I tend to work on small, self contained components with specific functionality, then compose them into the larger app. The individual components in re-com would be a pretty relevant example, and same with the way things are built in devcards (I like as a great talk about why). It doesn’t mean your methods can’t work with that, but it definitely means that I expect the data requirements to change independently, particularly if I have a control that I’ve used in multiple apps, and I find it easier to deal with those changes if it’s compartmentalized the way re-frame recommends vs. the way you prefer. Doesn’t mean I’m right, it just means we are happier with different trade offs.


Also, I know it’s a bit weird using devcards as an example of why I like re-frame’s approach considering they don’t play that nicely together, but let’s ignore that for now. It’s on my list of things to try and improve one day (I think they belong together like peanut butter and jam) 🙂


@fenton I believe @(…. (subscribe ….)) is an anti-pattern for re-frame. (…. @re-frame.db/app-db) should behave the same without uselessly creating a subscription and then not keeping it around.


But of course by accessing app-db directly you’re giving up on the advantages of having effects pure.


@fenton It's great if your approach works in your case. I'm still not quite sure if you really need re-frame at all. One clarification: By "subsystem", I refer both internal and external logical components, modules, layers and other relatively independent parts of the system - not only to external 3rd partly libraries or external services. There is multiple useful ways to split the whole system to subsystems. E.g. when designing a web app, it's usually useful to think UI as a subsystem and, say, data model another and so forth. The main reason to do so, is to reduce complexity by reducing variance of communication between parts of system. In "spaghetti code" variance of communication is high - a piece of code can use anything anywhere and exactly that variance makes all changes hard. If UI is complex, it's probably good idea to split UI into small independent sub-wholes (i.e. sub-systems) and force them to communicate with each other via a unified interface (such as re-frame or core.async channels). While UI as whole is a sub-system to, say, a web app, a web app is a sub-system for an overall architecture containing also e.g. database, authentication infrastructure and set of RESTful microservices. An web app is also a part is a part of social system serving interests of organizations and individuals. At last, wisely chosen abstractions of won't increase cognitive load, but decrease it as you need to keep less things in mind at the same time. Yet, all abstractions comes with price. If they are not intuitively clear to you, you need to use time to study the underlying logic. The most expressive abstractions tend to be non-intuitive and hard at first. E.g. ClojureScript is expressive abstractrion on JavaScript engine, but requires a lot of study.) At last, @fenton: Do you want me to clarify or elaborate something in my arguments? Currently, its hard to me to figure out, how might I clarify my thinking as you essentially seem to tell that my arguments are nonsense to you. It would be helpful, if you specify a bit more which of my premises aren't plausible or sound in your opinion, or where you think my deduction goes wrong.

mbertheau06:08:38 nice write-up on different levels of arguments made in disagreement.


Question regarding regsub... Is it possible to get a reaction from a subscription in another namespace using ':<-'? The following example throws an error: no subscription handler registered for: " c…s.c…e.Keyword {ns: "main", name: "some-items", fqn: "some-items", _hash: -1237...`

(ns myapp.core
  (:require []
  (:require [re-frame.core :refer [reg-sub]]))
  (fn [db]
    (:all-items db)))
  (:require [re-frame.core :refer [reg-sub]]))
  :<- [:main/some-items]
  (fn [items]
    (filter odd? items)))


@joshkh: I suspect that this is a bug in the new reg-sub macro introduced with 0.8.0. Can you open an issue?


sure thing


if I wanted to “ratom” some javascript state, is there a clean way to do that with re-frame? I was thinking along the lines of having a subscription that simply returned some jsmodule.getState(), and my views could subscribe as needed. I have a feeling this isn’t going to work, though, because the js state isn’t maintained by a reagent ratom.


I could come up with a some register callback fn scheme, but before I do that I wanted to check if someone hadn’t thought up a better option.


@lwhorton try a reaction - you supply it a function to calculate the value


oops, no, that's the underlying impl... it wraps the body with a fn


and you can use a reaction in the reagent views just like an r/atom


oh neat - thanks @mccraigmccraig i’ll try to see how that works


i've not used it to fetch js values... i think all the active reactions get re-run to determine which components need to re-render - but it's been a while since i looked, and if i'm mistaken then it may not work


hmm.. gets complicated quickly. there’s also this to consider but i haven’t quite parsed it in my head


@shaun-mahood yes i’m aware of that. my issue is a bit bigger i think. i’m looking for a way to implement the state changes so that views dont need to know - they just subscribe like it’s any other source. for now i’m going with the heavyhanded approach of onCallback dispatching


otherState.onChange((state) => reframe.dispatch[:state-changed state]), so to speak


it’s going to be too heavy for a particular use case I can think of, but for now it’s “not bad"


@lwhorton: Interesting, it sounds like it will be a bit of an adventure. Good luck!


@ilmirajat I dont want to carry on a public conversation unless it has the chance of helping someone here who is interested in using re-frame. Happy to carryon a PM thread tho. Lets go over there if you like.