# The Visual Future of Reactive Applications with Statecharts

Canonical: https://davidk.dev/talks/the-visual-future-of-reactive-applications-with-statecharts/
Video: https://www.youtube.com/watch?v=o84Xw8qiTCw
Speaker: David Khourshid (@DavidKPiano), creator of XState
Type: Conference talk · Event: HolyJS · Year: 2019 · Duration: 1:01:09 · Views: 5752 (as of 2026-10-19)
Topics: Statecharts, Visual modeling, Reactive programming, State machines, XState, State management

## Summary
David покажет нам, как можно делать удивительные вещи с использованием state machines, делая логику работы вашего приложения более прозрачной и предсказуемой.

## Key takeaways (quoted from the transcript)
- We could just look up in states, the searching state, which is our current state, and then this on object contains a mapping of events to states. (10:00)
- We should model this as a state machine, where each of the different states over here models what phase were in. (15:00)
- The problem is that when you have many states and your app has more complexity and you need to add more states, the number of transitions increases. (19:00)
- Instead of that, we could use orthogonal states, and this is just a visual representation of being in all of these states at the same time. (27:00)
- You would take your application, you would model your application as a state machine on the side, like, don't put that state machine in your application just yet. (55:00)
- Finite state machines and statecharts, which are finite state machines, are less powerful than Turing machines on purpose, and it is important for them to be less powerful. (58:00)

## Chapters
- 0:00 Introduction
- 5:00 First of all, it's difficult to test…
- 7:00 A finite state machine also has a finite number of events…
- 17:00 We don't have any transition or any outgoing edge…
- 20:00 We could have all of these different states…
- 30:00 An integration test is basically you have a unit test with…
- 32:00 Only the shortest path, but all the possible paths without cycles…
- 43:00 All of the different paths you know throughout your state machine
- 45:00 We have support for actors…
- 48:00 I recommend you google this go to a chart autocoding for…
- 50:00 Complexity with statecharts after a certain point…
- 52:00 You replace your reducer logic with state machine logic without removing…

## Transcript
[0:00] Hey everyone, my name is David and I'm very excited to be here at Holi. - yes, it's my first time in Russia. I'm gonna be talking about again the mixture of state management and graph theory, and this is a very, very old concept called state machines and statecharts. But first, a little bit about me. My name is David, I'm known everywhere online, as at David Kay. Piano, like he said, I do play the piano, so piano is not my last name, it's just it's what I play.

[0:00] I work for Microsoft and I live for it. I live in Florida, which is a state in the United states, which is a part of Russia. So anyway, let's talk about a very common problem that as engineers, we deal with pretty much every day. So let's say that we have a fetch data buy in here. And this is a very simple button, you click it. It makes an API call and so eventually, after a while, you get a response back, a 200 OK response.

[1:00] But now consider that this API call takes a little bit longer to take. And so what you could do is you could show a spinner. And this is a typical way that we handle these kinds of issues. Is we show a spinner or we show some sort of loading state. But what happens if we had this button in? It's loading and then the user, out of frustration, clicks it a lot of times?

[1:00] Then we get a lot of API requests. So you might be thinking there's a simple solution to this. Of course, we could just disable the button and then after the data loads, everything is okay. But if you're anything like me, you could just go into the Dev tools and you could under Sabol that button. And then your user could just make more requests. So that's why I say one of the most neglected variables in programming is time, because we don't consider time a first classes.

[2:00] And in a lot of the apps that we do. The typical paradigm that we work in is called the event action paradigm, and this means that when an event happens, we calculate the next state based on that events. But if you've been working in real Redux, even mob acts you. Know that this is not exactly the way things work. And the more accepted pattern nowaday is that we have to consider the current states and the events in order to determine what the next state is.

[2:00] But that's also not adequate, because how do things happen in the app? We have to have effects, and so we need we need a better way to model these sorts of side-effects in our app. So let's take a look at a code example real quick. You could imagine this in any framework that you work with, whether it's React, View, Angular, Speltz, whatever. But let's say that you have an event handler which is on search, and the search takes in the query, and the query calls the Flickr API.

[3:00] And then, once it receives the data, it sets it to the state. So we see that we have a problem, just like we saw in the button, is that we don't have a way of showing that it's loading. So the typical solution for this is we have what's called a boolean flag. And so we set loading to true and then after we get the data, then we set loading to false. But there's another problem with this too.

[3:00] Now we have to manage what happens if there's an error. So if an error happens when we're trying to call the API, we have to set the error boolean flag to true and we have to set loading to false again. But then what if the user wants to retry? Well, then if they do on search again, we have to make sure to set that error boolean flag to false and set the loading flag back to true.

[4:00] And then what if we wants to cancel the currents promise, then we have to have some sort of cancellation flag. And can you all see that here? I'll zoom in for you. You have to have some sort of cancellation flag. That lets them know, it lets a promise note that the problems to cancel. And so there's a whole lot of problems with that. I don't even know what that says, to be honest with you.

[4:00] This is known as the bottom-up approach, and the bottom-up approach happens when we have some sort of event listener and we stop all of the application logic inside of that. Event listener so I'm going to give you a preview into what I'm going to advise for the rest of this talk is that your event listeners should only be one to two lines at most. It doesn't matter how complex your application is.

