4 ms·
Auth logic or similar. Somewhere area in app that may be genuinely complicated and can't go wrong, where you need granular control over a set of states which of
by RobertKerans 5y ago
Auth logic or similar. Somewhere area in app that may be genuinely complicated and can't go wrong, where you need granular control over a set of states which often have sub states, and where there are things like remote requests to different services occurring.
And you can just write this stuff as basically lots of nested if statements but...
As an actual example, I have a state machine in an app I work on:
1. check if there's a session (if so goto 4). 2. If not go to email input. 3. On submit go to password input. 4. authorized. However: 2 and 3 and some of the time 1 have network requests, so handle those. Password can be entered wrong three times (error message changes accordingly, oh also no. retries are modifiable at admin level), which bumps user back to 2 (error message changes accordingly). User may have turned on PIN security, if so that will be an extra step before allowed into app. They may also have it turned on, but not one set, which is a slightly different flow. And they can turn it off/on from within app. Oh and biometric, same deal as PIN. Also can drop back to username/pword instead of OTP in some circumstances.
That's most stuff I think off top of head. That's a hierarchical state machine written using XState. It's easy to test (UI is seperate from the machine, and I can just plug in API functions for the remote calls). It's relatively easy to read (xstate API produces stuff that reads like a diagram, it's easy to explain what's going on). It's easy to add/remove states
- runawaybottle 5y agoThat’s actually a good use case, thanks for sharing.
- RobertKerans 5y agoJust to note, I think I do agree with you. With the above flow, it's behind an interface that just provides update functions, the current top-level state, and the values that are updated by it (the user object the remote calls return from my Auth provider, for example). All the machinery is completely hidden: I had previous versions where it was more exposed, but it asks a lot of every other dev I work with to learn yet another complex API. There are other potential uses for in my apps (ex. backing a numeric input made up of multiple inputs for PIN/OTP that needs to track focus state + a few other things), but I've been slightly wary about introducing more xstate code. I feel like: - explicit state machines are extremely useful. - they're very well understood by embedded/game devs, but not so much by web GUI devs... - ...but the latter have an innate understanding due to much of the things they build often being implicit state machines. And those things are often fine as they are. - adding an explicit machine greatly increases granular control at the expense of [complex] boilerplate. - the simple fact that they are so explicit (and that you get one state at a time) means state machines aren't some silver bullet for UI, and they get complicated really fast due to state explosion. - I think any game dev would be able to explain why you don't just use them for everything, and I find it slightly strange that there's little input from game/embedded devs when these things come up on HN -- maybe I'm just assuming there's some overlap of knowledge when actually there isn't. - heirarchical state machines and state charts fix the state explosion issue, but then bring with them a more complex API that needs to be learnt. I'd say, for web/JS, XState is gold standard and it's a fantastic library. Explicit state machines are very useful, but writing ad-hoc machines that do anything useful isn't particularly pleasant in JS; XState, with its serialisable object configuration, is pretty easy to explain. It has the advantage of being completely agnostic w/r/t front-end library, which I think is critical. I can shove it behind an interface, and if necessary replace it with something else pretty easily. I'm somewhat uneasy about having it directly tied to [in the OP's case] React, because I'm in agreement that it's baking clever, complex code right in (yes, for anyone disagreeing, I am aware state machines are a simplification. So is Redux. So are observables. Hell, so is recursion. Anyway).