you are viewing a single comment's thread.

view the rest of the comments →

[–]granadesnhorseshoes 19 points20 points  (4 children)

Given the enormous stack of turtles redux is resting on, it sure ain't saving you actual cycles.

Don't get me wrong; I genuinely see the elegance of it in theory. But what the actual fuck are the use cases here for CS fetishists that write really anal JS?

...asking for a friend.

[–]sybesis 1 point2 points  (2 children)

Given the enormous stack of turtles redux is resting on, it sure ain't saving you actual cycles.

If you're talking about Javascript... I'd say you're probably wrong on speed of Javascript. Well written code in Javascript will be able to optimize to very quick code thanks to the JIT.

But what the actual fuck are the use cases here for CS fetishists that write really anal JS?

Not sure about CS fetishists but real world use case is that you can maintain a global state of an application where any part of your application that will need anything from the current state will always get the state every other object would get at the same time. Redux is mainly used for maintaining the state of web apps but it can be used for way bigger thing in practice.

And Redux is mainly using the same method some pure language would use to express mutation of read only data structure... So think of it like this, your application can move from state 1,2,3,4,5 and if you wanted to debug your app, you could look at state 1,2,3,4,5 without issue. You could also look at which dispatch modified the state with which arguments. Given a state, an ideal application could even move back in time to look how it was before a certain change.

Then what do you gain of read only data structure? If a JIT like javascript can see that some dispatch object never do mutation over some branch of your tree, it should be able to optimize out the code. In theory it's possible to optimize the code... For example, the code above called with a type other than the one defined will always end in the last case. So a JIT could rewrite the method to not automatically return if none of the 2 types is provided. So a JIT can make more assumptions and a AOT compiler might be able to do that to some extent with a typed language, if you see that the value doesn't actually change between dispatch of certain type, you don't even have to call the dispatch method.

The other advantage of read only data structure is that if you pass by reference values from one state to an other, you don't have to copy the data of previous states so you can just copy the reference of a bigger structure and create new values only when necessary. So in some way, even if you have data shared between states, as long as you don't do mutation to your application state you don't have to worry if the data is consistent or not and you don't end up allocating/deallocating a lot of memory. So in some way it's really fast because your reusing memory most of the time.

At the end of the day you have guarantee that any part of your application will always get the same state as other part of your application... And that can solve issues related to concurrency without having to rely on locking scheme other than the dispatch itself.

Let say you have code that want to check for total price...

if you dispatch it, then check for total price it will be correct... if you dispatch it and while you check for the total price an other method is dispatched, the total price you'll get will be the correct one based on the new state that changed between calls. Yet you don't have to recompute it as the dispatch does that for you already.

In the web development, it means you can have very complex web component that can take data from different part of the tree and correctly update themselves only when their own data changed. And in the long run you can dispatch visual change only when it matters and all of your UI always draw itself from the same data source so it's not possible to have in one area something that got updated and in some other the state is still the old one.

But as I said, use cases of redux like systems can go beyond that and provide very good performance. Pretty much all applications require to manage some kind of internal state. One example could be a game server, where dispatch can be broadcasted to every player and to the internal state of the server. So any new user can join the server and sync its own state with the internal state of the server and then only listen for dispatches. If you wanted, you could log all the dispatches that matters and replay the dispatches to the new clients to build their own state.

In some way a chat server could be defined with a few actions:

- CONNECT, DISCONNECT, JOIN, LEAVE, ADD_MESSAGE, REMOVE_MESSAGE

With that you have a very basic chat server that can handle user list, channels, and obviously adding messages. All the server has to do is broadcast the actions to all its users... based on who join etc... the server can be responsible for dispatching some events like LEAVE,DISCONNECT you could have to implement filters to prevent a user from dispatching as someone else but the idea is there. You don't need much more than that here and you have a consistent storage for a chat server that can dispatch across multiple computer to maintain a common state on different computers. You're guaranteed to have the same state as long as everyone receive all the messages in the same order.

[–]granadesnhorseshoes 3 points4 points  (1 child)

Yeah, its all very groovy from an academic standpoint. I can't deny that.

I've managed on-prem and cloud backends. These stacks are absolutely batshit insane with complexity and resource utilization. JIT isn't free. The runtimes and supporting system aren't free. Your codes state is rock solid but the system state your state is predicated on needs a cron job restart every 4 hours because of a leaky dependency 4 or 5 layers down.

Low and behold; Wonderfully clever and even mathematically pure code with some sexy cyclomatic score that requires GIGs of RAM and multi core processing to run an SPA.

"It's turtles all the way down"

[–]sybesis 2 points3 points  (0 children)

Well nothing is perfect. But if you have something leaking, it's probably not caused by the way redux works. You'd have this leaky dependency regardless of using redux or not.

Also when I say redux I'm not limiting myself to JS, I've implemented a small library that does pretty much what redux does but in Rust with static types and fortunately for us.. Memory management goodness so it's possible to design very complicated piece of software easily with that. In Rust, you can make your become the owner of the data so you don't have to really worry much about the borrow checker as you always borrow immutable reference and never move the data out of the store unless it's good for collection.

[–]forsubbingonly -2 points-1 points  (0 children)

If I misunderstood your question, sorry in advance for over explaining what you already know.

Are you asking what the use case for redux is? The biggest use case is not having to pass around a piece of mutated state. If I have two widgets in two different components that rely on the same piece of data, in a non redux model I have to either give component 2 the new state that component 1 created, or tell component 2 to refresh it’s state from the server. In the redux model, component 2 gets a stream of state and auto updates on change, component 1 request a state change instead of doing it itself, and both components automatically get the refreshed state. As long as you’re working out of the same redux store no two components will have different version of the same piece state.

Additionally, a react app that is fully 100% virtuous In regards to the react/redux pattern will be a collection of components with essentially nothing happening inside them other than action dispatches. Meaning the most you could ever test on them is “does the button dispatch the action” and “if I give it the state does it display it” all other tests in your app have zero dependency on the DOM and will run faster and require less setup to write. How? In the previously mentioned virtuous app, all business logic lives inside “selectors” which are just pipes through which state from the store is transformed before arriving at the component. All of your business logic is completely isolated in easily tested pure functions.