[4:00] You should not have logic in your event listeners, you should send an events delegate that events somewhere else, maybe do events that prevents propagation or whatever it is, but you should not have all this logic inside of your event handlers.

[5:00] So this bottom-up approach is typically how we start coding apps, and it is a source for a lot of complexity. And so there's a problem with this event handler driven bottom-up code. First of all, it's difficult to test, and it's difficult to test because all the logic in our app lives inside each one of those event handlers. This makes it very difficult to understand the app, whether you're a developer or a user, just because the developers cannot be too sure where the features are, where the app logic lies.

[5:00] Because it's spread out all over the place and the users might run into edge cases where they're not sure, is this the way the app is supposed to work? This means that your code will contain bugs. For sure. It's just a mathematical, you know, definite probability, because you have so many different states everywhere, and so this makes your code difficult to enhance. Where I'm sure you've all run into the situation where if your boss or someone tells you, Hey, we need to add this feature, it's a small little thing.

[6:00] It'll be easy, right? And then you realize that feature actually affects so many different parts of the app, and in fact, features make it worse. Because the more features you add, the more combinatorial complexity that your app, your app now contains. So how can we better model the behavior of user interfaces in a declarative way and in a way that's easy to understand? It turns out, the solution has been around for over half a century.

[6:00] And it's called finite state machines, and there's also something called statecharts, which we'll talk about a little bit now.

[7:00] If you go to Wikipedia, there is a mathematical definition of a finite state machine, which says that it is a tuple of five parts. So it's Equinsu Ville. A finite state machine has five parts. the first part is the initial state, so all finite state machines need to start somewhere. And so in this example, we have an initial state. For a promise in which its idle, nothing's happening yet. Finite state machines also have an alphabet, which is the mathematical term for it.

[7:00] But it is the number, the finite number of states that you could be in, and so the rule with finite state machines is you could only be in one of these states at any given time. So a finite state machine also has a finite number of events that could happen in the state machine. And these events could come from anywhere, they could come from within the machine, they could come externally, they could come from other services.

[7:00] But the point is that the machine reacts to these events, and when it does react to these events, it transitions between states. So if you're in the idle state and you have a fetch event now, you go from idle to pending on that fetch event. And so these transitions, of course, are also finite, and they determine the behavior of the machine. And so you also have a finite number of final states, and these are states that indicate that the processing of the machine is done.

[8:00] Now. Typically, applications we don't have as done. Because they live for, you know, the lifetime of, you know, however long the app lasts. But if you have something like a form wizard, then you could have like one final, you know, ending step, and then that indicates that it's complete. So let's take a look at our original problem, where we have a searching and we have, you know, we want to either resolve or reject it, and we want to give the user the ability to search again.

[8:00] So this could actually be modeled as a finite state machine, as you see here. And so we see that when we're in the idle state and we do a search now, we're in the searching state. Notice that there is no outgoing transition, or, in mathematical terms, an outgoing edge from the searching states on the search events, that means if the user presses that search button many, many times, nothing's going to happen because that events.

[9:00] Is not handled in the current state. So already you are preventing an entire class of bugs that you would otherwise have forgotten. So, one typical way, in many languages that you would create a finite state machine is with a switch case statement. And so you're gonna see, no matter how you implement it, you're doing the same thing. You're defining transitions between the states and events so that you could determine what is the next states, given the current state and the event.

[9:00] So with a switch case statement, you would first take a look at the states. In this case, it's it starts at idle, or this case it's searching and so in that state. Then you switch on what the event is, so you could sort of picture this. If you do Redux, this is sort of the same as a Redux reducer, and so you switch on what the type is, and then you return the state.

[10:00] That results from being in the current state, which is searching, and the events resolve, happening, and so you get success. However, I find this very, very, very tedious to type, and the problem with that is that not only is this a lot of things to type. But you can't really go through and enumerate each of the states. And so a nicer pattern that I found a couple years ago was using objects instead.

[10:00] And this object is just a relational mapping between states, events and next states, so to translate the previous example into this object. We could just look up in states, the searching state, which is our current state, and then this on object contains a mapping of events to states. That results from that event being performed on that state, and so, for example, for in the searching state, the resolved event happens. Now we're in the success states.

[11:00] And so this is a lot more concise than this, and I just want to emphasize that, because not only is it more concise and, in my opinion, a lot easier to read. But we could take this and we could actually visualize it. So brother, visualizer a while ago, let's see if this works. And so we could just copy and paste that right into our visualizer if it lets us. And so this is just a JSON, so we could just.

[11:00] Put that in like that, cool. So now we have an automatically generated visualization of our application logic, and so you could see all the different parts of the state machine. Over here. We have Idol searching, failure, success with all the transitions. And the only reason this is possible is because we're defining our state machine in the declarative way. And with this, we could even simulate the state machine. To where we could, you know, resolve, we could project, and, you know, we could just go through each of the states.

[12:00] So we'll talk more about that in a little bit. But that's one of the biggest advantages that I see to using an object instead of a switch statement. So to actually make this machine work in real life, you would need some sort of function. And this function looks very, very close to our reducer that we've been using in Redux or NG RX if you use Angular, but we have the same, the same function signature, so in this transition reducer we have.

[12:00] We have first year state, which defaults to the initial state, of course, and we have an event which is passed in from the machine. Into what we would do would. We would first look up the current state and then we would look up the event on that state, and this should be events type in that event. And if that event is not handled, we just return the current state. And so in these six lines, we're able to represent our state machine that we created here and use it within our app.

