Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Funny, I have spent a ton of time around Rails code where I dearly wished we had a state machine, because the alternative was an unorganized cluster of home-grown "state transition" glue without any consistent way of handling it, with all the weird-ass edge cases and split-brain BS that come with it.


The quip I like best for this is: “Any sufficiently complicated model class contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of a state machine.”

Lots of models I've encountered eschew being organized as state machines in favour of having "if salad" strewn throughout their code. That being said, refactoring to a simple state machine and trying to maintain it as such in perpetuity isn't always the correct solution.

Sometimes, a hierarchal state machine is needed, and if it is expressed as a simple state machine, it's just as messy.

Sometimes, a portion of it needs to be a state machine, and the right thing to do is to delegate some of the methods to a strategy that reflects the current state, but not all of them.

Sometimes, the whole thing is just too fat, and a state machine won't save it, the right thing to do is to get very aggressive about refactoring to a composite object.

Any time you have a big, messy model, it's very easy to write a blog post espousing a single solution, like this one:

http://raganwald.com/2018/02/23/forde.html

HN discussion: https://news.ycombinator.com/item?id=16468280

But the reality is that a big, messy model is always going to be some kind of problem, and unless you can break it down into parts, you're going to have a problem. A state machine is conceptually a way to break a big thing into parts based on its "state," but that's just one approach to factoring.

p.s. Another problem is that even if a simple state machine is the right answer, "rolling your own" usually isn't. Grab a well-tested and documented library already. This isn't your passion project, this is industrial programming. Rolling your own is one of the best ways to learn how state machines work. Once you've learned how, reach for a professional tool.


State machines aren’t exactly rocket science though, I don’t necessarily think writing one for your specific preferences/use cases is as bad of an idea as, say, writing your own ORM. It’s a pretty well understood concept.


They aren’t exactly rocket science, agreed, but there’s an interesting trap here:

Implementing classes on top of pre-ES2015 JS wasn’t exactly rocket science either, so there was a “Cambrian Explosion” of home-grown implementations and OSS libraries all over the place. Frameworks like Ember.js rolled their own too, and everything was incompatible with everything else, plus while the basic principles were the same, the details differed from implementation to implementation.

And when organizations are rolling their own, they tend to do just enough to serve their immediate needs. As their needs grow, different internal contributors add patches and bodges to the implementation, using different approaches.

Over the long haul, even though the concept is simple enough to roll your own state machine, it’s often a win to build on top of something which is well-supported and can grow with your organization.

Just as it was with classes in JS.


I've been on the receiving and perpetuating end of state machines and it's painful to have to deal with one that started years before you got involved and easy to think that you can do better. I've got a modest one in a side project and due to it being a side project I touch it once every couple of weeks and already it is making me uncomfortable. And it's dirt simple and I wrote it!

There's a take on state machines in a railsconf talk further down in the thread and it seems like an awesome way to reap a lot of the benefits while keeping a grip on the complexity. Sometimes complexity can't be buried safely and you kind of need to frame it instead. I'd argue that state machines bury that complexity but breaking those states into ruby objects w/ their own validation frames and delineates them instead.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: