helix

kennytilton 2021-07-30T07:01:55.045800Z

"How do you solve the problem of synchronization and communication between those different 'scopes'?" Synchronization requires a bit of interesting code. šŸ™‚ MobX has a solid approach, this is a specification mine: https://tilton.medium.com/the-cells-manifesto-b21ed10329f0. Scroll down to "Data Integrity" for the detailed requirements. Communication works by letting any node in the graph see any other node, but by navigating to other nodes hierarchically so data is discovered in a naturally scoped manner. Less mysteriously, a node can see its parent, and has only one. As long as I search up, I see only my context, following nesting order. So it is not really communication, it is more omniscience. Yes, this is the opposite of today's obsession with purity. Works great. Unlike purity. (See poor ReactJS's long history of trying to allow "pure" views to see the outside data they in fact do need.)

raspasov 2021-07-30T07:33:49.046700Z

I think I understand… I can see how this can be beneficial if your data structures in the language are mutable (this was originally for Common Lisp, yes? I haven’t used Common Lisp myself) . I’m not sure if this approach is needed/useful with Clojure(Script). Immutable data are values. We can share data freely between components without any issue and have a simple (fn [data] (view …)) model

raspasov 2021-07-30T07:36:42.046900Z

Have you looked at SwiftUI? They have done some pretty cutting edge stuff for a mutable object situation. Was nice to use, but I only have ~1 week of experience with it. Definitely worth a look if you’re interested in different UI/frontend approaches.

kennytilton 2021-07-30T08:27:42.047100Z

Mutability matters at a different level of abstraction. At the application level, as even re-frame says, mutation is how the application moves forward. That is true no matter what language we use. The full re-frame take on mutation: "Now, to a functional programmer, effects are scary in a xenomorph kind of way. Nothing messes with functional purity quite like the need for side effects. On the other hand, effects are marvelous because they move the app forward. Without them, an app stays stuck in one state forever, never achieving anything. So re-frame embraces the protagonist nature of effects - the entire, unruly zoo of them - but it does so in a controlled and largely hidden way, and in a manner which is debuggable, auditable, mockable and pluggable."

kennytilton 2021-07-30T08:33:09.047400Z

Matrix decomposes almost the entire application into s = (f s). View is state, too, after all, though conventional wisdom tries to relegate it to second-class citizenship. If one looks at how Matrix achieves all-functional-all-the-time, with formulas deriving all interesting application state, one sees mutation in the implementation state, not the application state. These are the different levels of abstraction I mentioned earlier.

orestis 2021-07-30T08:46:20.048500Z

Hey there @lilactown, would you be interested in making someone a maintainer of hx? We use it actively in production and we'd like to be able to make small tweaks without bothering you.

lilactown 2021-07-30T15:43:29.048800Z

yes!

lilactown 2021-07-30T15:43:54.049200Z

I think I mentioned this on defn recently šŸ˜„ was definitely thinking of you @orestis

lilactown 2021-07-31T19:09:38.061300Z

@orestis I'll initiate the transfer to the github user orestis if that works for you

orestis 2021-07-31T19:13:08.061500Z

that should work

orestis 2021-07-30T16:16:22.056100Z

I'm glad to take this on, let me know what should be done... I guess commit bits to the repo but perhaps also building and cutting new releases in clojars? I'm clueless on that front...

lilactown 2021-07-30T17:00:17.056300Z

who should I transfer it to?

lilactown 2021-07-30T17:01:32.056500Z

orestis?

lilactown 2021-07-30T15:51:25.050600Z

you can also start rendering a screen and add a transition in between if it takes too long, which again is very difficult to do without bugs if you are controlling what is on the screen outside of the React tree

lilactown 2021-07-30T15:54:16.053300Z

I actually am working on this problem right now: we have a page that can sometimes take over 1s on initial render, so we want to show a spinner while it's churning on that new screen. But I don't want to show the spinner if it takes less than say, 200ms. AFAICT it's not possible to do that with synchronous React, since I need the ability to interrupt the long render to show the loading transition if it takes too long.

lilactown 2021-07-31T13:50:55.060100Z

"recompiled" I meant recomputed šŸ˜› it happens on the client

šŸ‘Œ 1
lilactown 2021-07-31T13:51:14.060300Z

no to web workers. that would require a lot of work

šŸ‘Œ 1
lilactown 2021-07-31T13:51:59.060500Z

a lot of it is bad code. I've managed to in other areas slim a similar computation down from 1s to <200ms

šŸ‘Œ 1
lilactown 2021-07-31T13:52:51.060700Z

but it's an extreme illustration of a class of problems, and one of the solutions to it is to leverage concurrent mode to provide a much better UX when you have a slow path in your app

šŸ‘ 2
raspasov 2021-07-30T21:46:16.057Z

1s to render is a lot, I agree. Do you think that is because there are many components on the screen? Or because there’s a many updates/mutation that are each done separately?

raspasov 2021-07-30T21:50:30.057500Z

I assume there might also be some HTTP request/de-serialization going on that is using up that one JS thread…

lilactown 2021-07-31T00:23:33.058400Z

The app loads a lot of data and processes it in a re-frame subscription. That subscription gets recompiled anytime someone navigates to the page

lilactown 2021-07-31T00:24:37.059500Z

And that processed data is used to calculate and render a large data grid on the screen, which also takes awhile

raspasov 2021-07-31T04:58:38.059700Z

ā€œrecompileā€ - does that happen on the client or the server?

raspasov 2021-07-31T04:59:50.059900Z

Have you explored/tried web workers?

lilactown 2021-07-30T15:59:37.054600Z