[13:00] Because we're able to tell what's the next state based on the current state. So there's another solution for this, too, that I created a while ago. It's called XState, and the way that X8 works is, it takes that exact same structure that we made. And if you wrap it in a machine, you just important machine from XState, then it's going to do the exact same thing. The difference, though, is that we have a transition method built-in and that transition it's actually a function.

[13:00] That transition function takes the current state, the events that happened, and it returns the next state. And so, of course, you could use a an interpreter as well, and so you could make this machine, which is. Just a pure object and the machine dot transition function is of pure function. And you could actually make it a live stream of events that you could, you could imperative Li send events to. So, in this instance, we're interpreting the machine, and whenever a transition happens, we're logging that state.

[14:00] And so if we were to send the search events to this running service from the interpreted machine, then we're going to get this state. Object that logs a value of searching, which is exactly what we want. And it includes a lot more nice things that we'll talk about in a little bit. So one of the earliest examples I made using state machines in XState is this interaction that I saw on Turbo.

[14:00] By a illustrator named Cal shear makes really, really awesome animations and they're always fun to make, so this animation in particular. You, you could drag, you could take a bunch of states and you could delete them. And you could edit your week and make Sunday last a whole lot longer, which sounds really nice. Turns out that this was a lot more complicated than I thought, and instead of having to do it, like with code and with React or whatever.

[15:00] I sat down and I said, you know what? We should model this as a state machine, where each of the different states over here models what phase were in. So, you know, we could at first be in the start state and then we could be in the selecting state where we're drawing that rectangle. And then once they're selected, two things could happen. We could either let go and then we're back to the selecting state, or we could drag and then we could be in the tracking state.

[15:00] And then, depending on if we actually put the put the dates in the trash bin, then we could be in the disposed state. So just to show you that there's a lot of complexity here in this simple animation, and that's why I created a state machine. Because, for example, if I don't select anything, this should just disappear, if I do select something and then I click outside, it should also disappear. If I select some of the days and then let go, I should be able to resume and grab it again.

[16:00] So you see. That the act of dragging my mouse does different things depending on what state I'm in, so dragging again over here will not show that. That rectangle because we're now in a different state. And so, yeah, so with state machines as well, the software bugs are made very, very clear. And the reason why is because we're able to visualize the states and transitions in our application, and we could apply graph theory principles to that as well.

[17:00] So take a look at this machine, we have three states, we have idle loading and success, so you might wonder what exactly is wrong with this machine?

[17:00] And one thing we always forget is that in the loading state, an error can happen, so what happens if an error happens? If you showed this graft someone, you could see that. We don't have any transition or any outgoing edge, as it's known in graph theory, from the loading state or the loading vertex. And so we say, OK, we could have a failure state. But now here's here's two little graph theory terms.

[17:00] We have what's called a source vertex, which only contains outgoing edges, for instance the idle state. We have an outgoing edge from idle to loading, but no incoming edges. And we have a sink vertex, so these sink vertexes don't have any outgoing edges. Which means that if we go to the failure state, there's no way to escape the failure state. And so these could be detected, of course, using a simple algorithm that you keep track of which edges each node has and which states connect to it.

[18:00] And we'll talk about that in a little bit, but because we know that this is a sink vertex and that there's no outgoing transition. We know that this is a problem because our goal state is success, and because our goal state is success, we want to make the user able to transition somehow from this failure state to success. So what we could do is we could add an edge, and we could, you know, allow the user to retry from the failure state back to the loading state.

[18:00] And now you see that we could trace a path in the graph, going from idle loading failure, loading success, and so we're literally setting the user up for success. So does this scale? That's a typical question. When people start using state machines, they think, OK, we're going to use the state machine everywhere. I'm going to make my app and a nice big state machine. And just every time I have in new states, I just add a new transition and add all the transitions that come to the state.

[19:00] But we get to this problem called the state explosion problem. And I encourage you to go to Wikipedia and look up state space enumeration for more information on this problem. Now, the state explosion problem, which is. It's a really risky thing to Google at the airports, and I shouldn't have done that while making this slide. But the problem is that when you have many states and your app has more complexity and you need to add more states, the number of transitions increases.

[19:00] And so when the number of states and the number of transitions increases, then you have an exponentially larger combination of states and transitions, and also possible paths throughout your state machine.

[20:00] So, this was solved in 1987 from a computer scientist by the name of David Harel, where he wrote statecharts, a visual formalism for complex systems. And if you look this up online, there's a nice PDF with a lot of graphics that really make it easy to understand. And so it's one of the nicer research papers that I've read. But everything I'm talking to you about today is based on these very old research papers.

[20:00] So David Harel made the statecharts formalism, which he also called hierarchical finite state machines. And these give you a lot of nice benefits over, say, machines that make it easier to manage states. So, for instance, we have actions, you could think of actions as side effects, because that's exactly what they are. But instead of side effects just happening anywhere, we have three possible places where side effects can happen. Whenever you enter a state, which is known as an entry action, whenever you exit the state, which is known as an exit action or a non exit action.

