Paul Mikulsis: Hi there and welcome to PodRocket. So today we're excited to have Jenn Creighton, and she is a senior software engineer at Netflix and she also hosts her own podcast called single-threaded. So you can go check it out. We can link it in the description. How are you doing Jenn? Welcome. Jenn Creighton: I am slightly sleep-deprived but doing okay. I just got a puppy, so- Paul Mikulsis: Congratulations. That's a good reason to be sleep deprived. That's an exciting reason. Jenn Creighton: It's a pretty good reason. Paul Mikulsis: We're also a little foggy from having COVID for a while ago, so we're all on the same page, but we're really excited to bring this episode to you about async JavaScript because it's nasty and everybody could probably use some tips and some time to talk about the best way to approach some of the problems that you face every single day when you're writing JavaScript. So if there's anything that you want to interject with while we're going on about our particular set of topics, totally throw-in, but I'd love to kick it off with, why is async JavaScript so hard? It's nasty. And is it because it's JavaScript? JavaScript gets a lot of hate, especially nowadays. So what's your take on that? Jenn Creighton: Oh, well, first, let me address JavaScript gets a lot of hate. JavaScript does get a lot of hate, but note how many people use JavaScript as their first language. So I think that does say something about the accessibility of it or how fun it can be to work with in terms of UI and its many applications. I think JavaScript is a fun language. That said, async, async JavaScript, whoa. Okay, some of what makes async JavaScript difficult is, look, async stuff is hard anyway. Our brain doesn't want to work that way. It's not meant to work that way. We don't have a really good idea of nonlinear time as humans and async is just generally nonlinear. So saying like A then B then C makes sense to us, saying A, C, B, C again, B, A again is very confusing. That doesn't make sense to us. Jenn Creighton: But then on the JavaScript side, there are so many different ways to do async JavaScript, because JavaScript has to be backwards compatible because the web is built on it and you can break the web of you break something in JavaScript. We have a history that is weird in JavaScript and some of that has to do with async stuff too. So you're no longer just dealing with what you used to deal with, right? You used to deal with maybe like set timeouts, then promises. Now you have async await, it's a lot. Paul Mikulsis: Yeah, it changes a lot. It changes fast which can be hard to keep track with. Now we get fetch just right in node. That's wild. That's pretty great. Jenn Creighton: Yeah, it's good, but also, it's just also the different specifications for things because you could use fetch in node, it just wasn't supported, it was like you'd add it and the specification for it, I think, wasn't exactly what the fetch specification was and so- Paul Mikulsis: Not to a T. Jenn Creighton: Yeah, so now they've aligned it, but then that's confusing to people who were previously using a different version of fetch, so even that kind of stuff, the compatibility of what the spec says versus what you were actually using. We had the same thing actually with Promises as well. You had Bluebird which had its own specification for Promises and you could do things in Bluebird that you actually couldn't do with Promises. Paul Mikulsis: Interesting. What is an example of one of the things you could do in Bluebird that you couldn't? Because I feel like you can do almost everything. Jenn Creighton: Now, but at the time. Paul Mikulsis: Okay, at the time. Got you. Okay. Jenn Creighton: Yeah, so at the time, right? So again, things change pretty quickly, and so when something isn't available in the language right away or we don't fully have the spec flesh out, sometimes libraries will come up with alternatives. And so one thing you could do in Bluebird that you couldn't easily do was cancel Promises. And even that's gotten a little bit better now, but that was something that you couldn't really do without Bluebird before. Paul Mikulsis: And on the debugging side, has that, in your opinion, really changed a lot? Because from my perspective, the things that I use in the Chrome developer tools have pretty much stayed constant since I feel like I've really gone into web development. Granted, I haven't been doing it for a decade or anything, but do you think that those have really progressed and changed in the way that maybe the use cases of these types of features are in the language? Jenn Creighton: There have been changes, but most, I would say still and I don't consider this an issue, a lot of engineers still do not use the debugger for async JavaScript or at all, like, minor usage. If they're working with something like say React, they're probably going to use the React dev tools, but not the Chrome debugger or the Firefox debugger. Those are still, I think, tools that not everyone reaches for. And so I'm not sure that everyone was as aware of what changes were happening in it over the last like say decade as things got fleshed out. Because Promises for a while in the Chrome debugger tools, for example, didn't have a really good way of monitoring them or seeing them or seeing the call stack and they actually introduced at some point experimental features for Promises in the debugger. It's not at the same rapid pace of development as JavaScript in general though. It's not keeping up with that same explosion. Jenn Creighton: Debugger tools mostly have stayed pretty similar. For the most part, I still use a lot of console.log and I love it, nothing wrong with sim console.log. And then, I started using... I really started using the developer tools when I was working on very heavy asynchronous. I started to figure out that was actually the better way to look at asynchronous code, but over the years, that hasn't changed so much. What's interesting now is that you do have this explosion of developer tools happening with companies that are specifically for developer tooling. So replay.io is one of them. That one is a whole new debugging experience. And then there's some other companies that work specifically now on this thing like how to make debugging better, not just async but just debugging in general. Paul Mikulsis: And you mentioned the async debugger in the Chrome developer tools, that not a lot of people use it. Can we touch on that and talk about it? Why don't you think a lot of people use it and why is it so great? Jenn Creighton: So it's not just for async code. It is just the debugger that will... you can make it stop execution of your code and then inspect things. Paul Mikulsis: With breakpoints, right? Yeah? Jenn Creighton: Yeah, with breakpoints. So yeah. So for anyone who has never used this before, there are a lot of tutorials online that will teach you how to do this, but you can set a breakpoint, and at that breakpoint, when you start running your code, it will pause it and the Chrome developer tools will take over your screen if that's what you wanted it to do. And from then, you get to actually step through your code, line by line if you want. It's a little confusing at first and I think this is why a lot of people don't use it. There are a couple of confusing points about it. One is understanding the difference between stepping over, stepping into, stepping out of, stepping through your code. Actually, you don't just get to go, "Oh, I want to go line by line by line." There is the step-over function which is the most common one that you might press. Jenn Creighton: Actually, if it encounters a function in the line, it will run the function, but it will not go inside of that. So it will just run the function and then you'll go to the next line of code as if the function had just happened. Paul Mikulsis: Like you're reading a sheet of paper, right? Right? Jenn Creighton: Yeah, like you're reading a sheet of paper, like references, like something else. It'll just keep going. But if you wanted to step into that function, then you have to be intentional about the fact that you want to use the step-in function. And so even as I'm talking about this, this seems like overly complex. And for the most part, I feel like the debugger is overly complex for most of the minor things that you might come across, right? You're not going to use it for syntax errors and you're not going to use it sometimes for even runtime errors. You can probably figure those out which is the console.log, but when you're talking about wanting to be able to see how your program actually executes, which is the real value of using it for looking at async code, that's where you're going to want to figure out how the debugger works and actually use it. Jenn Creighton: So that's when you have to also get better about, "Oh, I want to step over this function. No, I want to step in to this one and actually look at it." You also have to understand how the side panel works. When you see like call stack, it will give you actually the call stack on the side, very useful for async debugging when you want to see where you actually are in that process and also you can follow variables and all these other things. But that said, as I'm talking about it, again, it's a pretty complex tool that you have to learn on the side essentially. I guess it's part of your job, you could, but it's something additional to learn is what I mean. Jenn Creighton: And so a lot of people see that, see the complexity of trying to figure out, "I'm stepping over and I'm stepping in. What am I doing here?" and are like, "You know what? console.log doesn't have these problems and I'm out." And I get it totally. I would reevaluate the phrasing code. I absolutely would. Paul Mikulsis: console.log is just really easy. It's instant. You just drop in a line with a bunch of explanation points, you know where it is. Jenn Creighton: And there's other useful console features like console.table or console, dot, D-I-R, dir. There's a whole bunch of like little helpful console things in addition to log. Paul Mikulsis: What does console.dir do? Jenn Creighton: It will actually print out an object for you. You know how currently if you try and do console.log which is an object, sometimes you'll get object, object. Paul Mikulsis: Right. Right. Jenn Creighton: Yeah, you won't have that- Paul Mikulsis: That's a cool trick. Jenn Creighton: It's a fun little trick. Paul Mikulsis: I didn't know that. That's awesome. Jenn Creighton: Or console.table will actually lay it out in a table format for you, make it all nice and pretty. Paul Mikulsis: Don't have to call JSON.stringify and like everything that it print out. So when do you immediately go to the more complex, maybe harder to reach debugging pain versus console.log? Because there are a lot of things that you can do if console.log, you can just drop two or three statements and know where they are. And, has that changed as you've grown in your career, maybe as you've got a more accustomed to things? Jenn Creighton: Yeah, yeah, that changed. Well, first, I went through a period that I think some engineers just go through whether like, "Oh, I shouldn't be using console.log." There's like a weird little shame about it. I think there's no shame in it now, but at the time, I was like, "No, if I want to be a real engineer, I need to use the debugger," and so I learned the debugger. And then as it turned out, it was a lot of lift for a lot of the smaller problems that I wanted to solve. console.log was just quicker. And so I switched my thinking and I started really just relying a lot on console.log as my first line of defense. I would just start doing that. Jenn Creighton: And then over time I would realize that, especially when it came to asynchronous JavaScript that at some point that really didn't help anymore. At some point, I couldn't keep track of everything that was going on with console.log and having to remember the steps in order of how I expected it to work and how it actually did and what was getting logged, when and where. And that's when I started reopening the debugger and being like, "Okay, well, what does it look like if I do this," and it was so much easier to figure out what was going on. Now, I almost always straight go for the debugger when I am in a brand new codebase and I don't know how things connect. I almost always now use the debugger because it allows me to step through the code. It doesn't even have to be asynchronous. Just I need to know what calls what and the order of this. I've actually used the debugger to look inside the React source code and figure out how it worked. Jenn Creighton: I was just curious and realized when I was doing that, the console.log was not serving me very well and opened up the debugger. And I was able to actually follow along with what the order of how React would render things, right? So I got used to that. And then when I work on just really heavy asynchronous operations, I tend to just straight go for the debugger, not even bothering with console.log. I used to work at Apollo on Apollo Client which is heavily async. And so if I was debugging something in that or trying to make a new feature, I was in the debugger. I was not bothering with console.log. There was no point to that. Apollo Client is a complex async project. There was no point. Paul Mikulsis: It's a very cool project. There's a lot of magic things. I remember the first time using it, it felt like the one time I got a ride in a Tesla and they put on the autopilot and all my data just came in. Because usually, you have to do a lot of work to make the graphs update and stuff and it just- Jenn Creighton: Just did at point, right? Paul Mikulsis: It did its thing. Yeah. Jenn Creighton: Yeah, it's magical, but if you looked in the debugger, you would find out what it's doing and you'd be like, "Oh, it's not magic. It's JavaScript all the way down." Paul Mikulsis: Yeah, because in the debugger, you can drill down as far as you want. Everything that's happening in the browser is right there for you to view and understand. And would you say this is a good way maybe to get accustomed to a new code base in general? Is it go run it and just step through it in the debugger? Jenn Creighton: Yeah, yeah. I use that all the time, like I said. Whenever I'm dealing with a new codebase, I'm almost always opening the debugger and going line by line. Also pro tip, if you use the debugger, one of the slightly confusing things about it is that it will call library code for you. So if you have, for instance, a React application and you want to look at something in your application, you'll notice when you set the breakpoint and start stepping through in the debugger that it will eventually start calling React's code. It will actually start calling the library code. Jenn Creighton: You can actually tell it to ignore that. So there is a way, I forget off the top of my head, but you can Google it, where you can find the file that you want it to ignore and tell it to ignore that and you might have to do that like a few times with like different libraries. But that way, you'll skip over the library code and you'll go straight to your code which will make the process so much cleaner when you're trying to use this for figuring out an application that you've never seen before. You can just ignore all those library files and then focus on your application code. Emily: Hey, this is Emily, one of the producers for PodRocket. I'm so glad you're enjoying this episode. You probably hear this from lots of other podcasts, but we really do appreciate our listeners. Without you, there would be no podcast. And because of that, it would really help if you could follow us on Apple Podcasts so we can continue to bring you conversations with great devs like Evan You and Rich Harris. In return, we'll send you some awesome PodRocket stickers. So check out the show notes on this episode and follow the link to claim your stickers as a small thanks for following us on Apple Podcasts. All right, back to the show. Paul Mikulsis: And that brings me into this point that I had a question about, you said sometimes using the debugger, it is a lift or it was too much of a lift for the task I was trying to accomplish. So maybe just to step into the weeds a little bit about async actually debugging the stuff, what is some of that lift of using the debugger and setting it up and stuff like that? Jenn Creighton: Yeah, so one, you may not be working on a project where naturally the debugger is just easy to set up. So if you are working on UI and you are working in Chrome or Firefox, it's pretty easy. But if you're working on node, there's a little bit of setup, a little bit of figuring out how the heck this thing runs on node? I've had to go through that recently where I was like, "How did I do this again? I don't recall," and I have to look up tutorials and get it running. And then once you get it running, it's there. So one, you might be working on a system that just naturally doesn't have the debugger attached to it like node. And even then if you're in the Chrome dev tools, you have to do the thing, like I said, where you have to tell it like, ignore library code. Jenn Creighton: And that's not a very quick process. I recently did a talk on this, and to do my examples, I had to tell it to ignore the library code. And so I'd run my project and hit a library source and be like, "Okay, ignore this one," and I'd run it again and hit another library source. And I think I had to do it three or four times before it finally was ignoring everything I wanted it to ignore, but that's a bit frustrating, having to do that kind of setup. And then some of the other things are like making sure you understand where you're setting the breakpoints and the stepping through and stepping out. Jenn Creighton: So you have to learn the debugger to some extent. It is a very full feature thing. There are a lot of features in the debugger. You probably don't need all of them. You probably just need a small subset of them, but you might have to spend some time figuring out what those are and what is going to be of use to you. And when you're working with the debugger the first few times too, you are just reorienting yourself to how it works and what it does and just figuring out, did I do the breakpoint in the right place? Did I get the right thing that I need over here? It's just a lot more set up than console.log. But once you get it done the first few times, I think it gets a lot easier. Paul Mikulsis: Got you. All those things are just overhead. I guess it changes project to project and what libraries are there. So it's not a one and done I learn it and then it's breeze. There is some investment involved. Jenn Creighton: No, actually, yeah, if you're having to tell it constantly to ignore certain files. Yeah. Paul Mikulsis: So for people trying to get better at debugging async JavaScript, like for example, I had a brother, he's starting to get in JavaScript, wanting to learn how things work. And I was like, "Oh, well, you should go learn really how the event loop works, actually understand what it does." What are some of those types of parallels you can draw to what made you mental models that really help you start to understand async JavaScript and dive into debugging and thinking about it in a creative way? Jenn Creighton: The event loop, I'm glad you mentioned it, it's one of the first things that when someone's learning async JavaScript. There is a talk, and I'm so sorry because I've forgotten his name, it was from ScotlandJS. I want to say it was like 2018, is on the event loop. It is the talk I send everyone when I'm like, "You should learn the event loop." I send them this talk. It is so good. It is so clear. It is perfect for understanding it. It was the one that I watched when I had just started one of my first dev jobs and someone had done set time out zero and I was like, "Why are we setting it to zero?" And they were like, "Watch this video." And I did and I was like, "Ah, the world makes sense again." So I understood the event loop. So that's the first thing you have to do if you want to understand async Java script. Jenn Creighton: And then the next thing that you get to do is something I don't think is very commonly suggested but is one of the main things that I suggest, which is not just doing tutorials that show you how to do everything correctly, but taking those things that you learned how to do the right way and then looking at what it looks like when the things break. Intentionally breaking things is one of the best ways that you can actually learn really well what it does and why. Paul Mikulsis: Well, what's an example of breaking something, like infinite react render loop? Jenn Creighton: Yeah, definitely. Oh, yeah. If you want to understand why the, shoot, I forgot the term for it, but the square brackets, the dependencies are there in use effect. There we go. If you want to understand why those are there, break it. Break it a million times. Don't put them in and see what happens. Put them in. Put them in just a few and see what happens. For async JavaScript, it's going to look stuff like, "What happens if I forget to return a promise? What happens if I want to do a .catch, but I do it before my .then? What will happen to the order of it? If I want to throw an error," errors are a big deal in async JavaScript, "what will happen in this async await? What happens when I forget to await a promise in async await?" all these things. Jenn Creighton: So just go in and break it as much as possible and then have some fun figuring out like where it broke and why. It will be a much better education for you on how these things work than just always being like, "Okay, the tutorial said to do X, so I do X," but you don't really know why, if that makes sense. Paul Mikulsis: Right. You have to be in the line of battle to really get it. I mean get your hands dirty to really get it. Jenn Creighton: Yeah. Paul Mikulsis: Problem solve on the spot. So we have used the debugger. You don't need most the things in the debugger, but it's really useful. You should go use it. We have learned the JavaScript event loop. And is this talk, correct me if I'm wrong, is this the one where the speaker also made a little website that you can go to... Jenn Creighton: Mm-hmm. Paul Mikulsis: ...and visually put things on like the call stack? Jenn Creighton: Yeah, yeah. Paul Mikulsis: The website's really good. I love the interactivity. That made it click for me too. That video is the one? Jenn Creighton: It's the one. It's how we learn the event loop and there is no other option. Paul Mikulsis: And like 2,150 or whatever when the textbooks have moving pages, that video should just be uploaded for the event loop page. Jenn Creighton: It's so good. It's one of the best talks I've ever seen on JavaScript. Paul Mikulsis: So we have the event loop and then we have, "Go break things and observe how they break." And there's a lot of ways to observe it because step one was learn the debugger, right? So you can observe it in the debugger and then everybody knows console.log. That's step zero because we have to index from zero and everybody starts with that and then use console.log. Should we add on more things? Are there more things that you would come to mind or things that... or any aha moments when you were debugging or you got really excited, you're like, "Wait, I'm starting to get how this works," if you can think back to them and be like, "What did I take away from that moment?" Jenn Creighton: I think being kind to yourself when new things come out in JavaScript is nice. So if you're listening to this and you're new Java script, you're probably overwhelmed, it's okay. Don't worry. You're going to get there, but on the inverse, if you've been in the field in a while and things keep getting introduced, sometimes it actually, even though you knew other things that were similar, like, I've worked with Promises for years. When async await came out, I actually struggled with it a bit. I got the general sense of it and I was like, "Cool," but I was struggling with the differences between promises and async await and how to do the things I knew how to do in Promises and async await. Jenn Creighton: And that actually took just some time. Again, I went and I did a lot of like I would convert a Promise-based series of code into async await and see if they work the same. Attentionally, I tried to break them and I did that strategy again. And over time, it finally started to click of like, "Oh, you knew the rules for how this thing worked for a really long time and async await is technically not that. It is that and it is not that at the same time, and that it's just confusing and it will just take time of working with it to get yourself used to it." Paul Mikulsis: That's a good one because it's really easy to be tough on yourself. I know when I'm learning something, it's like I'll watch YouTube videos until you know it's way too late and you need to go to bed. You just got to chill, give yourself a break. Jenn Creighton: Yeah, I would get frustrated with myself. I'd be like, "You know Promises. Why are you struggling with this?" Like, "Well, maybe it's a little different and you're going to need some time." Paul Mikulsis: Yeah, some time. Sleep does wonders. It lets that information compound. Jenn Creighton: Yeah, get sleep. Also, please don't try to learn things when you're stressed out. It just doesn't work. Paul Mikulsis: It doesn't work. You heard it from here. This is it. Jenn Creighton: When you're stressed, you can't learn things. Paul Mikulsis: That comes on the page after the moving video of the great [inaudible]. Jenn Creighton: Go to bed. Paul Mikulsis: Then go to bed. All right, we're getting used to async code and how to do all that. When you're writing it and you're trying to make it good, if there's one thing you want to do when you're writing any code, not just JavaScript, you want to handle your errors properly, don't do catch-all and then pass and then have that error die silently in your code. But for handling errors specifically in async JavaScript, what are some common pitfalls that you've seen people get themselves into? Jenn Creighton: Mostly, it's been that the error does go silent at some point, that the error is caught and then maybe not rethrown. That is a big error, a big issue with async JavaScript. Silent errors are really the bane of my existence. They're really easy to make happen and very hard not to. But if you're dealing with them, make sure that you're catching appropriately, make sure you understand how try-catch works. Make sure you understand the differences between promises. Catching with promises is not the same as catching in async await and rethrowing errors is also not the same between them. And make sure that they're actually erroring out. I think a lot of the times we just test one portion. We're like, "Oh, cool. It throws an error. Great," and then you forget that's being called by a whole bunch of other code that could silence the error somehow. And so you have to be really careful with that. Jenn Creighton: And then lastly, make your errors helpful. You should catch them and probably rethrow them with an actual helpful message than probably what you're getting back. Paul Mikulsis: And by surface them, we're talking about, if, you're developing, you're still getting the wheels turning. Make sure the program crashes and it tells you where it did and it gives you message. And then if you're running and staging a production, you have your stuff running, make sure it logs the error properly, and if it does need a crash, make sure it crashes. And if it doesn't need to crash, make sure it continues properly. Jenn Creighton: Yes, yeah. Because a lot of the times, especially when you are newer to async JavaScript, you don't know much about error handling in general. I think we do maybe a bit of a disservice when we teach async JavaScript, that we don't talk as much about error handling. So you may not realize that in addition to being like, "Yes, this thing works," you sometimes have to break it and make sure that it breaks properly as well." So again, I like to break things if you haven't figure this out, so break your stuff. Make sure that it's breaking appropriately. Paul Mikulsis: And to wrap this up, what is one of the most profound differences between the Promise-based error handling and the async await handling or one of maybe the nastiest differences that you had difficulty wrapping your head around at first? Jenn Creighton: Actually, there's two things that I struggled with with async await and it wasn't always error handling. One is that Promises just don't block. They're just nonblocking. And when I got to async await, I got that when I put await in front of a Promise, it was going to block, but I didn't always think through the consequences of if I wanted to block or not. And that is actually something that you, I think, don't wrap your head around at first because all of the examples for async await are showing you to await the Promise. And so I think you get it in your head that like, "I have to await the promise every time," but you actually don't. It depends on what you want to happen in parallel and what you don't. If you don't await a Promise though and it errors out, sometimes you aren't so good about catching the error. It's better if you await when you're trying to catch an error or you have to do try catch to catch it. Jenn Creighton: The other thing that really has tripped me up about async await and Promises is that I actually sometimes get confused when switching between them and I will use the wrong syntax which is very annoying. Because I forget when I'm working with async await, that once I need to actually call that async function, I need to revert back to Promises syntax. And so sometimes, I'll treat it like a function I can just call and I'll forget that it's doing async-y things and I need to also do something with that like a .then or like also do that in another async and it just becomes a thing that I just have forgotten because you just think, "Oh, it's an async function and it's awaiting and it'll be fine," and you forget completely. "Yeah, it'll be fine." It will not be fine. Paul Mikulsis: So raise your errors and surface them and then... yeah, I guess that's a really abstract thing to wrap your head around about what you particularly can draw a circle around about what you struggle with because it's a whole paradigm shift really. It's two different languages and it's really just marrying the idea of accomplishing the same thing, but with these two whole different paradigms is difficult. And there's a lot that can be bullet pointed about that. Jenn Creighton: Yeah. It's not so simple. I think, when async await came out, there was this immediate push of like, "It's better than Promises, but it's similar. It's the same," and actually they're not. They're not the same because of the blocking nature. And so if you want to do the same things that you were doing in the Promise, you actually have to be really intentional about when you want to be doing those parallel things and then you're often reaching for promises to do ... Like you're using promise.all or promise.allsettled to do things in parallel while also awaiting them and then properly catching your errors in async await. So it's a shift. It absolutely is and it can be awhile to wrap your brain around it. Paul Mikulsis: Yeah, I feel like those types of shifts are the ones you do when you're hopping languages and complete programming languages and you're just reorganizing the way you organize things because of the way it does stuff. Jenn Creighton: But now you're doing it in one language. Paul Mikulsis: In one language, yeah. Jenn Creighton: And this is why JavaScript gets a bad rap. Paul Mikulsis: Yeah. It is. It is- Jenn Creighton: Full circle. Paul Mikulsis: Yeah. All right, podcast is over. Well, actually, we are running up on time, so we're at a good closing point here. Jenn, is there anything that you would want to give as closing words of advice or resources that maybe we can link in the description for people looking to up their skills in this area? Jenn Creighton: Definitely, I know you're already going to probably link to the video for the event loop. Please do. Please watch it if you don't understand what we're talking about when we say the event loop or even if you think you knew. Check it out. It's a really good talk. The other thing that I think is really useful if you are familiar with JavaScript, but you just want to learn async JavaScript a little bit better, Execute Program is one of my favorite resources. They have some courses that walk you through different examples of things. And I love them in particular because they do show you what it looks like when things break, which has been phenomenal, but also Execute Program is built on the idea of how you learn things is by repetition and so it'll give you exercises that you have to complete before going on to the other mini-lessons. Jenn Creighton: And so I just think it's a really helpful thing. It's been really good for me. Like we talked about, you're going to get the best sense of things when you're actually practicing it, when you're in the weeds, when you're working with things and I think Execute Program does that well. Paul Mikulsis: Awesome. And are you on Twitter or anything? Jenn Creighton: I am on the Twitters. My handle is gurlcode, girl with a U. Paul Mikulsis: Great. Well, thank you for joining us, Jenn. Thank you for your time. I'm sure that this podcast is going to find its way to some people that are going to find all the great advice you had very useful. Jenn Creighton: Hope so. Paul Mikulsis: Yeah. I hope so. That is the hope, but yeah, thanks for coming on. Jenn Creighton: Thanks for having me. Emily: Thanks for listening to PodRocket. You can find us @PodRocketpod on Twitter and don't forget to subscribe, rate and review on Apple Podcasts. Thanks.