5 ms·
> It can easily be said that any UI is fundamentally a state machine This doesn't make sense to me as a criticism of Redux. Redux is a giant state machine. Tha
by dwohnitmok 6y ago
> It can easily be said that any UI is fundamentally a state machine
This doesn't make sense to me as a criticism of Redux. Redux is a giant state machine. That's all it is. Actions are transitions and the store is the current state. The state transition table is the reducer.
The Redux architecture (and the Elm architecture that inspired it) is about the purest expression of a state machine you're likely to find in any architecture. The fact that a UI is just a giant state machine is the whole reason these architectures were created in the first place.
Redux is tricky and boilerplate-y because of some interactions with React, because it doesn't come with a built-in mechanism for handling interactions with the world "outside" the UI (e.g. interactions with the backend), and because JS doesn't have facilities for immutability out of the box and rather you must bolt on post-hoc solutions.
- darksaints 6y agoThe problem with Redux is two fold: 1. The datastore is a massive global. This already brings to it many of the pitfalls that have caused programmers everywhere to avoid global variables like the plague. But in addition to that, for incredibly complex apps, it is a massive burden to maintain all of your state in one place, without any ability to encapsulate or localize trivial local states. Why do I need a global state tree to determine which option is selected in my select dropdown? Why should I bundle the varying hyperlocalized implications of onChange actions vs onSelect actions with the business implications of things like payment submission states? Why does the state of one button for basic user A have to be bundled in the same data structure as an input element three tabs over, two levels deeper, meant for admin user B with privileged access? 2. Robbed of the concept of benign localized state, all state transitions must be weaved through the entire complex functional tree that renders it. Small refactors of your UI, like moving a widget from one place to a different location in your application "tree", involve not just refactoring the component which renders the widget, but every single component that it passes through, to reroute the data to the right location. It is extremely high touch refactoring, exacerbated by javascript's dynamic nature which is already hard to refactor, and Redux's inability to play nice with static typing tools like Typescript. Redux's bad ideas do not come from the fact that it models a state machine, it comes from the fact that it models it poorly and forces you into using a giant state machine, intricately threaded and tightly coupled throughout your entire application, when smaller state machines are easier to understand and easier to compose. Luckily, there is another programming construct that allows you to easily model state machines, and allows you to build them arbitrarily large or small to meet your demands, and allows you to encapsulate data and actions extremely well so that state and associated actions do not leak. They're called classes.
- dwohnitmok 6y ago> The datastore is a massive global. A single global state machine and a bunch of small state machines can be losslessly transformed from one to the other. And indeed Redux offers tooling to transform from one to the other depending on preference (this is the Redux Toolkit). And indeed in that world they don't have to be bundled together. You can have separate state machines for different parts of the page. > Robbed of the concept of benign localized state, all state transitions must be weaved through the entire complex functional tree that renders it. As you say, this is really just a specialization of 1 right rather than a separate problem? > They're called classes. Classes of course can model state machines since any Turing complete style of programming can model state machines. However, they are significantly different from the classic representation of state machines in that the important part of representing state machines is that you can inspect their state. Classes are meant to be opaque; as you say their encapsulation is a feature. But their opaqueness prevents the usual state machine composition, which is to link different state machines together based on the states they are currently in. Whether or not that's a good thing depends on the circumstances, but they make it painful when you really do want to represent things as a state machine proper, and not simply as a stateful component. And to the extent that you want a UI to be a state machine, that's a bad thing. Of course not all parts of your UI should be a state machine, especially things that involve continuous states rather than discrete ones. For truly mind-numbingly benign stateful details (such as which frame a button should be in while performing an animated transition from one color to another) you can just put it directly in the React component and ignore the store altogether, and that's definitely where you really don't want explicit state machines, but rather encapsulated black boxes that are stateless from the perspective of the overall system (which is effectively what a component-based/class-based system looks like when interacting with a state machine).
- nsonha 6y ago> the important part of representing state machines is that you can inspect their state Why? Is that because you need to know if a transition is valid for a given state? Do you have a citation for this? > Classes are meant to be opaque; as you say their encapsulation is a feature. This is true, but in practice, people do expose things in classes. I regularly implement state machines in classes as immutable builders. > But their opaqueness prevents the usual state machine composition. Not sure what you're refering to by this. Sounds like it's based on a specific implementation. I'm sure there are patterns that could help with this.