[21:00] And whenever a transition happens, such as when the search transition happens, and that's known as a transition action. You also have guards, so you could prevents transitions from happening. For example, if we're in the idle state and our query length is not greater. Than zero, which means the user hasn't entered a query yet. Then this transition will not be chosen. And so it's useful to not use too many guards. Because then you're back to the boolean flags and if-then nested conditional traps that your old applications suffered from.

[21:00] But they are useful in small parts. And so to see this in code, if you're using XState, then, for example, we have these. These entry actions over here, which is prefetch resources and fetch results. So anytime you enter that state, those actions are going to be executed by the interpreter, not by the machine itself. And then on this search we, we could expand that search string in error that should be searching, we could expand that string into a, into an object with a target.

[22:00] In a conditional, that conditional is what's known as a guard, and that determines whether that transition could be taken. So this is the same thing if contexts are queried, that length is greater than zero. There we go, then that transition will be taken, otherwise we stay in the same state. There's also the concept of extended state as well, and so extended state you could think of as states that doesn't necessarily fit into finite states.

[22:00] So in our example searching application, we had these well-defined states of where idle were searching. And then we might have a success, we might have a failure, but then their states that can't really be modeled in a finite way, such as the query. And that's because the user could type a nearly infinite number of possible queries, and we don't want to model each one of those. So instead, we put this in what's called machine context, which is just it's a data like a states container.

[23:00] And so we could change those using actions as well. And so in this case, we assign the query to the event target value, so you could imagine that this came from some sort of a text input. So there's also the idea of hierarchy, which is nested states, and so this group states that have common behavior and allows you to infinitely nest these states in the recursive way. And so it makes it a lot easier to deal with the state explosion problem, as we will see soon.

[23:00] And there's also orthogonal D also. Known as parallel states. And that means that when we enter a parent states that has orthogonal states right next to each other, then we're in both of those states at the same time. Now, I don't want you to think that means that we're violating the rule of state machines, where you could only be in one state at any given time. But instead, it makes it easier to represent a combination of states.

[24:00] And there's also history states, which allow you to go to the last state that a parent state was in. And so it's also very helpful for managing how many states. Yeren so let's take a closer look at hierarchical states, for instance. When we see the success and failure states over here, we see that there's a search transition that's outgoing from each one of those, and this is what's known as common behavior.

[24:00] And so we could group those two states in one common states known as the search state, or whatever you want to call it, and so we could see in the search state. You know, we could either be in success or failure. And for both of these states when the search event happens, because they're not handled directly by each of these states there, instead handled by the parents. We know that no matter which state were in, we could go to the searching states.

[25:00] So you see how this reduces the number of transitions just barely, but it makes a bigger impact the more complex your app gets. And so now the way that we do it in XState is that we had this machine. And because this is a declarative JSON like structure, in fact, you could declare your entire machine as a JSON object. We could infinitely nest, or, well, however much your computer could handle, but we could nest each of these states inside the parent state as well.

[25:00] So we see that we have that we have the success and failure state nested right inside the search state. And we could handle on the parent states that, when a search event happens, were in the searching state. So this also allows you to refine behavior in which, if you're in a state and that state eventually evolves to have more complex behavior. Then the overall machine doesn't need to change. You could. Still have three states like idle searching and searched, but we could refine these states, for example, searching.

[26:00] We could be like searching for users all right now we're searching for this user, okay, now we're searching for these users, friends. And so we could have all of these different states, but we could still be in that parent searching states. Now orthogonal states are a different beast. Let's say that you're trying to model a text editor in which you have three buttons. You have a bold button, italics button, and an underline button.

[26:00] In order to represent each of the states that those could be in, even though there are a finite number of buttons, only three. We have two to the power of three or eight states, so you can imagine if we add something else like Strikethrough, now we have 2 to the power. 4 or 16 possible state. And so you could see, this is where state explosion happens. Because we need to represent each one of these pulled off italics, Alvin are lying off, bolt on and Telex off, underlined off and so on.

[27:00] We need to represent each one of those as its own state. So instead of that, we could use orthogonal states, and this is just a visual representation of being in all of these states at the same time. So looking back at here, this does not violate the rules of what a finite state machine is. We're still in only one of these states. But it's just visually represented differently. In which each of these start in the off position, and when we toggle each one of these, they're in the on position.

[27:00] Now. Doing this in XState is pretty simple as well, so we have a type of parallel and so we add this to the machine. Just to let it know that we're not going to give it an initial state, instead, we're going to say that every single state that's inside, we're going to be in all of them at the same time. And then we have, you know, all of our state's. In fact, I added a strikethrough state, and these states are modeled right up here.

[28:00] Where I just, you know, I have a function that gives it the state, and so that should be toggled. Config' bold toggle Config italics. Underline and Strikethrough. And we could configure each one of those states now. What this gives you as a state value is, instead of a string or an object with one property, it's going to give you a state value of every single one of those properties. So we could say bold is either inactive or active, and then when we toggle Bolt, for instance, now it turns to active.

[28:00] And we could see that the other states are completely untouched. And so that's a way that we could model many states at the same time. Just because, naturally, having an object mapping of states to their state values is combinatorially represents all of the possible states that, you know, those are combined in. So I showed you a previous visualization tool that I made, but there is a newer one and I'm actually going to update it pretty soon.

