Visually Create State Machines
Visualizing app logic is a game changer. In this episode, David Khourshid will teach us how Stately lets us visually create state machines and statecharts, then use them directly in React.js apps.
Links & Resources
Full Transcript
Click to toggle the visibility of the transcript
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Hello, everyone, and welcome to another episode of Learn With Jason. What is happening right now? Get out of here, you unmuted thing. Let me refresh the page here, because it's not showing up my -- there's the overlay. Come on, you can do it. I wonder which service is hanging right now that's causing this to be -- anyone? Huh? There it is. Okay. Always an adventure on this show. Never a dull moment. So, hello, everyone, and welcome to another episode of Learn With Jason. Today on the show we're bringing back David Khourshid. How are you doing?
DAVID: Doing great, how are you doing?
JASON: I'm doing wonderful. I'm super excited to have you back on the show. I always feel like I learn a ton when you're here, but for the benefit of people who are maybe meeting you for the first time, do you want to give us a bit of a background on yourself?
DAVID: Yeah, sure. So, at the very beginning, I was a pianist, let me point to the right place, there we go. But I turned to developer, have been a developer for about ten years. Most recently at Microsoft, and now I'm basically starting my own thing at Stately, which is a company for making software modeling tools and services for visually modeling and analyzing application logic. So, yeah, that's what I'm doing.
JASON: Yeah, that's very cool. So, when you say "modelling application logic," I think a lot of us, myself included, are maybe a little fuzzy on exactly what that means. Can you give us a bit of an overview of what modeling application logic entails?
DAVID: Sure, the most basic summary is modeling application logic is what happens when you take pen and paper before analyzing any code. So, understanding what are the possible modes or states of my application, what are all the things that can happen in it. And that can be coming from users, or other signals, such as when you actually receive data from a fetch request. Like all of these things play together, and comprise the complex application logic that you have. And, so, modeling application logic is just understanding all of that, both before, during, and after you actually code. And I think that the way that most developers code nowadays is we just start coding. Okay, we have a vague idea of what we want to do, so we're going to code, and if something is wrong, we're going to change a few Boolean expressions and hope right now it works. And, so, we're trying to argue for just sitting down with either pencil and paper, or in our case with visual tooling, and saying, okay, we're going to carefully plan how we want our application to be. And planning it in a way that allows it to change over time. Because, you know, we all know project managers are going to add features, change use cases, maybe pivot to something. So we have to be ready for that. But we think that doing it in a visual way is the best for the team. Obviously, developers don't think -- well, a lot of developers do think visually, but we feel the visual communication mechanism is something that's universal to everyone on the team.
JASON: And what's interesting, you know, as you're talking through this, I'm thinking back through my career and the things that have caused a lot of pain and a lot of frustration on my teams. And the biggest one is that if I inherit an app, and that app has been around for a year or more, it's inevitably gone from its original design, through a few iterations, we added features, changed things up, had to flip something around, add some security thing. And, typically, it's just really hard to untangle what each of those things does, and there's a lot of, well, we borrowed this code from this file, but it's not technically supposed to do that. So, we're using it over here. And it's really difficult to tell what's going on. You find these giant lists of if statements saying, well, if this status is true, then you need to show this thing. And if this one is true, then you need to actually show a different thing. And building that mental model is painful. It's really, really challenging.
DAVID: Yeah, it's mainly because code is really not the best medium for expressing those thoughts.
JASON: Uh-huh. Yeah, that makes sense. You know, okay, now I'm even thinking a step further. How did I unblock this, I'd go grab everybody who worked on the app. Okay, we have to figure this thing out. Can you talk me through how this works, and we'd end up at a whiteboard, we're drawing little flow charts and diagrams. This thing talks to this thing, goes over here like this. And at the end of it, we've done a very poor job of visually modeling our application logic. And, so, what you're proposing is that rather than waiting a year and then being frustrated and having to pull an all-hands meeting to get everybody to explain their little corner of the app, you're saying just do that from the get go.
DAVID: Exactly. And do it in a way -- so, obviously, we could do it from the get go right now. We could be diligent about writing user stories, writing documentation, and creating these diagrams to explain our app. But, first of all, do you know any company -- I mean do you know any company that actually does that religiously and is actually in sync with, you know, changes to the app? Like that's extremely difficult to do.
JASON: I would say that Netlify is probably the best I've seen at being good at this, and it's still, you know, we build stuff, and then we write some docs about what we built. And the docs are good, but they are surface-level API, not deep internal implementation. And they always drift a little bit, because people have to fix something pretty fast. Yeah, the documentation, if we make diagrams, the diagrams are dead seconds after they are published.
DAVID: Yeah. And that is, like, immediately our selling point. Where anything you create -- one of our team members calls it speculative artifacts. I love that term. These are artifacts that are not very long lived. Once you change a feature or do something different, it's out of date.
JASON: And that's interesting, because it changes the value of those things, right. Doesn't mean they are not valuable, but means you don't get to use them as a source of truth anymore. You use them as an iterative step towards your source of truth. I'm going to draw this diagram, and then I'm going to build the thing. And as soon as I built the thing, the diagram is trash, it was a throw away, it was a planning step. So, are you proposing there's a way to make nonspeculative artifacts about visualizing your app code?
DAVID: Yeah. This has been something that's existed for many years, and it's called -- well, it has two terms. Visual formalisms and executable diagrams, and those go hand in hand. Basically, what we're saying, we can visualize the code in a diagram, so we have a visual output that's always going to be in sync with the code. And these diagrams are actually executable and formalized, which means they are not just like, oh, here's sort of a hand-wavy version of how the app works. More like this is an exact representation of how the app works, and this is always going to be in sync with the code. So, our idealized goal is that you should be able to edit the code and have the diagram updated, so always in sync. And here's magic going the other way around, editing the diagram and have the code updated as a result. Or at least have a very clear picture of where the code needs to be updated to for everything to be in sync. So, we need to basically remove the barrier of creating documentation in diagrams and coding the implementation details and having those be separate. And instead, have those be under the same thing.
JASON: Yeah. Yeah, because as you're talking about this, I'm realizing I can only think of one example that's not what we're talking about today that does this. And it's not even a full implementation of what you're talking about, because it's not two way, but GraphQL is about the only thing I can think of, where when you write the code, it automatically updates the documentation and makes sure that, you know, when people go to look at that graphical explorer, they see exactly what's in the code. It's very difficult to get out of date docs with a GraphQL API, because the documentation and the code are the same thing. And, so, what you're saying is that with this kind of visual representation that you're talking about, we are drawing this diagram, but the diagram is the code, and the code is the diagram. So, no matter which part of it we work on, we're always technically working on the same thing. It's just a different view of the same underlying structure.
DAVID: Yeah, that's exactly it.
JASON: Super cool.
DAVID: Basically GraphQL but for application logic. That's what I love about GraphQL, too. How it automatically generates the schema, documentation, types, everything. That never goes out of date. It's impossible for it to. So, we want to do the same thing for app logic.
JASON: That's -- I mean, this is one of those things as you're setting it up, my brain is going, it's too good to be true. Like, yeah, this is going to be great until somebody has a deadline, and they are going to get lazy, and they are going to cut a corner, and then it's all broken. Is this something that is going to -- I talk a lot about the idea of setting good defaults. You make the right thing the easy thing, and when people cut corners, they do the thing you want them to do. It sounds like you're hinting at maybe this is that, where you're giving people an ability to, you know, the shortcut is the thing that's actually the best for long-term documentation and visibility into what's going on in the code.
DAVID: So, are you talking about how people actually author these diagrams and state machines and statecharts?
JASON: Yeah, and I know we'll look at the specifics how we author them, but the promise that you're making here is, for me, the easiest thing to do would be to draw a little arrow on my diagram and say, okay, everybody go implement that. But what you're saying, I could go put the arrow into the flow chart and it updated the code for me.
DAVID: Yeah, exactly that. And that's northern star of what we want to get to.
JASON: That's pretty incredible. It really does that -- it makes the right thing the easy thing by saying, look, you need to update everything at once, and the way you do that is by updating this one thing that's very visual and human-readable. And that's going to trickle into the whole application logic properly and consistently.
DAVID: Yep.
JASON: That is really, really interesting, and a very cool promise. So, how did you get into this space? Where did you find yourself, you know, from being a pianist, to being this visual application architect?
DAVID: One of my first jobs as a junior developer, we were working on these really gnarly medication prescribing forms that had multiple steps. So, anyone who's made a multi-step form knows immediately what I'm talking about. There's so many things to think about. And these aren't just your typical run of the mill sequential multi-step forms, where you do step one, step two, three, then review, complete. It's more like you could go back a step, do different flows, depending what the user chooses. And even in each step, depending what the user chooses, like which radio button they press, you might show a different field. Probably a lot of people walking right now have heartburn just hearing all of this. Yeah, I wanted some way -- as a junior developer especially, and a lazy junior developer at that, I wanted some way of better representing that. Because we had a huge mess of Boolean logic, and everything was being done in jQuery. I was just curious, researching different things. I discovered, oh, there's a formal term for this called state machine, so I started researching that. Then I found out, oh, there's this thing called statecharts, which is like a state machine, but cooler and with more features, and you can express more complex logic, but not in a way where it can blow up and become completely confusing. So, yes, I sort of took that idea and ran with it, or at least as far as I could in that company, but then they were like, hey, you're technically -- this is technically our software, and since you're no longer with this company, your open-source project is not allowed to be open sourced. They sort of took that down. I had to start from scratch at the next company, and those ideas evolved into me wanting to experiment with state machines and statecharts as a generalized library. And, so, that's how I made X dates, and then more and more people started using it. Then here we are.
JASON: Yeah, it's wild. I mean, you've kind of cornered the market on state machines. I think if anybody says state machines three times, your name will get invoked almost immediately.
DAVID: Oh, it only takes one time.
JASON: The alert goes off.
DAVID: Exactly.
JASON: It's been really fascinating to watch how this is kind of matured. I know Stately is not the first visual state machine creator that you made, right? Or I guess you had a visualizer, not a visual creator.
DAVID: Right. Sorry, right. And, so, even in our previous shows, and I'm really excited to show you the new visualizer, too. Yeah, we had previous iterations of the visualizer. So, those were useful for you're creating a state machine and you want to actually visualize it and play around with it, maybe show designers or other project managers, stakeholders, et cetera. But those tools eventually evolved into actual inspectors. So, if you're using state machines in your application, you want to be able to visualize the state as someone is using the application. Obviously, in dev mode you don't want to use this in prod. But, yeah, so, now we're just going a level beyond that, and, you know, just giving you the ability to create these state machines visually.
JASON: It's super cool. Okay, so, the promise of state machines is pretty stark here. We can see how the app looks, we can put that up in a way that's discussible. Not just with engineers, but with the whole company. If you click this button, this thing will happen. Does everybody agree that's the right way for this to go? And, so, I guess is there -- what are the tradeoffs in this? When are you not going to use state machines?
DAVID: That's a very good question. So, I like to say that -- two things. First, if you have a simple enough app, like basically any cred app, even though I would argue some need state machines, too. But an app that's really simple and doesn't need a concept of different modes or anything like that, then you don't need a state machine. But what I will also say is that apps that start simple seldom stay simple. And that's because, as you add more features and use cases, the app grows in complexity. And something that I hear pretty often is eventually developers get to the point of I wish I used a state machine for certain parts. You can even look at your own side projects or apps you're working on and you're going to see a mess of Boolean conditional logic, where it's really hard to discern what is the intention behind this code. I will say that one of the biggest -- I don't want to call it a drawback, but things to consider with state machines and statecharts is the learning curve. I do say your entire team has to be on board. Thankfully, it's not that hard to learn just the general concept of state machines. But if your entire team isn't on board with it, then you're going to end up creating something where someone else is going to say this looks really over-engineered. When in reality it's the opposite. If you're not using any sort of modeling, whether it's state machines or just anything else, then it's really under-engineering. So, yeah, just make sure everyone is on board.
JASON: And you've put this in a way that I've heard in the past, where, you know, not writing a state machine, as you're saying, is under-engineering, but it's also when I deploy something, there are a whole bunch of unknown states. And I'm just trusting that we want get into any of those. And trusting all the people who work on the application later to also know what those unknown states are, and how to handle them. And I'm trying to remember the exact phrasing you used, but it was around this idea of, like, make impossible states impossible, is I think how you said it.
DAVID: Yep.
JASON: You know, with Boolean logic, it's really easy to mess this up, where you have an if error and an if loading and an if loaded. And if you combine those incorrectly, you can accidentally get into a state, where you are both loading and loaded. Or where you have an error and you have data, because you didn't do your Boolean checks right, or you forgot to return or something like that.
DAVID: Yeah. And, so, what's funny, developers, sometimes they hear that and they are like, you know what, I'm a Boolean expert. I know how to wrangle my Boolean so they don't get in those impossible states. But here's the reality. I encounter apps like this every day, where they do get into impossible states. And users don't report it. They either, I don't know, hard-refresh the app, best-case scenario. Or they leave and use a different app because they are like, okay, this one is broken, I'm not going to use it. So, it's not something that you're aware of until it's too late, really. So, that's another common, I want to say -- I don't want to say criticism, but thing that when people start using state machines, they feel like, wow, this is really complex. But it's revealing complexity. It's not doing, like, you know, the thing where abstractions would hide complexity. It puts it right in front of you, so you can say, oh, I forgot to handle that case, or this transition, or, wow, I didn't realize these states were impossible, you know.
JASON: That's a good idea. Because what I like about that, in a completely non-programming context, something that I talk about a lot is setting good expectations. Because a lot of what we do is implicit, you know, if we go to dinner, it might be implicit that we're going to split the bill. But if we misunderstand that, then one of us is expecting to split, the other is expecting not to pay, and now you have discomfort. If you set the expectations up front, doesn't change the outcome of the meal or the information, just exposes it before something's happened that is now uncomfortable. And the same is true with our app logic. If we look through and actually map out what our app is allowed to do and not allowed to do, and what states it can get into, that can feel like a lot of code, but those things were all there. All of that possibility was there. We just didn't write it down.
DAVID: Yeah. And now you're better equipped to handle it. So, it's not just for the developers to understand, oh, okay, now I see all my, you know, states and, you know, up close and personal with me. It now becomes something that you can communicate with the rest of your team. And that's like the important thing that I also want to stress, is that this sort of escapes the developer bubble and allows you to tell your designers, hey, this is all the visual states that we didn't consider, or just confirm use cases with your project manager and have them also be able to understand, oh, okay, here's all the possible ways that the user can use this app, and we could easily do things like list features, list edge cases, change features. You know, in confidence.
JASON: And that's actually really, really interesting, because we have, on the Netlify team, we've got some of our UX designers, and they are effectively human state machine checkers. They have to go through every flow in the app and think about, well, what if somebody clicks this button and immediately hits the back button, right, what state does that get us into, or something like that. And they have to do all of this work, which is effectively manual QA. Which, that is -- it works most of the time. We've got great designers, but it does rely on somebody paying attention. And we all know everybody at some point is going to miss something, or cut corners, or whatever. So, having that explicitness, where we can look at it together and say do we have a screen design for this state in the flow chart? No? Okay, we should design one of those. Right, it's much easier to communicate about it. Gives us a checklist, how does the UX work, what do the buttons need to say. All those things, we can follow it through. Not doing the thing that I'm super guilty of, of having a homepage and a log in, and then I show the dashboard. Then they are like what about you click the log-in button, then log in, what if you don't have an account, you have to sign up, what happens if you were on a different page, then click log in, do you get redirected to that page? All that stuff. Eventually, we'll talk about it. It would be better to map it up front so everybody knew design-wise. Helps with scoping, heading deadlines, all those things. I'm seeing this as an estimation tool, as well.
DAVID: Yeah, yeah. It could definitely be that, too. I like to think of it as part of all parts of the development cycle, both planning, during actual development, so you understand what you need to implement. Even things like producing those artifacts, documentation and diagrams, but also texting. I could talk about for hours just on the testing part, but you could essentially generate tests from this, or at least know exactly what's to test. Because to get into mathematical terms, your app becomes a directed graph. So, all of these tests are testing each path in the directed graph. And all of these features are just like notes and edges of this graph.
JASON: Fascinating. This is really cool stuff. Okay, we have one question from the chat that I wanted to ask, which is does something like X state replace state management in your app? Would this be used in addition to redux or in place of redux?
DAVID: Oh, this is a really good question, and something I really ought to write a blog post about. It follows up from the initial question of, like, when do you use state machines. So, I want to differentiate that X state is a state orchestration library, whereas other libraries, such as Redux, Mob X, Recoil, those are state management libraries. So, the biggest difference, and they do overlap, but the biggest different is state libraries offer you a box or set of boxes, where you could hold your state and do whatever you want with the state. Unopinionated. Just give me your state, I'm going to give you a really convenient way to change it whenever you want, which that's a bit scary. But also to retrieve it wherever you want. X state takes a different approach. I'm more an orchestrator. Here's all the finite states, here's how the states can go between each other. So, you know, it dictates what events are possible in each state, how the state can change, what can happen in the future, which is something that's impossible to do with state management tools, just because you don't have that information. It's just a box. Who knows what's going to happen when you mutate this part of the state, or send this event over. So, as a state orchestration library, you definitely can use it stand alone to also encompass your state management, but you don't have to. So, I think one of the most important examples of this is forms. There's plenty of good form libraries. So, you could definitely use XState has something to orchestrate, okay, we're in the shipping information state, the checkout information, cart state, I'm describing a shopping cart. Then we can leave it to form libraries to communicate back with the orchestrator and say here's my data, what do I do next.
JASON: Got it, it's like an it depends. That's great. I can probably pester you with a lot of abstract questions, but I think it's going to be more fun to see this in action. So, let's switch over into our paired programming view here, camera two. And what we're going to do now is just do a quick shout-out to our captioning. We've got Ashly with us today from White Coat Captioning doing all the captions on the home page. You can find those on learnwithJason.dev. And that is made possible through the support of our sponsors, Netlify, Nx, and Backlight. All kicking in to make this show more accessible and to help me run all the other great things that we're able to do here. Thank you very much for that. All these links are clickable, so make sure you go and check those out. We are talking to David today. So, we are going to go over to DavidKPiano on Twitter. Make sure you go and give him a follow. And then we're talking about Stately -- is it .ai, is that right?
DAVID: Yes, Stately.ai.
JASON: This is the company that you're starting now. Should I have anything else pulled up, or is this a good starting point?
DAVID: This is definitely a good starting point, this is a bare bones landing page I made in half an hour. It is deployed on Netlify, so shout-out to them. Yeah, it's sort of a teaser on what we're working on. And we are coming out with a new landing page soon, but if you want, you can jump into Stately.ai/vis, and I want to show you the new visualizer that we have.
JASON: Here we go.
DAVID: Click an example machine. See an example. That's going to give you a machine. Now if you click visualize now, you're going to see this visualized.
JASON: Cool.
DAVID: This is your basic fetch machine. You could immediately start playing around with it, click fetch, resolve, retry, reject. Whatever you want. And this actually has logic, where I think it's going to do something if you reject too many times, or not. Long story short, takes your XState code and allows you to visualize it.
JASON: This is very cool. It's so nice to see how straightforward this is. And we immediately know what's going on. We're going to get something, and when it's loading, it either works or it doesn't. And we can retry it if we want. Looks like with the retries, yeah, you get the number of retries, and it looks like the logic to fail on a number of retries isn't here. Okay, here's the visualization, here's the code. This is all of the code. So, 39 lines of code total. Let me make this a little bigger, so we can see all of them. David, I don't know if I told you this, but if you look at the screenshot in the call you're in, there's going to be a kabob, and you can open that in a new tab, shows full screen. Little easier to see. We're creating a machine, ID, name, initial, that's the initial state, here's our list of states. Here's our idle state, loading state, success, and failure. We can see idle, loading, success, and failure. And then each of these, here's fetch, resolve, and reject. Here's these actions here. And then we've got to retry. So, I'm not -- I'm passingly familiar with state machines, I've used them in a couple projects. It's not a core competency for me. You can reason your way of what's going on here, visually very easy, and in the code it's pretty straightforward. So, this is really cool. I am a fan here of how this is working.
DAVID: Awesome.
JASON: Getting some problems on the visualizer in the chat.
DAVID: So, yeah. So, for the past, I don't know how long I've been working on XState, six years or so. It's definitely been a code-first tool, where you write the code to make the state machine, and then you visualize it. But something we recently released in beta is actually the Stately editor. So, if you go to Stately.ai/editor, you're going to be taken to a completely different experience right now. I mean, it looks just like the visualizer, but here's the difference. You can visually create these state machines now. So, inside machine name, if you double click somewhere, that's going to create a new state. Inside where all the other states are.
JASON: Okay.
DAVID: Then click one of the white boxes and drag an arrow from one to another. Start typing that event, you can drag things around. Then if you press simulate, then you could actually walk through the states just like you can with the editor, you know, just go from first state to second state to third state. There's no transition back to third state. You basically made a broken traffic light.
JASON: To fix that, I want to be able to go around. Boom, boom, boom. We're able to cycle through our app.
DAVID: Okay, you just made a state machine visually in a few seconds. This right now is a visual artifact. If you go to export, then you could -- let's copy that -- oh, you do have to sign in via GitHub. Yeah, one more user!
JASON: All right, I'm going to export.
DAVID: Yeah, it's going to copy to the clipboard. Go back to the visualizer. Yeah, type create machine and copy that entire JSON thing into there. Now if you press either command-enter, or click the visualize button, hopefully, it's going to be the same. Yeah, there we go. So, this sort of proves that this machine that you created visually can be used directly in code. You could just export that and use it directly.
JASON: This is really cool. Like it's so nice that we didn't have to -- I didn't have to set up the boilerplate of naming it and stuff. Now if I go back to this, let's go back to the editor, right, we can create one of these. And I can give it a name. You said you had an idea for what we could build. Did you want to look at something else before we start building one?
DAVID: Yeah. My idea was to build the beginning of Wordle.
JASON: All right, let's do it.
DAVID: I don't know if we have time to do all of Wordle, but at least we could do the basic mechanism. This is actually a great example, and I know there were people talking about it in the chat, but games use state machines all the time, and Wordle is no exception. You've played Wordle, the entire world has played Wordle. There's certain states in the game. There's a state you're guessing, you have five letters you need to type in, and those are all individual events, as well. You should only be able to press one letter at a time, or back space is going to remove the most recent letter. When you press enter or whatever, it's going to do this sort of revealing animation. I know we did animations in the past episode. We have the revealing state, where you can't type a letter. Then either you've won, you guessed the word, you lost if you have six tries already, or you go back to the guessing state. So, it's definitely a state machine. And I found it to be a pretty cool example of one that we can make.
JASON: Yeah. Okay, let's do it. The initial state convention is idle, right?
DAVID: When I jump into a Wordle game, as long as you're not in the here's how to play the game screen, you're in the guessing state. I would call it guessing.
JASON: I'm sure it doesn't matter, but do people capitalize, not capitalize, all caps?
DAVID: It's funny, because with this you can really do whatever you want. Personally, I like to keep things lower case and camelcase, because it's been ingrained in my head as a programmer to do that. One of the engineers on our team, he loves doing sentence case. So he makes this English prose, looks nice, reads really nice, but it's been a bit interesting putting that in code, just because it feels like two different worlds. I like doing the lowercase, camelcase thing.
JASON: Let's do it. Lowercase. First event is going to be --
DAVID: Submit a guess, we could type one. Call it submit. Yeah. Then we're going to be in revealing states. They sort of animate, flip to the different colors, either green if it's correct, yellow, and black. So and a half that revealing state is done, that's going to happen after some time. What you can actually do is -- yeah, already event selected, choose a delayed event. It's going to say after. So, after. We'll do it after two seconds. You could put 2,000 for that delay.
JASON: Okay.
DAVID: Then you could change the target. Do in the right. Drag that little circle back to guessing. Yeah. That's going to be our simple state machine for now. Eventually we're going to add more conditions on to it. I think it's a pretty good starting point. Another thing you can do, in the guessing state, I don't know if it's actually going to simulate the timer in here. We haven't implemented that just yet. But in the guessing state, you could also have a key, or have a backspace. There's three events that could happen in the guessing state. You could make an event to itself, just drag one of those boxes and come right back to the same state. I'm doing this wrong. Go here. Wait, where do I go? Let me get this one out of here. Okay. I'm going to do this. Back to itself.
DAVID: There you go. Now just type "key." That's when we press a key. Then there's another event that could happen, which is backspace or delete, whatever you want to call it.
JASON: We've got our backspace, key entry, and delete, both of which will go into our guessing.
DAVID: The tricky part about this logic is that our after 2,000 milliseconds thing, that's the time where after it's done doing its revealing animation, we have to determine do we go back to the guessing state, or do we go to a win or lose state. Let's create two more states, win and lose. Yeah, one more advanced feature, and, of course, because this is in beta, it's something we're still working on. If you click the after 2,000 milliseconds, we could add conditions. If you click plus, just right above that event, then we have if. And so I would say that if -- and you could type just plain English over here. If guess is correct, then we're going to go to the win state. Yeah. And, so, I guess if we move things around, or you could do that. Awesome. So, now let's add another one, because we also need to see if -- what would we call it, if guesses are exhausted? Or is sixth guess, that works, too.
JASON: This is a little that's not future proof. Maybe we allow seven guesses in the future.
DAVID: Exactly.
JASON: If out of guesses.
DAVID: There we go, yeah.
JASON: That way we don't have to edit that later. That would go to -- I'm going to click this, and I drag it.
DAVID: So, yeah, there you go. And one more. Otherwise we're going to go back to guessing. So, yeah, you can actually delete that, because it's just an else.
JASON: Oh, I got it, else. And that's going to take us back to guessing.
DAVID: Uh-huh. Yeah, so --
JASON: Put this here, and this one here. So that we can see them a little more easily. I guess we could even -- look, we can make our flow chart nice and clean.
DAVID: I'm actually working on making these lines a lot prettier, too. There's a whole lot we're going to be adding to the editor. If you want to color the win state green and the lose state red, you should be able to do that. If you also want to drag and drop images for prototyping or mockups into any of these states, then you should also be able to do that. These are just things coming to the future. So, now you could take this to, I don't know, your designer, your project manager, and go ahead and click simulate and say, hey, I have this great low-seven figure million dollar idea for a very popular word game. And I want to show you how it's going to work. So, you say the user submits a guess, it's revealing, and, so -- yeah, I guess after transitions aren't working over here. We could, you know, implement this in code or whatever, something that needs to be fixed. You could show this diagram and say, hey, here's how our app is going to work, our little Wordle machine. And speaking about having this as a documentation tool. If you go back to edit, we could click any one of those states or events. Yeah, and you could put a description. In the future, this is going to be full markdown, so you could put images, text formatting, yeah. So, you could clarify what each of these different states means.
JASON: Oh, this is dope. We can tell what's going on in a way that's -- yeah, delivering on the promise that this is a communication tool. Being able to go in here and show people what's going on. I'm already thinking -- ear muffs, David, even if I didn't use the state machine, you could use this as a way to plan your apps and give to your team for development. Still super useful.
DAVID: I will definitely admit and agree with you on that. We don't want this to be a tool, hey, this is only useful if you're excusing XState. We want this to be a tool where it doesn't matter what state library you're using, but it's useful in some form. Either as a documentation tool, a planning tool, visual tool simulation, whatever. It shouldn't matter. That's why we want to definitely expand this for use cases of just any framework, any state management library, and in the future even other languages, as well. I just want to make that clear, this is not an XState-only tool.
JASON: Yeah. So, kind of in that vein, there's a question in the chat. I'm not going to try to pronounce your user name, I'm sorry. But what is the best way to integrate this at the back end level, so you can take advantage of state machines without relying on the client side.
DAVID: That's a huge conversation. Actually, we had someone recently join the team working on this exact same problem, because one emergent use case I've seen come up is people wanting to use XState for all sorts of things, whether it's automation, CICV, even back-end workflows. We think statecharts are a way of expressing complex workflows in the back end. There's a lot of considerations there. There's so much. Not only do you have to keep states, but you also have to execute actions and, you know, timers. I know Netlify recently came out with their ChronJob scheduler. That's an important consideration in workflows, too. That's something we're actively working on. And in the future, we want to make this editor something where you could drag and drop different services. So, one of the states could be send an email, or check the weather. And then you have a nice pretty deploy button where you say, hey, I want this to be an end point where I can send events to it, and it's going to do the things in my workflow. All that is coming soon and we're working on it very diligently.
JASON: I see MPocock asking in the chat if I want snap-to. Yes, I definitely do. I'm sure he watched me trying to get all these lined up. No, this is great. I am absolutely thrilled with how quickly we were able to model out. I know that there's stuff missing, we don't have the six key presses before you submit kind of thing, but this is really fascinating to see how quickly we were able to get a thought out of your head visually on screen in a way that is, I would say, borderline universally comprehensible. This is -- it would be hard for anybody who is, you know, at least somewhat capable of logical thought and reading English to look at this and not know what's going on. I think that's so powerful.
DAVID: Yeah, and it's mainly because we see code as something where in order to make code understandable, first of all, all the developers have to have had a hand in writing code. Usually the only person that understands the code fully is the developer who wrote it. And sometimes that's not even the case. Two weeks later they go on vacation, look at their code, I have no idea what this is. Did I write this? Oh, I checked, I did write this. And it becomes a problem. You could put --
JASON: Code monsters did this to us.
DAVID: Exactly.
JASON: Oh, it was me.
DAVID: Yeah. So, we really wanted a meeting where it's first and foremost visual. Just this idea of boxes and arrows. You could talk to a child and say, hey, you follow the arrow. When you see an event, follow an arrow, which box are you on now? These are things really simple to teach. So, by describing your application like this, too, you could also simulate it, you could hook it up to mockups, maybe Figma, things like that. Yeah.
JASON: Yeah. I mean, what I also think is interesting about this is you mentioned Figma. Figma has this prototyping tool, right, and so something interesting that could be done here is you could build a direct integration, where, you know, you've got your state machine here, and that creates Figma prototypes that are like, yeah, design here, this is the box that you click to go to this to submit the form, this is the box you click to do this thing. And you can kind of see how that would work and how quick that designer flow would be where, you know, basically the whole team can define the logic. Then the designers don't have to spend time wiring up prototypes. They just have to fill in the blanks in the prototype.
DAVID: Exactly. Even the other way around, yeah. I've worked with designers, where they were the ones who created these user flows. They were like, hey, we made these really pretty boxes and arrows in Figma, which aren't functional, but they look extremely clear. You need to go here, and when the user logs in, now you're in the log-in page or the welcome page, whatever. And we're thinking of making this a tool for even designers to go in, make their user flows in it, and hand it over to the developer to either refine the logic, or like you said, fill in the blanks. Either designers can fill in the blanks with designs, or developers can fill in the blanks with implementation details, or both. So, this becomes a common language for the entire team.
JASON: Yeah. I mean, you know, you'd think that I would use state machines in every project, because every time we talk, I'm like, man, this is definitely the way I should be building everything.
DAVID: Right.
JASON: Because it really does -- the -- it's there. Everything that you want to be there in the way that you cross functionally communicate, in the way that you keep things up to date. Because, you know, I want to try something. I'm going to go rogue here. I'm going to copy this. I'm going to go over to -- oh, I have a question. Is there any way that I'm going to be able to import JSON over here if I were to try to edit this machine and bring it back?
DAVID: In the future, you will be able to. But right now -- I mean, yeah. It's fine. We're working on a VSCode extension, Matt in the chat is working on this a lot. You can do two-way editing, but we don't have it synced up where it actually saves it in the cloud just yet. That's definitely on our priority list to have.
JASON: Question in the chat about adding a second machine. So, if you wanted to have one machine and then that talk to another machine, is that -- how does that pattern work?
DAVID: I mean, in XState that's pretty straightforward. You either invoke or spawn. But over here we don't have that feature quite yet. Again, one of our priorities is getting a full feature within the editor. We still have a long laundry list of things to do to support everything. It will be the same idea of you click a state, click invoke, and then you pick from a drop-down of existing machines you have. Then you just talk to it that way. Eventually the simulator will be able to show, hey, this machine is sending an event to that machine, or this machine received an event from another machine.
JASON: Got ya. Okay. It's pretty early days for Stately. How far are you into this journey?
DAVID: We have -- in terms of a company, we have been around for a little over half a year. So, I honestly really love our team, because it's amazing what we've been able to establish in just half a year of being alive. It was just May of last year that I quit Microsoft and started doing this full time. It's definitely been less than a year that we were able to do all of this. But we have a lot of future plans. And at least for the Stately editor, it's definitely still early days. So, I want to thank everyone who has been kicking the tires and playing around with this. First of all, keep it up, keep making cool stuff. Secondly, we'll be adding a lot of cool new features to this and working on bigger ideas that also incorporate the visualizer and the editor and all these other things that we're building, such as workflows, model-based testing, simulation, all of these ideas that become possible with state machines and statecharts.
JASON: It's, yeah, this is an impressive amount of, you know, what, six, seven months. That is a lot of progress. I can see there's no shortage of ideas. Is there somewhere that you want people to go, as they are having these ideas, so that they are collected somewhere?
DAVID: Yeah. We have a Discord. It's discord.gg/XState. And, yeah, we have a very vibrant community there. There are a lot of -- one thing that I love about this community is that there's just no shortage of ideas. It's not just people asking for help, but also people saying, hey, it would be cool if we could do this, or I see possibilities for, you know, doing this and that, and using state machines for home automation, or chatbots, or things like that. There's always exciting conversations. And pretty much never-ending arguments either. This is based on some really, really old stuff. You're not going to argue with a paper from the 1970s or 1980s. That stuff is already written in stone, and we're just building on top of that.
JASON: Nice. Yeah, I mean, it is good to see that, you know, we're not reinventing wheels with state machines. We're just implementing the spec in different languages. And, you know, seeing a JavaScript implementation of state machines in XState, or somebody was requesting Rust. You know, there's just a lot of ways that -- ultimately, the logic that JSON object that describes how things communicate, that's portable. If you build a state machine interpreter in Rust, the JSON would look exactly the same.
DAVID: Exactly.
JASON: Assuming the language you're using has a JSON representation of things. Whatever, very similar, I should say, no matter where you are. It's going to look familiar. And that is something that I think is really interesting, where it's not, well, we're going to build this brand-new thing, and then we have to convince everybody to use the brand-new thing, and after we convince people to use it, we have to port it to all these different places. This is more saying, well, this thing exists. We're just trying to explain why it's going to make your life easier. We don't have to reinvent wheels. The work is done. We have to get people onboard.
DAVID: Exactly. That's exactly it.
JASON: All right. So, we have about a half hour left on the clock. What else should we show off about the way that all of this stuff works?
DAVID: Yeah, so, I actually -- it was late last night, that's why I thought of the Wordle game. How quickly could I make Wordle, or at least a very ugly version of it, using XState, using the same -- or a similar machine to what we created. I pasted a link to you in the video program that we're using.
JASON: Great. Let me grab this.
DAVID: Now, fair warning. I do love CSS, but, again, it was a challenge to me to make this in under half an hour. So, styling is a bit lacking. So, you could see that we have basically the same -- actually, the exact same structure of state machine. I don't know why I called it toggle machine. I was using the XState template, which by the way, if you go to GitHub.com/XState, you could see anything you want to use XState in, most anything, React, Use, Felt, JavaScript, TypeScript, yeah. This XState page is another one of those, I created this in ten minutes, because I needed something there. Sorry, if you go to the ReadMe. Yeah. So, just going back. If you scroll down, beyond packages, just to templates. These are all code sandbox templates, where if you want to get up and running quickly with XState, click one of those and start playing around with it. So, this one is the JavaScript React template, where, yeah, we were taking our Wordle machine, and I made a very simple unstyled version of it. So, if you scroll down to the state machine, you're going to see that things are very familiar. We have our three events, which is the key, the backspace, the submit. And then we have the other states that we created. So, we have the revealing state, which if you scroll down. Yep, we have our three conditions over there, exactly what we did. And we have two states at the end. They don't really do much of anything. Wordle says, okay, you won, here's your stats. That's something you could definitely add on later to this. Yeah, that's our machine. We just put the guesses in states, did some things to show it. If you try not to cheat and look at the answer, but, yeah, go ahead and try playing this.
JASON: All right. Let's see.
DAVID: You actually can't click the letters. That's something that I forgot to do.
JASON: Okay, I have to type. You're all about to see my actual strategy here.
DAVID: Again, styling is terrible, and I'm sorry about that.
JASON: It's all good. Okay, so, let's say, I and R in the wrong places. Let's go with -- what's a good word?
DAVID: This is exciting.
JASON: Right, okay. R, I still in the wrong place. Okay. Let's -- I feel like the chat probably cheated. Let's go with -- okay, what am I going to do? We're going to get --
DAVID: Interesting to see how other people play Wordle. I'm actually a very infrequent player.
JASON: Grift. Oh! Nicely done. Well played. This is super fun. I love -- okay, so, let's look, all things considered, we built this, or you built this. I don't know why I'm using collective pronouns here. You built this in 214 lines of code. Because this is a single file, right?
DAVID: Yeah, yeah, one file.
JASON: 214 lines of code we've got Wordle implemented. I want to see the application logic here. So, we have letter status. This is correct or almost unplayed. Okay, good. With this, is this in the -- that's just checking the letter status here. So, we use our machine, get our state, ability to send an action. And then we --
DAVID: Don't worry about the active stuff, yeah. That's from the old example.
JASON: Guessing, guesses. Let's look at the code here. Got the template, got the state. Current state right now is we won. Then we take our guesses, and we just map through if it is correct it's green, almost orange, nope it's gray. Then good. Then we go through the full -- let's see, got our flex here. This is the keyboard layout. All the keys.
DAVID: That was fun to type. You just take one finger and go like this on the keyboard. There you go.
JASON: I love it, I love it. Then we go into the bottom of the keyboard, and when you submit, you submit. What's really fascinating about this, this mostly just looks like markup, but what's cool is that in each of these we just get to pass in the state to figure out what the letters are doing. So, looking up at this letter status, we're able to say, you know, does the guess exist, all that stuff. And each of these is able to happen, because we're in -- this is our whole logic.
DAVID: Yeah, yeah, exactly. Besides letter status stuff, all of our application logic is basically inside what I erroneously called the toggle machine, but it is like a Wordle machine. So, you could essentially, if you're brave enough, I don't know if we have time today, but you could take this machine, put it in view, and basically have the exact same Wordle game without having to reimplement everything except the review object. This is sort of like Docker for your app logic. We put it in a nice container, and you just deploy it anywhere.
JASON: Yeah, this is really -- I'm kind of blown away by how little code is required to make the full game, you know, it's so cool to see how -- you know, the big complaint you hear about state machines is state machines are a lot of boilerplate, there's a lot going on here. I'm trying to think about how I would write this without a state machine, and I have a hunch there would probably be a little more code than this.
DAVID: Probably. That's because you would probably opt to use Boolean values. Did user guess, revealing, playing animation. So then you're mixing view concerns with logic concerns. But, yeah, you could also implement this as a big reducer, but here's the problem with that. If you do this in a reducer and use Redux or something like that, you also need a way of just specifying side effects, and it might not be apparent here, but we have the side effect of after two seconds, we're going from the revealing state to another state. So, you might have to write another use effect to express, okay, after 2,000 milliseconds, we're going to transition state, but now that logic does not live with your core logic, even though it technically is still core game logic. Going back to an original question, XState, state management libraries tend to keep things like state only, but as a state orchestration library, we have the additional responsibility of dealing with side effects, and timers, and things like that. Those are side effects.
JASON: Yeah. Okay, so, question from Sean Grove, is it still easy to extract state machines from the toggle machine code and visualize edit it later? Assuming a developer changed and you want to rebuild it on every CI or PR?
DAVID: So, you want to visualize it, or you want to -- sorry.
JASON: I think the question is around pulling out the edited application code to build a visualization on every PR. And the reason I think that is because Sean is on the Netlify team and is working on Netlify graph. I can hear the gears in his head turning right now.
DAVID: If Matt is in the chat, he could speak to that more. He made a GitHub bot that whenever you make a state machine, it's going to be like here's the visual representation of that state machine, which is pretty cool. That's something that I would love to work on, you know, further. Just because it brings that extra dimension of understanding code, you know, in pull requests. In terms of -- sorry, go ahead.
JASON: Well, the question I was going to ask, the thing that I can see getting tricky is like with something like this, this does not break the visualizer, this kind of code?
DAVID: No. It doesn't. This is not something -- since, you know, we're just starting from XState, this isn't something where you would go from the editor to this, at least not quite yet. We're working on in-line implementations. But as far as visualizing, lines 8 through 11, if you un-comment those, you're going to see our new inspector, yeah, just do that, reload. And it's going to open a pop-up window. If you have pop-up windows blocked, then you might not see it. This is a good pop-up, not a bad pop-up. Also, there's one more step to do if you're not seeing it -- oh, no, dev tools should be true. If you go ahead and reload it.
JASON: Reload this one?
DAVID: Reload, yeah, code sandbox.
JASON: Okay, I'm going to reload the code sandbox. I think I'm going to have to un-comment. Nope, it's still un-commented. Okay.
DAVID: Interesting. So, what is supposed to happen is you're supposed to get the visual representation of the machine on the left. Maybe exit this window and reload it. I promise you this works a lot more smoothly.
JASON: Might need to permanently allow -- let me allow pop-ups.
DAVID: Yeah, because it's trying to communicate with a separate window. Okay, there we go. If you drag that out. Oops, sorry. I guess I can make that bigger. Then you could zoom in. Yeah. There we go. Okay. So, this is actually visualizing that application logic, and it doesn't matter how you code it. You could have the in-line expressions and everything, but this represents your application logic as the game is playing. So, if you go back to the Wordle game and make a guess, you'll see it go, even just type "corgi" to see you're in the winning state.
JASON: Got to be in here. So, press enter. Okay, it's in the revealing state.
DAVID: Then it goes to the win state.
JASON: So, we just visualized the internal functionality of the app. And if I were to change one of these things, for example, just going to change the name here --
DAVID: Make sure you change it on the state, as well, if you change the initial state.
JASON: Got it, got it. Here we go. This was a bad initial step. But if I change, you know, okay, let's change the --
DAVID: Or add a state.
JASON: Yeah, let's add a state. That seems better.
DAVID: Statistics, whatever, final state of showing, hey, here's your stats.
JASON: Right now we leave it as it is.
DAVID: Yeah.
JASON: So, as we're editing the app, seeing these changes come in, kind of straight up, which is pretty wonderful. Then we can do something like if you go to the one state, we could kind of immediately move, right, which would be on -- let me see if I remember how an XState works.
DAVID: There's an easy way for you to do that, one, we go here, always take that transition. Just say always, then stats. Yeah, it's a lot less awkward than doing the quotation marks.
JASON: This is great. We will always run this. The reason you'd have two transitions, for example, is maybe I want to fire off an event to track the stats, track the win/loss counter or something like that.
DAVID: Exactly, yeah.
JASON: What do you think, chat, how are you feeling about state machines? Who's here going to give this a shot?
DAVID: Yeah, hopefully everyone.
JASON: Hopefully everyone. I did see a lot of people subscribing today. Thank you very much for the subs, I appreciate it. Sean is asking, any plans for visual diffs on state machines for quickly understanding important changes in a PR?
DAVID: Yeah, that's something we're starting to think about as a team, as well. The interesting thing with state machines and directed graphs in general is that a code diff doesn't really do you much good. Because there's this thing called -- what's it called, isometric machines, or it's isomorphic machines, or graphs, where two graphs might have nodes in different places or whatever, or might have different names, but they are essentially the same graph. Essentially the same number of arrows coming in and out of every node. So, what we want to do in the future is just explore ways of like you're saying, visually diffing machines. So, if Jason goes and adds a state, or changes a transition, all I want to see is green for this state was added, or red for this transition was deleted, or maybe orange for this transition was moved from there to here. There's a lot of interesting ideas around that.
JASON: Yeah. I mean, even just showing the two side by side and highlighting the stuff that's not identical is interesting. Yeah, I love the fact that we've been talking about this for under 90 minutes, and multiple people have come up with things that they would want to use this for and it's like one step to make it useful for that, as opposed to what if we invented this, then that changed. All right, we got this map of the thing. I want to see the difference between this one and the last one. Great, okay, one step. We can go figure that out. We want to see the ability to port them back and forth, great. It's very telling, I think, how much utility there is in these state machines. So, I think this is one of those things where the hardest part of something like this, I would guess, is inertia. My inertia says, well, I'll just write if statements. If I overcome that, I'll get all these benefits. Once you've done this a few times, I imagine you never write if statements. You open up a state machine in the beginning of mapping out a project, right?
DAVID: I will say, sometimes I am guilty, oh, this is going to be a simple problem. I could write a state machine, which will not take long, maybe a couple minutes, or I could use set state and that will take a few seconds to do. Then I always regret it later. At least for things that get more complicated. And we've even -- I guess you could call it reverse dog fooding. We've reverse dog fooded this in our own editor, because I was making very sloppy prototype just to get this editor working, I want to say a year ago. Not the current state of the editor, but just how the editor was in the past. And there were parts where I just desperately needed a state machine. And there are still parts of the code base, where we were like, hey, this is a bit buggy, we need a state machine to really smooth these areas out. In fact, and I suppose it's weird to expose our own bugs, but one thing is if you into the editor and drag an event, then the event is selected and you drag it again, it's going to highlight the text instead of actually dragging that event. And, so, the solution to that was, literally, using a state machine. Saying, hey, if we're in the dragging state, we don't want to be highlighting text. These are types of bugs and fixes that are both easy to recognize and fix when you have state machines, because everything becomes an event. Either an event isn't firing, or an event is firing and going to a state that you don't expect, or, you know, neither of the above are happening. So, it's just -- that's going to immediately tell you where you fixed the bug. Yeah, just understanding problems in terms of state machines makes things a lot easier.
JASON: Yeah, that idea of dragging versus editing, I've dealt with that before. I think the way I dealt with it was to just completely ignore it. I was like, well, just don't click on the text when you want to drag this. You add a dragging bar instead of -- you know what I mean? Thinking about how the state you're in makes it way more approachable to deal with that, as opposed to try to juggle two active things. Oh, just deactivate the one that's not in the current state. Perfect. Yeah, you can just see the complexity falling away from implementation. And it comes from thinking up front about how your app is complex.
DAVID: Right. And, at the same time, I don't want to just tell everyone, hey, you must be using XState for all of these complex apps. Something Jason talked about beforehand was being able to use these tools as planning tools and design tools and understanding, okay, here's all the events that could happen in my app, but I prefer to use Redux or some other state management library. And that's totally fine. What I want developers to get at with all of this is everything is an event, a state, a transition, and they all fit together and create this map of your application logic that can be understood by everyone. And it's up to you to implement however you want. XState is the most straightforward, if you are already designing it with state machines in mind. But it's just that idea of modeling states that I feel is so important and worth emphasizing.
JASON: Yeah, it's just so good. Okay. So, is this the right place to give people more resources, or did you want to show anything else off? We've got about --
DAVID: I think this is good for now and I'd love to point people to the resources we have.
JASON: Absolutely. Where should somebody go if they want to go further with XState, Stately, state machines in general?
DAVID: I would say definitely our Discord. That's the number-one place where we're going to be just announcing stuff, and telling you about just features we're adding to the editor and registry and the VSCode extension and all of that. Especially the open source stuff, too. One of our biggest priorities right now is working on XState version 5, which is going to improve a lot of things in version 4, including typing. I promise we're definitely working on that. So, I would say the Discord, our GitHub. You could take a look at everything we've done. The visualizer, by the way, is completely open source. If you want to poke around, go ahead, take that visualizer, it's written in React and next.js. Take it and run with it. Also, the discussions there are really, really fruitful. There's people with lots of use cases and questions and ideas. And we try to answer them as diligently as we can. We also have a YouTube, YouTube.com/Statelyai. That's where we post all of our office hours. And we do it about every week. We're not going to be doing it this week, but, you know, roughly every Friday. And this is where we give you updates on everything we're working on and everything that we're planning on working on, too. So, that's the primary resource for that. And you can also jump into these and ask us questions if you want. I'm trying to think of other resources. The documentation, as well. But those are our main avenues. We also have a Twitter, Twitter.com/Statelyai.
JASON: There you go, everybody keep up on that. David, this was super informative, super stoked. There's a lot of people who are in the chat talking about how excited they are to use state machines now. So, I hope to see a lot of state machines coming out of people. I know I'm going to be revisiting my motivation to get these done, push through that inertia and put this into my planning stack again. Let's go ahead and do one more shout to David here. Go follow on Twitter. And we've also had Ashly with us all day doing live captioning. So, thank you so much, Ashly, for being here. That is made possible through White Coat Captioning. And the sponsors pay for that. So, Netlify, Nx, Backlight, all kicking in to make the show more accessible. And, you know, do other things, like keep the lights on, let me build new stuff, get camera gear, all the things that I need to do to make this show great. So, thank you all very much for that. While you're checking out things on the site, make sure you go and check out the schedule. We've got so much incredible stuff coming up. Next week we're going to have BW back on the show, I'd love to see you there, we need more people into open source. With that, I think we're going to call this one a success. David, any parting words?
DAVID: Also visit our blog, Stately.ai/blog. We're going to post a lot of info there, too. Just another resource for you.
JASON: One more resource.
DAVID: Yeah, this was a lot of fun.
JASON: Yeah, thank you so much for being here. Chat, as always, thank you for hanging out. We will see you all next time.
Learn With Jason is made possible by our sponsors: