{"id":14,"date":"2021-10-08T05:11:56","date_gmt":"2021-10-08T05:11:56","guid":{"rendered":"https:\/\/blogs.oregonstate.edu\/iangaither\/?p=14"},"modified":"2021-10-08T05:11:57","modified_gmt":"2021-10-08T05:11:57","slug":"state-machines-are-bad-and-why-you-should-use-them-anyways","status":"publish","type":"post","link":"https:\/\/blogs.oregonstate.edu\/iangaither\/2021\/10\/08\/state-machines-are-bad-and-why-you-should-use-them-anyways\/","title":{"rendered":"State Machines Are Bad and Why You Should Use Them Anyways"},"content":{"rendered":"\n<p>I remember my first introduction to state machines was by a professor exclaiming about how terrible they were. When I eventually discovered how they worked and what they did I thought he was crazy. In my head I thought \u201cthey give you so much control over logic flow and solve so many complexity problems, how is everyone not using these?!\u201d, and in one sense I was right. They solve a lot of problems compared to not using any structure at all and they simplify a lot of common behavior and UI problems where you want distinct changes in functionality.&nbsp;<\/p>\n\n\n\n<p>I had other students echo my professor&#8217;s sentiment \u201cstate machines bad\u201d, but when I asked them why they didn\u2019t even really know what state machines were. From there I knew it was my sworn duty to convince everyone of how great state machines are and why they should use them for everything; except I was wrong. State machines are a great tool and they work great in specific situations, particularly simple ones, but they definitely have flaws. They struggle in complex situations where many things can be happening at once and can cause huge issues with multithreaded systems. They are definitely not the golden egg of programing paradigms that I once praised them to be, but they definitely still have a purpose in every developer\u2019s toolkit.<\/p>\n\n\n\n<p>So then what is a state machine and why would you want to use one? For me it always comes back to logic flow. Having a concrete and traceable system where you can easily identify the order of execution in messy complicated systems is a huge boon to development and your sanity. This is where state machines come in. They separate logic or \u201cstates\u201d into independent execution channels with consistent behavior. While that may sound complex (and reading articles about state machines will definitely make you believe that is true), the reality is that they don\u2019t really need a ton of features for them to be useful. A simple example (C++) is a switch statement with an enumerated state:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"166\" height=\"514\" src=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/4753\/files\/2021\/10\/image-2.png\" alt=\"\" class=\"wp-image-17\" srcset=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/4753\/files\/2021\/10\/image-2.png 166w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/4753\/files\/2021\/10\/image-2-97x300.png 97w\" sizes=\"auto, (max-width: 166px) 100vw, 166px\" \/><\/figure><\/div>\n\n\n\n<p>Here we know that every loop will only ever be in one state and that every state individually controls what other states it can enter. So from start to finish a given state controls everything about that execution sequence. It doesn\u2019t have to worry about other states interfering and it doesn\u2019t need to check if we\u2019re flying because we\u2019re obviously dying instead, otherwise we wouldn\u2019t be in the dying state to begin with. This example leads to my next bit of code, otherwise known as \u201cindicators you might need a state machine\u201d:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"365\" height=\"84\" src=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/4753\/files\/2021\/10\/image-3.png\" alt=\"\" class=\"wp-image-18\" srcset=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/4753\/files\/2021\/10\/image-3.png 365w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/4753\/files\/2021\/10\/image-3-300x69.png 300w\" sizes=\"auto, (max-width: 365px) 100vw, 365px\" \/><\/figure><\/div>\n\n\n\n<p>This is a not so exaggerated example of code similar to some I\u2019ve seen in my teammates work on previous projects. These often tend to spread all over the place as systems get more complex and often act as band aid fixes when characters are doing things when they aren\u2019t supposed to. The problem here is that aiming has to care about all the other actions the player could take and for each new one you add there\u2019s an exponential growth of systems that need to check for the status of other systems until you\u2019re stringing along conditionals that become impossible to manage. We don\u2019t want \u201caiming\u201d to have to worry about if you\u2019re \u201cdancing\u201d or \u201cclimbing\u201d or \u201cjumping\u201d (well maybe jumping, but we\u2019ll get to that later). We want \u201caiming\u201d to handle aiming. That is its one responsibility and removing all the extra complexity makes designing a system that handles aiming much simpler and more straightforward. This makes any system where you can compartmentalize logic into separate states easy to handle and develop.<\/p>\n\n\n\n<p>All this sounds pretty good right? Well then what&#8217;s the catch? Well a good example of the catch is jumping. You might not want to dance when you\u2019re jumping, but if you\u2019re making something fast paced you may want to be able to aim while you\u2019re jumping. Well ok, one combination is simple, we can just put together a new state called \u201cjump-aim\u201d. But then what if we want to do flips while jumping and aiming? Then we need \u201cjump-flip\u201d and \u201cjump-aim-flip\u201d and then we need to consider how you transition between them. Can you jump-flip into jump-aim-flip? Can you jump to jump-aim to jump-aim-flip? Then how does non jumping aiming transition into all of these states? Wait, this is starting to turn into the problem we had before where things were handling too much at once. And this is where state machines start to break down. There are two main issues at hand here; the first being that states without clear boundaries start to break down when you try to put them together i.e. composite states. The second, and arguably the bigger issue, is that whenever you add a new state, suddenly every other state has to be considered for transitions. While we\u2019ve limited the growth of long if statements, the growth still exists. For every additional state we need to handle all the different transitions, both in and out, to all the relevant existing states. These two issues combined can cause state machines to balloon out of control and become difficult to manage and expand over time. While I personally haven\u2019t had to deal with extreme cases of this, I\u2019ve definitely had to toe the line and it\u2019s easy to see how something complex could make an unmanageable mess.<\/p>\n\n\n\n<p>So while state machines definitely have their uses, they aren\u2019t a magic bullet to every problem. An easy way to tell if they\u2019re good for a given system is to consider how well the system\u2019s tasks separate into independent functionality. If they don\u2019t cross the line into other tasks&#8217; functionality often, then the system could be a good candidate. In addition if the system isn\u2019t meant to be dramatically expanded on then it also could be a good candidate. If neither of these are true then it may be time to learn something a bit more complex or to try and re-design the system to better accommodate the separation of responsibilities.&nbsp;<\/p>\n\n\n\n<p>All that said, just remember that using a state machine is probably better than going in without a plan at all. They can make your life easier when used correctly, just use caution so you don\u2019t turn your team\u2019s project into a monstrous machine.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I remember my first introduction to state machines was by a professor exclaiming about how terrible they were. When I eventually discovered how they worked and what they did I thought he was crazy. In my head I thought \u201cthey give you so much control over logic flow and solve so many complexity problems, how &hellip; <a href=\"https:\/\/blogs.oregonstate.edu\/iangaither\/2021\/10\/08\/state-machines-are-bad-and-why-you-should-use-them-anyways\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">State Machines Are Bad and Why You Should Use Them Anyways<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":11629,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-14","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/posts\/14","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/users\/11629"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/comments?post=14"}],"version-history":[{"count":1,"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/posts\/14\/revisions"}],"predecessor-version":[{"id":19,"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/posts\/14\/revisions\/19"}],"wp:attachment":[{"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/media?parent=14"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/categories?post=14"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/iangaither\/wp-json\/wp\/v2\/tags?post=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}