[29:00] And so this visualization tool actually allows you to copy and paste those machines that we saw over here, like, you know, this one or the previous one. And you can copy and paste those and put them in the tool. And so let's just go to the tool real quick, so and you could see that over there. So this allows you to copy and paste that same exact XState code and visualize it over here and that way you could.

[29:00] You could model your application visually and be able to verify that all of the transitions and states are exactly as you expected.

[30:00] So this is just JavaScript and there's also a way of, like, you know, verifying states, and so you could see in this sample application. Whenever a promise fails, our attempts increase, and so that's just a way of modeling contacts. Or after a timeout, we see that goes to reject it as well. So not only are there ways of mount modeling state transitions, but there's also ways of modeling time as well. For example, we have this timeout sets of two seconds, and we could say as a transition after that timeout.

[30:00] Go to the rejected states. And what X8 handles for you out of the box is that the timeout will be cancelled if we transition away from that state. So you notice that time I was cancelled and we didn't go to the rejected state, so that's just, that's just. A way where the visualizer is useful. Or, you know, let's say that we cached this and we just go to fulfilled. We could update that machine and see our updates live.

[31:00] So there's this is the exciting part of the talk. Because you might be thinking, okay, well, this is just like real X or Mob X, or any of these other, like NG RX. But there's a reason that I'm so passionate about using state machines and statecharts, and it's because there's many other purposes just managing your state. For example, you could use state machines for integration testing. And so I'll explain. An integration test is basically you have a unit test with tests only one specific thing, and an integration test, which tests many things that are supposed to work together.

[31:00] So, an end-to-end flow, depending on whether you're doing it in a live browser or doing it in a simulated environment. Such as JSTOR is could be considered an integration test or an end-to-end test, if you want.

[32:00] But the results is still the same in that we need to go through each state in order to get to a goal state. So let's say that we have an app with five states ABCDE. We see here that in order to get to see, we must first go to the A state, then go to the B state, and then we eventually end up in the Sea state. So there's many different ways to go to each of these states in this diagram.

[32:00] And the truth is that when you are creating your apps, there's many different ways that the user could go from one state to any other state in the app. And you have to be able to manage every single one of those possibilities. Because every single time that you get a bug report in your application, it's because you did not properly test that. One path. But the problem is that there are, there could be hundreds, if not thousands, or tens of thousands of those paths.

[32:00] And, you know, this is easy to show, like, you know, using shortest path algorithms, you know, in which we could see that. We, you know, we have many different possible ways to go through each of the paths. And so, for example, if you're using Dijkstra's algorithm, then you could use weights. As well, in analytics, which I will talk about in a few minutes, analytics provides those weights so you could figure out what the shortest path to any state is from the initial state.

[33:00] And it might not always be ABC, it might be something different, like a Dec. And so when we have these analytics combined with a graph, we represent the happy path that your users are most likely to take. And so these tests could be prioritized. And, of course, because these algorithms work on this directed graph, these paths can be automatically generated, which makes testing a lot easier. Especially when your application changes and you need to change like the different states, or you need to add a new feature.

[33:00] So there's also death first search or breadth first search, whichever one you want to use. And these algorithms are useful for finding all of the simple paths. I'm not going to go through the algorithm exactly, but it works similar to Dijkstra's algorithm, except in a simpler way. Where you would visit a node and then you would visit each one of the other nodes. And if you, if you see that you've already visited a node from a certain path, then you've detected a cycle, and so simple paths are every path to every state without cycles.

[34:00] And so that's important. Because if you don't want infinitely many paths, you're going to have to assume that your user isn't going back and forth between pages, infinitely. Because if that's the case, something is wrong with the user and not the application. But as you can see, there's many different possible paths between A and C, and there's two possibilities here. We have a, B, C, A, D, E, C, and so on.

[35:00] And so this represents all the possible user flows, again without cycles. And the reason why these are so important is because they actually reveal all of the edge cases for us. Because when the user does something unexpected and when they do something that causes a bug, and we're like, Wow, we didn't have a test for that. Then. That was one of those obscure paths that the user took that we didn't realize actually has a hidden bug.

[35:00] Now, these could be automatically generated as well. Now the warning about this is that because we are generating not. Only the shortest path, but all the possible paths without cycles, that we're going to be generating a lot more paths now. This is very, very useful if you wants to comprehensively test your entire app and every single possible way. The user could do it. But it could also make your tests like an hour long to take.

[35:00] And so, I mean an example app where it's just a feedback app. And we were able to generate all of these different paths that go from like one part of the app to the other part of the app. Now. The beauty about this is that when you change the state machine in your app, these tests are also updated because it's going to find new paths through your app. There's also another area that I want to talk about, where state machines and statecharts are particularly beneficial to developers, the determinism of state machines.

[36:00] In which not only could you be in only one state at a given time, and there is a deterministic way of determining the next state in which you're not sure that there's going to be impossible states or whatever. That determinism is very helpful to developer experience, and so is visualization as well, because you're able to see your application logic a lot clearer. Communication is also important, too, because when you have those visual diagrams, you're able to talk to your designers, developers, stakeholders, project managers, and more.

[37:00] And so, as we saw, testability also helps with not only the developer experience, but making sure that we are uncovering possible edge cases that your users might run into. But, of course, we don't always have users at our disposal to test our apps and test every single edge case. Which is why you can imagine that you could use simulation with these state machines in order to simulate what the user could do.