the whole local vs global state really comes down to like you said, performance & organization. then there's whether you store the state inside or outside the tree, which also has performance & organization, and also UX implications w/ concurrent mode

lilactown 2021-07-30T16:01:02.055900Z

what I really want is an external store that can participate in React's scheduler, so we can have our state outside the tree and coordinate updates with React's VDOM. that's what the vision of https://github.com/lilactown/flex is

1
lilactown 2021-07-31T19:09:01.060900Z

yeah. right now it's very slow, so it's more like 100s of milliseconds šŸ˜‚

šŸ‘Œ 1
lilactown 2021-07-31T19:09:12.061100Z

but lots of room to optimize too

šŸŽ© 1
raspasov 2021-07-30T21:48:34.057200Z

This sounds like a good idea! You get fully consistent data state, and something like ā€œeventually consistentā€ render state within milliseconds, which is fine for majority of cases.

raspasov 2021-07-30T00:26:11.008500Z

@hiskennyness in my opinion and from experience with React(Native) in the last ~6 years, keeping all the app state in one atom (and yes, only one), is a good thing. I don’t use React context or any frameworks or patterns like FRP; I just pass props down from the root. All data management is simple, and easy to reason about. That way you avoid state inconsistencies and hard-to-reason-about bugs. I almost never run into performance issues. If you do have perf issues, selectively add a useState hook to a component that is being updated multiple times per second. That’s when I run into the bugs and ā€œwhat the hellā€ moments šŸ™‚ It’s almost inevitable with multiple source of truth, and it gets exponentially worse the more sources of truth I add.

raspasov 2021-07-30T00:32:01.010900Z

To me it feels like Concurrent mode is trying to solve a problem for a very big app (think the FB website, not even the mobile app, because there’s only so much visible on the screen in one moment), with dozens/hundreds of components, all developed by separate teams, where each component is doing its own state management and they want to avoid any and all state centralization. If your app is not like that, I’m not sure if you’d see a benefit.

lilactown 2021-07-30T15:50:06.049300Z

IIUC concurrent mode is more about UX than state management. Concurrent mode allows us to reorder updates based on priority, so that we can e.g. update state based on key presses immediately before other less important things, which you can't do without bugs if you store state outside of the React tree.

šŸ‘ 1
raspasov 2021-07-30T00:34:41.012900Z

Also, one thing that JS does not have going for itself is efficient immutable data structures. You get a situation where you have 10 teams working on the same frontend app, some are using Immutable.js let’s say and doing efficient rendering, some are using plain JS arrays/objects and re-rendering everything on any and every change. It’s a mess. Concurrent mode might help a case like that.

kennytilton 2021-07-30T01:24:42.020100Z

Yes, @raspasov, mobile apps are definitely simpler, so a lot of issues are avoided. The problems I have seen with re-frame, eg, are in web apps that once were desktop apps. Then the global state tends to trip people up: I see a lot of "leftover" data bugs, because data was not cleaned up after processing. re-frame and redux brag on beautiful state flow, but it is a globally scoped state. Dynamic scope is how things work, so there is a fundamental conflict that gets exposed as apps grow. Is global state bearable for small apps? Sure. But why deal with it when we could have dynamically scoped data?

raspasov 2021-07-30T01:27:53.022600Z

@hiskennyness I’m not sure that mobile apps are simpler šŸ™‚ They are just… different. There’s less shown on the screen at any given time, but they do have their own complexities. When you say dynamically scoped data, what do you mean by that? How do you solve the problem of synchronization and communication between those different ā€œscopesā€?

kennytilton 2021-07-30T06:42:07.027300Z

"There’s less shown on the screen at any given time" That is part of it, @raspasov. Fewer ways for the user to interact means less complexity to manage. Also, mobile apps follow a "modal" model, vs the "modeless" model of good desktop apps. On the desktop I pick an object and then any action I have in mind, and the interface shows me which are allowed. On mobile I have to click the hamburger, click "Delete", and the whole app is in "Delete" mode, and I stay there until I am done with that. Lousy U/X, simple coding.

raspasov 2021-07-30T06:49:04.035900Z

Once you get past the basic case, there’s a ton of complexity/mutability around multi-touch, for example. Even a simple photo viewer component with all of its gestures is a pretty complex beast. I’ve done both React and React Native and I would say IMO React Native/mobile is harder to get right, at least for me.

kennytilton 2021-07-30T06:49:34.036700Z

"When you say dynamically scoped data, what do you mean by that?" In Matrix, everything is a tree. Esp. the view, with widgets part of components part of panels etc etc. And the shocker: the view tree is also a state tree. (Not sure hot reloading is going to like us.) As a plus, any node in the tree can see any data, but searches the tree inside out, "inheriting" data from containing nodes. ie, a node's location in the tree determines its context. All very orderly and easy to think about. Redux/re-frame's global, flat stores discard that context.

kennytilton 2021-07-30T07:10:55.046Z

Project is a bit scattered. Here is the CLJS version: https://github.com/kennytilton/matrix/tree/master/cljs/matrix The JS version is alongside that in the same repo. Best write-up starts with this: https://github.com/kennytilton/mxtodomvc That includes the "Data Integrity" bit at the very end.

kennytilton 2021-07-30T07:13:07.046300Z

I am working on a RN version with the great help of Helix, then I plan to clean everything up, document, and produce a tutorial sequence.

raspasov 2021-07-30T06:51:26.037900Z

I think I saw the Matrix project somewhere, link?

raspasov 2021-07-30T06:49:52.037200Z

Not to mention that the perf. requirement for mobile are generally higher; the slightest touch delay will be felt by the user.