Hacker News new | ask | show | jobs
by bearjaws 1917 days ago
Anyone with experience using finite state machines in production apps want to share their experience? I love the concept, but not sure how to implement a POC so my teams can see the value. We have a few areas that have a ton of dense business logic, and I think something like xState could be beneficial.
3 comments

XState is incredible when combined with something like Svelte. I've seen it used to power videogame UIs (huds, health bars, menus, etc.) for a AAA shooter.

The really nice thing about working with it is that all your components get much simpler about understanding when and how they should render. No longer are you trying to track state through some combination of variables or await statements, you are just asking, "Am I in this state? Great, I'll render." Double if you are managing animations or something else that takes wall clock time.

You also get an amazing visualizer and debug toolset where you can both see your app transition states, and inject the events to watch it transition states easily.

Would highly recommend checking out xstate in front end dev.

It really depends on the quality of the underlying state machine library, and whether you're actually using them at a good time.

Obviously, as the author of one of these things, I'm a pretty big fan of FSMs. And, y'know, even though the entire point of mine is to be easy and convenient to use, I still don't use it very often.

Most jobs aren't for FSMs.

Finite state machines aren't well applied everywhere. There are a lot of cases where you could use a finite state machine, but shouldn't. A chess board is an example: it is a well described state, there's clear right or wrongness to changes, there's no ambiguity or intermediate states, etc. However, managing a board that complicated, dealing with rules like en passant and castling, it'd be a hassle. You don't get enough value out of it, and so it doesn't matter what you're using. Yes, FSMs can handle chess; no, it's not a good choice IMO.

But then, there are times when it's well applied.

When it's something where an FSM is a good choice, and you've used a low-hassle library, my opinion is that they tend to make systems night-and-day simpler.

Consider creating a finite state machine for the state of any single given payment. Now, when the external actor changes their process, the FSM wedges and you get notified, instead of switching to a state that used to be impossible and isn't anymore, in software that isn't ready for that. That's a huge level of immunity to large classes of bugs.

My opinion is that FSMs are well applied when the cost of a state reaching a bad configuration is very high.

You wouldn't use them to manage the image in a paint program.

You would use them to control the airplane's jet being on or off.

If you're in a situation where they're well applied? Now it's going to matter a lot which system you actually use.

I have great respect for `xstate`, by example. It doesn't fit my preferences, but it's fast, robust, and largely bug-free. It's reliable, easy to work with, well documented, and has a good solid community. If you use `xstate` you'll have a good time, most likely.

By contrast, at a previous ruby job, we used a gem I'm not going to name. It was ahem not my favorite. It was slow, it was pretty easy to get it wedged when it shouldn't be, it relied on side state things as storage that weren't fundamental to the language, it was cryptic when it failed, et cetera.

Later, at that job, we switched to a different state machine gem. It was pretty hassle-ful; the datastructures needed to be manually converted because there was a slight difference in how the two gems saw the job which meant automatic conversion wasn't practical.

But we were sure glad we did! Once the other FSM library was in place, things were a breeze, the system was much easier to understand, and to control.

There's more to it than good or bad, though.

If I couldn't use my own, what would I use?

If it was business logic, I'd probably use `stent`. To me it's the easiest to debug, and seems the most robust. Their tracing tools are quite impressive.

If it was a redistributable react control, I'd probably use `fsmx`, or embed a cut-for-case one. Stent is 288k. FSMx is 24k. If it's typescript, I'll probably use `fsmachine` instead, which is 28k.

If I need transactionality, `edium` is my only real world choice.

If I need something that's easy for junior programmers to understand, I'll probably use `javascript-state-machine`.

If I need something to create documentation that's easy for non-programmers to use, it's very likely to be `state-machine-cat`.

And of course, if I could use my own, I'd prioritize it when doing less labor or having a shorter representation of the machine is better. For me, that's pretty much always shrugs `xState`'s light switch is 13 lines; `jssm`'s is a one-liner that's shorter than `xstate`'s import.

So.

What I would recommend is that you pick one that graphs for you, like `stent` or `xState` or `jssm` or `state-machine-cat`, and just try drawing out a rough of your business logic.

Maybe it's well implemented in a state machine. Maybe it isn't.

But once you've tried, it's usually pretty obvious which one it is. And it can be fun to try, y'know? New languages are neat.

If you have a bunch of little moving pieces that follow complicated rules and can't be wrong, there's a pretty solid chance that state machines are for you.

They're one of those tools that the right time isn't common, but when it is the right time, holy WOW do you want them