[37:00] And finally, you could capture analytics that track maybe not everything, but just how the users used the app. So this gets into the area of adaptive user interfaces, where we could go beyond just creating an app that works in creating an app that works well for the user. Now, there's a few steps involved to doing this. First, we create that abstract model of the application, this abstract model is what that finite state machine.

[38:00] Is it describes what the user is going to do? Then we have transition analytics in which we track every time a user transitions from one state to another based on an event. We identify which parts of the app are adaptive, and we use the analysis that we captured to adapt those paths in real time without having to go through development cycles. And the result is an adaptive app that responds to the user.

[38:00] And because we're representing our app as a as a directed graph, we could actually have those analytics represented in weights in that graph. So, for example, let's say that 90% of users, you know, go from sign-in to success. Then we could emphasize and visualize that is the path that's most taken. And so we could, you know, be able to use that for analytics, testing, simulation and more. In fact, in AI at the visual Studio, not visual Co, but the VIAS live share team, in which you could.

[39:00] You could collaborate with developers from across the world using VS code visual Studio, and have more than one person edit on the same file at the exact same time. Now, the user interface I, which is visual Studio code. I wanted to model what was actually happening inside the app and what the users were doing. Because we didn't have rich analytics into that, and so instead of littering our entire code base with, like, alright, track these analytics and track these.

[39:00] Instead. I just had them in one place, which I'm going to show you. And I used those analytics that we tracked and made this D3 visualization so we could see that. Obviously, most users are going to go from initializing to signing in, and then a couple things can happen. They could either do externally signing in, which means they're going to that login with Microsoft or GitHub page, or they could immediately go to signed in.

[40:00] And so we could see that most users are going to sign in now in the sign-in page. We want to get analytics on whether more users were joining a session or sharing a session, and so we see that as expected. Those are about equal. So this is just an example of the analytics that you can uncover just by making a state machine for your application and adding. Those analytics, and so let's say that we're creating a sample Instagram application.

[40:00] We have our login page, gallery, camera profile, and we wants to see that these paths could actually be adapted. From Logon, we immediately go to the gallery page. But we might be thinking, what if the user has a different preference, instead of manually picking that preference? We could measure how often or how likely a user is to go from one state to the other state. And so, for example, going to the gallery page, we see our thing on the gallery page, we see that this is the total weight of taking those paths.

[41:00] But going from gallery to camera, we see that users are more likely to navigate away from the gallery page, in directly to the camera page. And then, of course, the profile page is the least likely. What we could do with this information is we could see that since users are more likely to go to the camera page. We could instead adapt this transition to go from login to camera instead of logins to success.

[41:00] And so there's many different ways that you could use this as well. Let's say that you're trying to show ads and you wants to have some internal scoring mechanism that whenever a user a clicks an ad, then we wants to emphasize those, those decisions a lot more. Whether the ads are interspersed are shown at the top, so if they're interspersed, then, you know. If the user Scrolls away from them, then we score negative one, or we could score, you know, negative ten if the user Scrolls away from.

[42:00] The ads shown at the top. And this gives us a better idea of where to show the ads. Not that I recommend using state machines to show ads to users or anything, but, you know, it's just an idea. You could also use decision trees because you remember that extended state. We have that contextual data and we could use that contextual data, such as registration date or just any details about the user.

[42:00] In order to make decisions within our adapted path. And so we could, you know, just going based on the previous state machine, we could see that. Based on whether they're in a user or friend count, we could decide which paths to take in. That state machine, and which ones to emphasize? And so these analytics become just simplified using that interpreter again, we're just putting a putting that analytics track right inside of the interpreter.

[43:00] And so this becomes a single call because you represent your entire app and system machine, and you could track analytics right in there, you know, giving you the target, the source, which is where the word, the person went, the events, which should be sanitized to remove personal details, and, you know, time stamps.

[43:00] So there's also X - 8 / graph, which is it contains a lot of graph, you know, graph theory, ways to represent. Like all of the different paths you know throughout your state machine. So, for instance, this is getting the shortest path of your machine. You could pass the machine directly in there and it's going to return you all of these shortest paths. So a is B is B, the C, etc.

[43:00] And it does this using weights as well. Now you can imagine the possibilities for this where we could also use reinforcement learning or something close to it to predict the users behavior in the application. And so the way we would do this is you would have some sort of agents that would learn based on all of the analytics that we captured, and it would learn based on the environments in which we've modeled as a state machine.

[44:00] And it could be able to predict how a user is going to behave in the app. So, for example, we could easily model a tic-tac-toe game, you know, as a finite state machine. But because we have all of those transitions represented in the state machine, we could enumerate through them, which gets a little bit nasty. So I don't really recommend you do this in real life. But the result is that you could create a simple AI that plays against us and is able to dict.

[44:00] I think this one's gonna tie, where'd it go? So it's just to play terribly okay it one. So, you know, that's just an example of, you know, one way that you could utilize state machines, and so basically we take that metrics tracking.

[45:00] You could store it in Google analytics, MixPanel or whatever, and yeah, basically get adaptive user interfaces now. Exeed also works with Redux as well. And you could add this to the Dev tools, and you don't necessarily need to use XState. With Redux. In fact, I recommend you use it alone, as there are some pretty big differences between XT and Redux. In four point six, which I just released yesterday, I want to release it live on stage by accidentally published it, so it's out there.

