Why Developers Never Use State Machines

A few months ago I saw a great little blog post about state machines on the Shopify blog. The message was that state machines are great and developers should use them more – given my recent experiences with state machines at CrowdHired, I could certainly agree with that. But it got me thinking, how many times in my developer career have I actually used a state machine (either separate library or even hand-rolled abstraction)? The answer is zero times – which surprised the hell out of me since state machines really are very useful. So I decided to engage in a bit of introspection and figure out why we tend to manage our "state" and "status" fields in an ad-hoc fashion rather than doing what is clearly called for.

We Don't Need One Until We Do

The problem is that you almost never create an object fully formed with all the behaviour it is ever going to need, rather you build it up over time. The same is true for the "states" that a state machine candidate object can be in. So, early on you don't feel like your objects' state machine behaviour is complex enough to warrant a "full-blown" state machine (YAGNI and all that jazz), but later on – when it IS complex enough – you feel like you've invested too much time/effort to replace it with something that has equivalent functionality. It's a bit of a catch-22. It's overkill and by the time it's not, it's too late.

Does YAGNI Mean You Ignore The Obvious

StupidYou’ve probably heard of the YAGNI principle, it stands for (You Ain’t Gonna Need It). Essentially it is meant as a mantra for developers to prevent us from anticipating functionality and building things before we know that they are actually necessary. You can think of it as an Agile principle or an unspoken (or sometimes vociferously spoken :)) rule if you like. Regardless, it can sometimes be a good idea to keep this principle in mind and measure much of what you do as a developer against it to make sure you’re not building a ‘mountain’ when a ‘mole hill’ will do just fine.

I like the idea of YAGNI and often try to apply it to what I do, but just like any principle that has been around for a while I have seen the message (or the idea behind the principle) be diluted to the point where some people start to use it without thinking and without understanding what it is all about.

Applying YAGNI Without Thinking

You know you’re applying YAGNI without thinking when it becomes the first and only yardstick for anything you do as a software developer. Implement a pattern? No way – YAGNI, a simple loop will do. Use a utility library? What for – YAGNI, it’s just one simple method, we can roll our own. How about building in more automation around our deployment process? Bah – YAGNI, we only do this once every 3 months, we can do without.

Don’t get me wrong I am not advocating always using patterns, or libraries, or automating without thought. What I am trying to say is, you can’t unilaterally apply YAGNI to everything without considering the larger context. If I do use a pattern here, will it make my code more readable, maintainable, testable, if the answer is yes then perhaps the pattern is a good idea. The point is, YAGNI in and of itself is not an objective it is just a practice, a tool. No matter what task you do you should always be aiming to make the system easier to understand and easier to use, more testable and maintainable, cleaner and more robust. If that means writing a little bit more code and putting in a little bit more thought, then YAGNI will just have to deal with it.

The Ideas Behind YAGNI

To give it even more context, applying YAGNI to everything you do is a recipe for a dish of spaghetti code. In my opinion the two main ideas you need to consider before reaching for the YAGNI stick are:

  • granularity