When Booleans Are Not Enough... State Machines?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right our next talk it's gonna be parenting Joseph he's gonna tell us about when bullying's are not enough state machines let's give a round of applause thanks everyone can everybody hear me okay louder all right okay I'm gonna talk about when boolean's are not enough and how we can use state machines in those cases my name is Harrington Joseph I'm a senior software engineer at Netflix where I work on the data platform team my work is mostly focused on day orchestration and even dream in architecture feel free to find me after the talk if you want to know more about what I do in Netflix or you want to share your favorite show or something like that expectations this talk is about why how and when to use state machines this talk is not about the internals of a state machine I want to make that really clear let's start with a very simple analogy may be that you have a closet where you store tools and sport equipment but these clothes to be so messy that you don't really want to look at it you don't want to think about it reality hits you the moment that you have to get something from that closet and turns out that it's all the way at the bottom of the messy pile that you have in there you don't really know if you can pull it out or not because everything may fall apart things get actually worse when you ask someone to get something from that closet for you that person is probably not going to find what you need and it's very unlikely that it's going to feel comfortable moving things around this is exactly what happens when we use multiple billions to represent States and enforce business rules our code gets messy and no one wants to touch them so please raise your hand if you have a class with any of the following attributes right I think everybody feels identified so the problem using multiple volumes to represent States and enforce business rules very simple very concise so let's take a look let's your brand into the color here we have a video class that receives a source which is the source of the video and even ich Eliza's a source attribute with the given source but it also initializes a boolean attribute all explained equals false because at the beginning the video is not playing this class also provides three functions pause play and stop I'm not going to dive into the detail how to play or pause or stop a video file but what is important here is this last line of this function which is itself the display so when you Cove pause self to explain is set to false when you call play a cell Tory's plane is first set to true and when you call stop said that is plane is set to false so we can go and create a video instance we can play the video we can pause the video we can stop the video and we can check if the video is playing or not what videos do is playing what does it really mean when it's true it definitely means that the video is playing but what happens when is false is it pause or is it stopped in reality we don't have enough information to answer this question so naturally we will go on to something like this so we created a new-age recall is pause which by default we initialize it as false because when we create the instance of the video the video is not policy there then when we call pause we are now we are going to update these are due and we're going to set it to true when we call play you're gonna set it to false and we call stop we're gonna set it to false so we can continue answering me the video is playing by just following video that is playing we can answer it video is paused by calling video that is pause but when it comes to unknowing if the video is stopped we actually have to check if the video is not playing and not pause this is very ugly it's not elegant at all but it's also really fragile is front whereas the moment you introduce a new state any condition that you have built around this logic is going to be broken let's talk about some business rules let's say that a video can only be played when it's paused or stopped rule number two a video can only be paused when is playing and rule number three a video can only be stopped when is playing or pause very simple rules just like a regular video player so rule number one a video can only be played when it's false for stop we go on modify our play function and now we check if the video is not playing or if the video is paused then we make the code to play the video update our play is playing actually to true said they explained a is false attribute to false and if this condition is not satisfied we'll basically raise an exception saying that you cannot play a video that is already playing assuming that the video is already playing so there is some assumption here that leads to fragile code again the moment you introduce new States or new business rules for rule number two we say a video can only be played when it's pause but video can only be pause when it's play so in this case we check if the video is already playing in that case we make a call to post the video update our Flags otherwise we were excited every race and exception saying that we cannot pause a video that it's not playing and for rule number three we say that a video can only be stopped on its plane or pause again we check it to be explained or if the video is false we make the call to stop the video update our Flags otherwise race and accession so the code is rapidly becoming complex our play pause and stop functions are not actually focusing on what they supposed to be doing they are checking for the state they are validating business rules instead of focusing on playing pausing or stop in the video it's bloated we are at a bunch of coda we didn't get any functionality we're just checking for the state it's repetitive we keep checking for the state and racing exceptions even though it's not exactly the same condition it's something repetitive it's something that we could probably be automated and it's definitely hard to test in order to write unit tests for this you have to write unit tests for play for pause and stop with all the possible values of this flag can have we're talking about only two flags in my in the moment did you want more flags for different states here's a different approach you can have a video class where you define some constants for your States and then instead of having the boolean flags you can have a state and then used to initialize these stop because the video is not playing once you create the instance now you say a video can only be played once pause or stop the code actually didn't change much instead of chicken bones will continue checking for constants and now we have to update the state we keep raising the exception in all the cases and also we make assumptions we say if the video is not playing then we can definitely play but is that true it is true at the moment we have three business rules we have but the moment we introduce a new we introduced a new state this code is going to be broken same thing for for the stop for the repose case and same thing for this stop case so let's talk about state machines what's a state machine a state machine is a mathematical model of computation with a finite number of states transitions between states and a machine that can only be at a stay in a given time all these sounds very complex theoretical and mathematical when in reality a state machine can be seen as a directed graph where each of the node each of the nodes is a represent a state in the machine and the connections between the nodes are representing the transitions basically when two nodes are connected and connected it means that you can transition from one node node a to node B and then you just need a pointer that tells you in what state you are at a given time so here's a very simplest example of a state machine this is a machine for like when a user lands on a website initially the user is the in the log out same when you land for the first time in a website once you are in the log out state you can perform the login transition to move to the login state once in the login stage you can perform the logout transition to move to the logo state in this case logout has this like bluish glow representing that does the initial state of the current state at the beginning so how do we design a state machine first we need to define a number of states that we want to deal with what are the states that our object is going to be representing then we need to lay down the transitions between states what are the business rules that we want to enforce and finally we just need to pick the initial state so step one define a finite number of states playing pause and stop step number two laid out the transition between sted in states in this case what we're doing here is translating the business rules into edges in the graph so rule number one said that a video can only be played when it's when it is stop or pause that that's what you see two incoming arrows to the playing state one from stop learn from pause and the name of the transition is called play rule number two said that a video can only be paused when it's playing that's why you see only one in common error to the Paulo state and he's coming from the plane state with the name pause and rule number three said that a video can only be stopped when is playing or pause that's why you see two incoming arrows to stop state one from plane and one from pause with the name stop and finally we just need to select the initial state which in this case is going to be stopped because the video is not played at the beginning so let's take a look at the code so I'm gonna rely on a library called transitions it's an open source library that you can find on github it's really simple to read like the code is fairly easy to understand but you can find any other flavors are in multiple languages as well so the first thing that you need to do to use transitions is to import the machine then you define all the states that you want to deal with as you can see this doesn't look very different to the latest approach that that I show you next we need to define the transitions and this is the part that looks a little bit complex when reality is not what we're doing here is described in the graph the trigger is basically the arrow that represents a connection the value of the trail is going to be the name of the transition source is going to be the origin of the transition and this is gonna be the destination of the transition so for rule number 1 that the video can only be played when it's pause or stop we basically have two rules one going from pause to plane and another one going from stop to plane and the name of the transition is going to be played for rule number one that the video can only be paused when is playing then we have one transition that is going from plane to pause and the name of the transition is going to be called a pause and rule number three the Revere can only be stopped when it's plane or pause means that we have to transition rules one going from plane and one going to pause both ending in the stop state and the name of the transition or the trigger is going to be stopped another thing that is important to mention of this definition here is that the trigger name should match the name of the function that you're going to call and I go over that in a moment finally you need to create the machine when you create the Machine you say model equals self and I explain why this is important is related with the trigger name transitions the list of transitions that we want to enforce or that we want to provide and the initial stage which in this case is stop now our code actually looks like this as you can see there is not much there because there is nothing related with the state anymore we don't have to keep track of state we don't have to check the state we don't have to raise exceptions the code is actually focusing on what is supposed to be doing boss is going to pause the videos doesn't like it doesn't care about the state at all same thing for play and same thing for stuff so now we can create a video instance we can play the video on our stage to transition to plane if we really care we can actually check the state of the video as you saw I didn't create a video a state attribute but the machine itself is injecting this attribute into the object when we provide a model it will self the machine injects this attribute you don't really have to access this attribute at all because do technically shouldn't deal with a state that machine can handle that for you but if you need for some reason is available we can pause the video the states to transition to pause we can stop the video and just say transitions to stop but what happens if we call pause again remember a video can only be paused when it's playing but we are in the stop state this is gonna give us a machine error the machine is taking care of validating that this transition is right and we get this pretty much for free all we had to do was to define the transitions but we didn't have to write a single condition the way this works remember that I mentioned that the trigger name was important and the mobile equals self was important is basically when we initialize the machine the machine is gonna look all the trigger names and it's going to look all the functions that match the trigger name and it's gonna wrap them so when you call play you're actually going through the machine first the machine the machine is gonna validate the current state and the state where you want to go if that is valid then it calls the actual play function if it's not it raises a machine error another thing that is important is it for example if you call play and you get an exception saying let's say that you try to play a file doesn't exist or you couldn't some something happen trying to execute this file if your function praised the exception the exception is going to be propagated by the machine and therefore the stage is not going to change so how do we test this we don't if you're using a state machine library you don't really have to test that the state machine library is validating that you can transition from state a to P and then you cannot move from one state that is not connected to the other one because that's the same machine job instead you can test the machine was initialized with the right transitions and they write initial state and then you can actually focus on testing real functionality you can test that the play function actually does what it's supposed to be doing same thing for pause and same thing for stop nothing related with the state like you don't really have to care about that anymore so let's add a new state and let's call the state rewinding I'm highlighting in red all the new changes the all the changes that I made today the rules when I added this state and a brand new rule as you can see there is a new node in the graph called rewinding and you see a bunch of new arcs so rule number one saying that a video can only be played when its pause stop or rewinding means that there's there's a new arrow going from the rewind estate to the playing state with the name of play the rule number two that a video can only be paused when his plane or rewinding means that there's gonna be an hour an incoming arrow to the post state from the rewinding state named pause the rule number three that a video can only be stopped when his plane boss or rewinding leads to that big arrow on the ride that is basically saying that that is going from the rewinding state to the stop state with the name of stop and finally a video can only be rewinded when it's plane or cost that leads to the two new incoming arrows to the rewinding state one from plane and one from pause and the name is rewind so let's take a look at the code in this case all we had to do was this we basically define in a new stage or rewinding and now we modify our transitions so in this case we for the rule number one we added one new transition that is going for the rwanda state to the plane state and the name is gonna be play rule number two with it exactly the same we're going from the rewinding state to the pause take the name is pause similar for rule number three points from the rewind estate to the stop steak with the name stop and then for the root brand new rule number four that a video can only be reminded when he's playing or cost we added two new transitions one going from plane one going from pause to the rewind mistake the name of the transitions going to be rewind that's all we have to do the only thing that is left here is to write the rewind function but we didn't have to actually change any other any of the play pause or stop logic we don't really have to care about the state of any of these functions and the other good thing is like the unit tests are not going to be broken the only unit tests that can be broken is they wanted tests that the machine was initialized with the right transitions but the other unit tests for play and pause and stop remain the same so when our boolean sorry know when you have to commit for boolean representing a single state if you find yourself checking multiple boolean in order to decide what the state of an object is something smells fishy here so there's got to be a better way of doing this when multiple based when business was informed by multiple bullying's along the same lines if you find yourself checking multiple points or even multiple constant multiple attributes in order to decide if you can perform an action or not then you're probably in the wrong place that you probably have to change your approach so when to use two machine when states are no binary do you have something more than two or false one and zero years or no you may want to consider using a state machine it's not a hard rule but you may wanna consider when you have to account for future States and this is not about over-engineering which we are really good at by the way it's about knowing for a fact that you're going to add new states anytime soon for example or even remove some states when you have to enforce complex set of business rules as you saw the presentation we were talking about three states and four states in some cases three or four rule systems cases and it got fairly complex the moment we had more states and more business rules is the complexity simply increases so if we delegate all these complexity to a state machine we can actually focus on implementing the code that we want to write we can focus on they like trading the functionality that we need to provide so in summary I would like you to consider using state machines to represent States and enforce business rules as we saw in the presentation when we use boolean to represent States and enforce business rules the code gets messy unmaintainable prone to errors and really hard to test just like the closet analogy on the other hand if we use state machines with like basically delegate this complexity and it also helped us decrease in the amount of Unicode that a unit test that we have to write it is important to mention that state machines are not a silver bullet so it means that it's not a one solution to solve all these problems so now your tools think about the problem that you're trying to solve and decide if it makes sense to add a state machine to your solution be mindful about it and bias your decisions that's all I have thank you very much
Info
Channel: Next Day Video
Views: 5,854
Rating: 4.953846 out of 5
Keywords: pytexas, pytx19, Python, HarringtonJoseph
Id: I1Mzx_tSpew
Channel Id: undefined
Length: 21min 50sec (1310 seconds)
Published: Mon Apr 15 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.