[45:00] Now. We have support for actors, which is a completely different model than Redux. When it comes to managing state, instead of having one global state container, we have tiny state containers that communicate back and forth with each other. And actors can do one of three things they could create more actors, send messages to other actors and designate. Its behavior, and its behavior is defined by the state machine. So the reason that this is important is number one.

[46:00] The actor model has existed since 1973. You know, Carl Hewitt and Alan key, you know, invented the ideas of the actor model separately, but, you know, they came together pretty well. And it's been in use ever since. There's popular languages such as Erling and Akka, which used the actor model, and so we're now discovering that we could use the actor model directly in our user interfaces and so to do this. In four point six.

[46:00] We had this new spawn function, which spawns a new actor, and then we could send back and forth communication between those actors. There's also support for observables in the coming version, in which you could just place an observable directly in there and be able to listen to its events. Plus, an interpreted machine is also observable, too. Because has that subscribe method. Now there's a lot of great stuff coming to XState in a lot of stuff that's also released.

[47:00] For example, you could use X didn't React with a hook, and hopefully you all are using hooks by now. But there's this useMachine hook, which works exactly the same way as a reducer, except it also executes those side effects in a managed way for you. So you useMachine, you pass in your machine, and you have. You could declare that we represent your UI using that, and in fact, the visualizer is created using useMachine as well.

[47:00] There's also FSM, where if you don't need those nested states, you. Could use FSM, which you download from at X8 FSM. And that gives you a very simple way using the exact same syntax to model your state machines. And this, it's also extremely tiny, it's less than a kilobyte gzipped, which is pretty nice.

[48:00] So X8 has been used for more than two years in a bunch of places. Some of you might be familiar with Gatsby, its use in the file watching processes there, and they actually have a pretty involved statechart because it helps manage complexity. And there's also a talk at Google Dev Summit, where they used XState and the actor model in order to demonstrate how to use separate threads on the web. So you might think I'm talking about the future of state management, which I am, but all of this is nothing new.

[48:00] This is all based on a spec called SE XML, which is a chart XML. And there are some popular frameworks and platforms that are using SSE XML today, such as QT. And you can do tools, and so these tools work with Java, they work with C++ and Python as well. And they've been used in embedded electronics, automotive technology, Aeronautics and more, especially for simulation. So this is the exact same spec that XState uses as well.

[49:00] There's many advantages to using statecharts. It was used by the Mars Curiosity Rover, and they cited many benefits to using it. And so that was really cool to find out. I recommend you google this go to a chart autocoding for Curiosity Rover and just discover there's a really nice article on all of its benefits. There. There's also disadvantages to using statecharts, which I succeeded as three different categories. First of all, of course, there's a huge learning curve, something that we really couldn't cover in one hour.

[49:00] Modeling requires planning ahead, too, and this is a learned skill. You can't just model everything because not everything can be modeled yet. And you have to be smart about the way you model things. Because turns out, there's always a simpler way to model something.

[50:00] So there's also complexity trade-offs if you use it in FSM. If your app is not complex and it's going to be the simplest way to go. The typical way that we create our apps using the bottom-up approach just increases linearly in. Complexity with statecharts after a certain point, we see a reduction in complexity just because of nested states, the orthogonal states, the manage transitions, and the overall simplification of our app logic.

[50:00] So there's a lot of really good resources to check out. - such as the world of statecharts in the spectrum community, where we have awesome conversations all the time about statecharts. And in short, I wants you to make your code do more. I don't want to just have code that manages our state or does one thing. Or just ship stood outside the customer. I want us to create code that is testable, able to be visualized, simulated, analyzed, and more.

[50:00] And so with that. Thank you so much whole EJS for having me. [Applause]. Thank you, thank you, David, very much. It's really, a very powerful idea and we have some questions and I have some questions, so let's just sit down and continue our discussion. Come on, here's a sit. So first, it all looks really, really interesting and it Maps very well to any web project. I think we can describe pretty much everything in our life using statechart.

[51:00] Yes, oh yeah, this is cool. How do we go back to practical track? And here in our talking about XState, right? Your project? So just imagine, let's let's imagine we have two states Greenfield project, we just start with something, and more complex Brownfield project, let's start from the first.

[52:00] So I have some technical tasks to build some web project, and I really want to use statecharts. How do you recommend me to start npm? Install exact state? What's next? Actually, that's not even the first step, the first step. You take a pencil, you take paper, and you start drawing out your states. You start visualizing on paper what the app, what the app logic is going to look like. And so you're gonna find yourself doing a lot or raising, doing off.

[52:00] Oh, no, it should be this way, it should be that way. And then once you have your model, then you could use it within XState. And so, the easiest way to think about XState is. It's just an event emitter, you're listening for events, you're sending in events, so this works basically with so many different API. So that we've already used, especially Redux, where you're listening for state changes and you're able to dispatch.

[53:00] And so, if you treat X8 the same way. In a framework agnostic way, because you could use it with any framework, then it's easy to adopt into any existing app. So what exactly XState is? Is that state management library like this? In a way it is, it's a state management library that's based on the SC XML, which stands for a statechart XML standard. And in fact, one of the big reasons I wrote EXeed it was because I didn't want to write XML because that's painful.

[53:00] Does it also help you to visualize your state? Yes, so anything, you write an XState. And this is one huge difference from Relaxes. You copy and paste that exact same JavaScript code, put it in the visualizer, and you're able to see, visualize, and, you know, edit your machine right from the visualizer. Oh, cool. So you start with a whiteboard, then you implement your machine in the code, and then you click visualize.

[53:00] And you can compare, right? Is that correct or not? So they should look the same your initial idea and what XState should look exactly the same. So if you could represent it as a directed graph on paper, then it's going to be the exact same thing in AX state. Awesome, this is. This is really good to check ourselves well. What if we have project some web application like, say, medium complexity? Without any sort of state management?

[54:00] So we are really, really tired by caching with all these different states, all these subtle errors, hard to test. And we are choosing state management like library, and we decided to use XState. What are our steps here? Just imagine that we already have the project ready, should we architectured it seriously? Not now quite yet. And so actually, this is really exciting, as I'm giving a talk about in August. But the first thing you do is write tests, but you write tests by not writing tests, so here's how that goes.

[55:00] So you would take your application, you would model your application as a state machine on the side, like, don't put that state machine in your application just yet. And then I have an article coming out on. This? But there is a concept called model-based testing, and model-based testing alone is it's 20 years old, so these are all very old concepts, and model-based testing is. Instead of manually writing each test, you take this state machine, all of your application, and you generate using the algorithms we talked about, generate.

[55:00] Each of the paths in each of those paths are a series of steps that say, Oh, you want to log in? Let me go through the graph, okay, yet? The fill they use from me and fill the password, click login to that. But instead of manually coding that, you would figure that out with the state machine and those algorithms. And so when you use your out your state machine to test your application once all the tests pass.

[55:00] That confirms two things number one, that your app doesn't have any bugs that you've tested, and number two, that you could use that state machine inside of your app. And then you would do it in the exact same way you would replace parts of your app that we're using. Manual state management and instead, you use this basic events emitter approach, where you're responding to events and you're sending events up. Nice and short state EVF project with, say, Redox state management man.

[56:00] We are unhappy because this complexity curve goes like crazy on top, and we decided to switch to XState. What could be that transition path? Maybe some recommendations in transition path? I see what you did there, but what you could do is not necessarily get rid of Redux just yet. Instead, you could take each one of your reducers, model those the state machines. And then you could use XState transition function inside of there, because the transition function itself is a reducer.

[56:00] And what you're doing is you're given the current state, which contains more things, that contains that value, the context, actions, everything like that. But you take that current state, you take whatever event comes in. And it's the exact same since axis Redux as well, and then it returns you the next state. So you replace your reducer logic with state machine logic without removing Redux, without removing the reducer. And soon enough, you're going to see that every single reducer in your application turned into a state machine.

[57:00] And then you could. Remove Redux. So it's like a bit by bit sort of thing. I think this is the best puns ever when you don't have to switch everything completely at one step. But giant by we can eat, elephant by needs, right, right, cool and locations from our 10. This Roman is asking, is there some form of prevention of infinite loops in effects in implementation of exit 8? So there's not any built-in one, but that brings up a really interesting point in computer science.

[58:00] We know that there's this thing called the halting problem, and the halting problem is a problem. With turing-complete languages, such as well, every single language you use. And that means it's impossible to detect if a cycle is going to happen now. Finite state machines and statecharts, which are finite state machines, are less powerful than Turing machines on purpose, and it is important for them to be less powerful. But what that means is you could detect infinite cycles before they happen, because you could analyze the graph and see, oh, wait a minute.

[58:00] There's an infinite cycle over there and there are algorithms to do that. Nice. And the last one about comparison do you have some benchmarks? How XState compared with Redux Mobiles? Whatever else? So I don't have any performance benchmarks on that quite yet. Because the so, the algorithm, of course, it's like a, it's with finite state machines, it's o of 1. You're just doing an object lookup, you're looking up, all right, what's my current state, what's the event, and what's the next state?

[59:00] And so it's a 1 now, of course, if you use a switch statement, it's going to be a little bit faster, if you use just, you know, your normal programming, it might be a little bit faster. And so that's not entirely the concern. My concern was I want to keep it to O of 1, or O log of N, and the way I make it o log of N is. When you have nested state machines, now you have to, you know, traverse that hierarchical graph so that makes it log of N.

[59:00] But still, you know, as fast as it could be. With that said, I'm still working on performance optimizations. And also with 4.6, many of you who are using Redux know that. Redux is one global state, and so that means that when you modify one part of Redux, every single reducer is going to update. Unless you have some really smart, you know, memoization. To prevent that from happening in, even then, inside of your reacts components, you need selectors where Redux says, Hey, something changed in your component, says, hold on, let me see if the thing that I care about change.

[1:00:00] And you have to do all of that manually. XState takes a completely different approach, known as the actor model, where instead of having one global state, it's like having local state in each of your components. So by default, that means if one change happens here, or happens here, or happens here, nothing else is going to know about it. And that's because only if they care about the state of the other actors are they going to be notified.

[1:00:00] This is the exact same principle, by the way, that Mob ex works on. And so you learned in the last talk that Michel gave. The algorithms where change detection is only based on what cares about those properties. And so, in my view, it's a smarter approach than Redux. Where you change one thing and absolutely everything changes. And so in that you're gonna find performance a lot better. Awesome, yeah, I think pretty much thank you [Applause].
