Debugowanie aplikacji React - rób to jak starszy programista (film, 21m)
W najnowszym filmie na kanale Web Dev Simplified, Kyle dzieli się cennymi wskazówkami dotyczącymi debugowania w React oraz Next.js. Wprowadza widzów do narzędzi, które mogą znacznie ułatwić proces znajdowania błędów, zapewniając wyczerpujący przegląd, który może pomóc w szybszym rozwiązywaniu problemów z kodem. Video jest podzielone na kilka sekcji, które obejmują ogólne wskazówki dotyczące debugowania w React, zasady debugowania w Next.js oraz szczegółowe omówienie narzędzi dewelopera React. Kluczowym punktem w filmie jest instalacja narzędzi dewelopera React, które, jak Kyle zauważa, są łatwe do zainstalowania i przynoszą ogromne korzyści w postaci dodatkowych zakładek w narzędziach przeglądarki, takich jak „komponenty” i „profilowanie”. Kyle wskazuje również na istotne różnice w debugowaniu w Next.js, które musi brać pod uwagę obie strony: serwer i klient.
Następnie Kyle przekracza barierę prostych wskazówek i pokazuje, jak zintegrować edytor VS Code z przeglądarką do bardziej złożonego debugowania. Wyjaśnia, jak dodać punkty przerwania i monitorować zmienne wewnątrz edytora, co czyni debugowanie znacznie bardziej intuicyjnym. Rickt mostrando cómo usar puntos de interrupción, Kyle demuestra cómo se pueden gestionar y supervisar los estados de la aplicación más efectivamente, especialmente al tener activado tryb 'strict', który może powodować, że komponenty renderują się dwa razy. Nowy sposób debugowania, który jest prezentowany, polega na tworzeniu specjalnych punktów przerwania, które umożliwiają zatrzymanie procesu renderowania tylko raz na dwa uderzenia, co jest wyjątkowo przydatne, gdy debugujesz w trybie 'strict'.
Ponadto Kyle dociera do narzędzi dewelopera React, pokazując ich mocne strony i funkcje, które mogą zainteresować nawet najbardziej doświadczonych deweloperów. W szczególności mówi o zakresie analizy przy użyciu profili React, które wizualizują, jak często renderują się komponenty i które z nich są odpowiedzialne za spowolnienia. Wiedza na temat tych narzędzi jest nieoceniona, zwłaszcza w dużych projektach, gdzie złożoność aplikacji może prowadzić do nieprzewidywalnych problemów wydajnościowych.
W ostatniej części analiza Kyle'a koncentruje się na różnicach między standardowym React a Next.js, zwracając uwagę, że debugging w kontekście frameworka Next.js jest nieco bardziej złożony, ze względu na udział serwera. Kyle pokazuje, jak dostosować plik konfiguracji do debugowania na potrzeby Next.js, co pozwala deweloperom na precyzyjną kontrolę operacji zarówno po stronie klienta, jak i serwera. Dodanie takiego pliku konfiguracyjnego do VS Code znacznie ułatwia debugowanie aplikacji pełnostackowych, umożliwiając identyfikację problemów w jednym wspólnym projekcie.
Na chwilę pisania tego artykułu film zdobył 259,397 wyświetleń i 8,643 polubień, co świadczy o jego dużym zainteresowaniu i użyteczności dla społeczności programistycznej. Mimo że film ma sporo informacji, Kyle bardzo dobrze sumuje kluczowe punkty, oferując jednocześnie linki do dodatkowych zasobów, takich jak jego kurs, w którym znajduje się jeszcze więcej informacji na temat React. Jeżeli jesteś programistą, który chce poprawić swoje umiejętności debugowania, ten film z pewnością dostarczy ci wielu przydatnych informacji.
Toggle timeline summary
-
Wprowadzenie do debugowania w React, wskazówki dotyczące szybszego rozwiązywania błędów.
-
Prezentacja gospodarza Kyl'a z WebDevSimplified, zarysowanie sekcji wideo.
-
Dyskusja na temat ogólnych wskazówek dotyczących debugowania React.
-
Wyjaśnienie debugowania w Next.js, z podkreśleniem jego złożoności.
-
Podkreślenie narzędzi dewelopera React i ich korzyści.
-
Instrukcje dotyczące instalacji narzędzi dewelopera React.
-
Szczegóły dotyczące inspekcji komponentów i zakładki profiler.
-
Wzmianka o trybie ścisłym i jego wpływie na logi konsoli.
-
Podłączenie edytora VS Code w celu bezpośredniego debugowania.
-
Konfiguracja launch.json do debugowania w Next.js.
-
Wykonywanie punktów przerwania i zliczania trafień w celu skuteczności debugowania.
-
Wprowadzenie zakładki komponentów w narzędziach dewelopera.
-
Inspekcja props komponentu i ich wartości.
-
Wybieranie elementów i ich powiązanych komponentów React dla lepszego zrozumienia.
-
Wyjaśnienie granicy błędów i jej funkcji.
-
Końcowe uwagi na temat przesyłania i stanów ładowania w React.
-
Wprowadzenie profilu do testowania wydajności.
-
Jak zobaczyć czasy pierwszego renderowania za pomocą profilu.
-
Rekomendacja dalszej nauki poprzez pełen kurs React Simplified.
Transcription
If your react debugging looks like this, then you definitely need to watch this video. And that's because I'm going to be sharing with you all the tips and tricks that senior level developers use, such as these tools right here, to make debugging so much quicker. And if you watch all the way through by the end of this video, the next time that you run into a bug, I guarantee you're going to be able to solve it twice as fast using these tools. Welcome back to WebDevSimplified. My name is Kyle, and my job is to simplify the web for you so you can start building your dream project. Now, for this video, I'm going to be breaking it down into a few different sections. The first section, we're going to be talking all about React and just some general tips for how to debug in React. Then we'll be talking about Next.js and how you can debug in Next.js, because it's quite a bit different since we now have a server involved. And then finally, the third and by far longest section of the video is going to be talking all about the React developer tools and how you can use them in both Next.js and React in order to get all these amazing benefits that senior developers use almost every single day. Now, to get started, we want to talk about just some really general things that you can use inside of React. And the first thing I want to talk about is actually installing the React developer tools. This is very easy to do. If you just search for React developer tools, you'll probably get brought to this site, or you'll get brought to one of the direct install links. These are just installing extensions directly into your browser. But if you're not using one of these browsers, you can also install a package and run a few other steps that are detailed in this exact article right here that tell you exactly how to get set up with the developer tools. These are just tools that are built into the browser. For example, if I inspect my page, I now have two more tabs called components and a tab called profiler that give me a ton of additional information about everything related to my project that are incredibly useful for debugging. And the very first one actually doesn't even require you to use those tools at all. You know for a fact that if you're in strict mode, a lot of things get doubled. For example, if I just put in this simple console log that says here and I come over and I inspect my page and I look at my console, you can see it's been printed out twice. Once is being printed out from the first time my components run and the second is because of strict mode. This is honestly a huge pain. I hate seeing these logs in here twice, but with these react developer tools, I can just hit this cog icon right here. It says hide logs during second render toggle that to be true. And now if I go back over into my console and I just refresh my page here, you'll notice that it's only ever logging that out one single time, just like that one time, refresh my page again, one single time that it's being printed out. So this is a great feature already requires you to do nothing additional and just makes your console log debugging even better. Now, the next quick tip I want to talk about is how you can actually hook up your VS code editor to your browser so that you can do your debugging directly inside of there. And I actually have a full video, deep diving into everything you need to know about just debugging in general. And this is one of those things I'll link it in the cards and description. If you're not really sure how a debugger works, this is going to be a great video for you to check out, but essentially the easy way to do this, just click on this debug button right here. Ignore the fact that mine is kind of messed up formatting wise. I have a lot of custom CSS to make my thing easier for recording, but you just click this button and click on web app Chrome. It's probably a little small for you, but just click on that and you'll get a configuration file just like this. All you need to do is change the URL to whatever your URL is. So just copy that URL. We can paste it down inside of here. There we go. Now we have our URL, give that a quick save. And now the next time that we open this up, as long as we have this saved, you should see this plus or this play icon right here. If we click on that, that's actually going to start up my application in a brand new window. And the really great thing is it's hooked up directly into VS code. So now if I were to come into here and I would add like a debugger statement, just like that and save, you can see now immediately my code is hit that debugger statement. I can check what the value of my count variable is. I can do all these things. And if I click play, it's going to continue on my code. But since we're instructing what I have to hit this twice, because essentially I'm hitting this debugger statement twice. And if I were to bring that window back over, we'll just make it a little bit smaller. So it's easier to see. There we go. And I click this count. You notice I immediately get brought back into my debugger inside of here. So I can really see what's going on. And the nice thing is inside of here, you have information on different variables. So if I click in here, you can see, I get all my local variables and so on. Everything you could ever want to know is going to be inside of here. Now, this is really great, but since everything is hit twice because of strict mode, it's kind of a pain. So one thing that you can do that's really interesting is you can add in breakpoints. So for example, if I click on a line over here, it's going to add in a breakpoint. So you can see it's hit that code and it stops right there, just like as if I typed in debugger, but I can use a special type of breakpoint here called a hit count. And if I put in here, the percent symbol and two, that essentially means module 02, which means it's only going to hit this breakpoint every other time that the breakpoint is hit. And since we know strict mode renders everything twice, essentially what this does is it means only hit this breakpoint once for every single time my component rendered. So now if I were to come over here and refresh my application, you can see, I hit this breakpoint once and I click next, and now automatically it's out of there. It doesn't actually hit that thing twice. If I click count, you can see it hits this once I click next, and you can see it's already out of there. Again, this is, again, is a really great tool specifically for react and strict mode. Now that's pretty much all the small debugger related tips I want to give you. Most of the things I'm going to be talking about for react are going to be in the actual dev tools. But before we jump into that, I want to talk about what happens in a next JS project. For example, this project right here is a project built using next JS and debugging it is quite a bit more complicated because we have both a server and a client that we need to deal with. So your launch configuration file, which is inside of here, it's inside the dot VS code folder, launch.json. This is going to be quite a bit different. And in order to get this exact file, all you need to go is go to this URL, just type in something along the lines of next JS debugging, or I'll leave a link for it in the description for you. But if you scroll down, I'll zoom this in so it's a little easier to see. You can see it gives you the exact launch.json that you need. And this gives you three different debugger modes that you can use. So all you want to do is just copy this file, paste it into a file called launch.json inside your VS code folder. And this is specifically only going to work inside of VS code. Once you've done that, you can go back to this run and debug section. And now you have a dropdown that gives you a server side client side and a full stack debugger. So this means you can debug just the things that run on the server, just the things that run on the client, or you can debug everything all at once. For the most part, I like running this in the full stack mode. So now if you click play immediately, you're going to get all the same debugging behavior you got with just the react version, but now it's going to work both on your client and your server. And it's going to give you everything that you need inside of here, which is great. And it just pulled up on my other window, the application that we built. So you can see it's right there, but essentially anytime I put in a break point or anything like that, and if I were to come in here and I increment my account up top, you can see immediately it's actually hit that break point just like that. So everything that you would want to do inside of your debugging with react, you can now do in next JS. All you need to do is copy over that one launch config file. And the really great thing is that's really the only next JS specific thing you need to do. Everything else I talk about in this video is going to work for both next JS and react, no matter how you use it. So I'm going to close out of this because we just want to be working in the normal react version. It's going to be a little bit easier to work with. I'm going to drastically simplify our code here. We're just going to get rid of all this. We'll keep a button that increments things just like that. And there we go. We'll just keep that, get rid of all this other stuff. We really don't need all that additional stuff. I'll make sure I stop this debugger because we're not going to be using that for this video. We're just going to be using the debugger for the dev tools. But the nice thing about these two debuggers is you can use them both at the same time. So you get all the great debugging feature directly inside of VS code. And then you also have the ability to use the debugger in your browser as well. So what we can do is now that we have just the simple count variable that we can increment rather straightforward, I can look at what these dev tools look like. So if I inspect over here, what I'm going to do is I'm going to pull up this components tab. This components tab is going to render all the components in our application inside of a tree format. Right now, we just have one component, which is fine. We'll look into what it's going to look like when we have multiple. When you click on this, depending on how wide your browser is, it's either going to show information to the right or below it. For now, I'm just going to expand this so we have our information on the right. And you can see we have a section for all of our different props. For example, if we had props being passed in, they would show up right here. And we can even pass in different custom values that we want for our props to see what they're going to look like. Our hook section, this is going to show all the hooks in the order that we wrote them in our code. So we look over here, we just have one single use state hook. So you can see hook number one is our state hook that has a value of seven, because that is the current state of our button. You can see as I click on that, my state over here increments to be that exact value. Now, the unfortunate thing about hooks is they don't have any names. That's why it just says hook one state. But if you want to give it a pseudo name, if you click on this little magic icon right here, it's essentially going to take the variable name that you used. In our case, we use the variable name of count, and it's going to put that variable name right next to it. So it's a little bit easier to see what's going on. But the nice thing about this is always your hooks are in the same order. So if this says hook number one, that means you know it's going to be the first hook in your file, it says hook number two, it's going to be the second hook and so on. And no matter what hook you use, it's going to show up here. So if I put in a random use effect hook, just like that, it doesn't even have to really do anything, we just have it say console log high, just like that. Now, if we look at our app, you can see we have two hooks, the first one's a state and the second one's an effect. And we can come in here, we can manually change this state value if we want to. And if we look over here, you can see my account updated. So this allows you to fine tune and change things and look at exactly what your components are doing. Now in order to see what some of the other advanced features in here look like, I want to go back into our code. And I'm just going to add in essentially a child component. So we'll just come in do the exact same file, it doesn't really matter, we'll just call it child. Just like that, we're gonna turn on h1 that has a name inside of it. And we'll just take that name and just like that. And we'll say that it's a string because I'm using TypeScript for this. So now we can put our child component inside of here. There we go, pass it a name that says Kyle. Now if we give it a save, and we look at our application, you can see our name value shows up right there. Now let's go back to inspecting this, we'll go back over to that components tab. And now you can see we have our app. And inside of that, we have our child component. And you can see I have all the information for the props that I want to see. So I have my name, I have the value of that name, I could change this to be whatever I want. And if I were to save that information, you can see over here, it updates that directly in my page, really, really nice and handy. And you'll also see it tells me what component rendered this and the full call stack of the render. So if I have multiple nested components, it'll show me all their parents all the way up. And it even tells me the exact line of code where this is being rendered. You can see it's online 20 inside that app file. And if I click on this, it'll bring me to the component that renders it. All this is really handy to look at. Now, if we really quickly look at some of the other information that you get in this side of this page, you can see right here, I get the ability to select an element in the page to inspect it. So I'm just going to minimize this down a little bit, and I'll click on this icon. And it allows me to select anything inside my page, and it'll bring me to the exact react component associated with that. So if I click on this, you can see it brings me to that child. If I click over here, instead on my button, it now brings me to the app component, because that's where the button is rendered. So you can actually select an element on your page. And it's going to show you exactly what react component rendered that out, which I really love. Also, you have the ability at the top here to search. So I can search for example, for child, and it allows me to find those components. This is really useful because most of the time this page is absolutely loaded up with hundreds and hundreds or even 1000s of components. So finding the right one is really important. Then we have the ability to do different things with our component. This first one is for dealing with suspense, I'll get to that in just a little bit right now, our code doesn't have any suspense inside of it. But the next one allows us to actually go from the react component to the DOM associated with that. So if I click on this, it brings me to the element tab of the exact element that that code is being rendered inside of. So you can see it brought me directly to the h1 because I was on that child component. Well, if I'm on the app here, and I click on the eyeball, you can see it brings me to the button because that's the first thing rendered inside of that app component. It's a really handy thing right there. The next thing here allows me to just log out all the information related to that component. So let's go to our child here, I'm going to click this button. And then we go over to our console. And you can see right here, it gives me all the information for props, the nodes that are being rendered tons of different information. And if I have like state and hooks, for example, for this one, and I go over to my console, and we expand this, you can see I get my hooks information, my props, my nodes, literally everything you could ever want to see about your component shows up right there, which is really useful. And then finally, this just allows you to view the source code of your actual element. Sometimes it doesn't always work that great, because you have like source maps and stuff. But generally, this isn't as big of a problem. Because essentially, it tells you the exact file that it's in and the line number. So you can just go into your text editor and find that exact location. And to show you how this suspense button works, because right now, if I click it, it just essentially says this doesn't have any suspense code at all, what I want to do is just add some really simple suspense code. And we're going to wrap our child in that. So we'll say suspense, we'll give it a fallback that just says, loading, close that off, bring that down, come in here, make sure I import that suspense component. There we go. So now we actually have something inside of a suspense boundary. Obviously, if we look at our code, you can see it's just rendering out the name Kyle, which is perfectly fine. But if we click on that child component, and I click on this button to actually suspend that component, what you can see is now it says loading. So essentially, all this does is it treats it as if you're still in the loading state. And this is really useful for testing out what your application looks like in loading states, error states, and so on, I can just click that button, all of a sudden, my application pretends that this thing is loading forever. So I can really fine tune what it needs to look like in the loading state. And I can just toggle this off to bring it back to what it normally would look like. Also, generally, if you're dealing with loading states, you probably have error states as well, which means you're going to be using some type of error boundary, I'm just going to be importing an error boundary library. But if you want to be able to create your own error boundary and understand exactly what error boundaries do, I highly recommend checking out my full video covering error boundaries, I'll link it in the cards and description for you. And the last thing we need to do is just add in a fallback, we'll just have it say error, just like that. And since this must be an actual react element, we'll just make it an h1 that says error. There we go. So now we have our error boundary in place. If we go back to inspecting, we can go over to our components tab here, I can click on that child. And I can expand this out, you'll notice I have a brand new button. And this is essentially forcing it into an error state. So we can see what our application looks like in the case of an error. So if I click on that, and I bring this back, you can now see it shows me that fallback of error, and it's properly going into the error state. And I can click this button again to toggle back to my non errored out state. So now in combination with suspense and the error boundary, I can very easily toggle between error states, loading states and normal states to really see what my application looks like in all different avenues. Now, before we start diving into the second tab, which is this profiler tab, I first want to talk about some more settings that we can look at general setting is just going to be how you want the debugging tabs to look like theme and so on. We've already talked pretty much about this debugging tab, the components tab allows you to fine tune how this particular components page we've been talking about looks. So you can make it so that the tree always starts out expanded or not. You can also make it so that always parses those names of your hooks. So it's easier to see what the state are. I recommend leaving this off just because it may be slow to open up. Also, you can have it so you can open up things in your VS code editor directly. And what this does is if you have this checked, it actually adds a button right here, which when you click on it will open up inside of VS code, exactly where this code is, which is really useful. Now let's go back into our settings a little further. And this one right here is really important. It allows you to hide certain components because as you know, this tree can get massive. For example, by default, it hides all dom notes. But if you turn this off and we close out of this, you can now see things such as H ones and buttons are actually showing up directly inside of here with all their own props and so on. But usually you don't want all that information, which is why by default this is turned on, but you can hide literally anything you want inside of here by name, by type, higher order components. You can really add and fine tune exactly what filters you want to hide very specific types of components, which is really useful. Now, the final section here is you're going to be your profiler. And this essentially allows us to fine tune how this page is going to work. So before we dive into these settings, I first need to show you how the profiler works. So if we go over to the profiler tab, this is very similar to the actual performance tab built into the browser for testing JavaScript. But this is specifically for testing react, why things rerender and so on. So if you click on this button right here, this blue start profiling button, what's going to happen is it's going to open up your profile. And when I click on things in my application, do whatever I want to do. And then I click stop. And essentially it's going to give me a bunch of information for all the different times that my state changed in my application re-rendered. So you can see here, I have three different times that my application essentially re-rendered itself. And that's because I clicked on that button three separate times, as you can see by the fact that my count is incremented to three. So every single time you have state change or components, re-render props, change, whatever it is, it's going to Mark every single one of those inside of a mark here. Generally, this is going to be a lot of times that your application is going to re-render. So this may be a very large section that you can look at. But the nice thing about this is it breaks down exactly what happens. First of all, on the left, you can see it breaks down exactly which components are being re-rendered as well as the full tree of what's being re-rendered. And you can see, depending on what we're actually doing, certain things are taking longer or less time to re-render. It also tells you how long each thing took. So for example, my app component took 0.5 milliseconds to re-render, but it was a total of one millisecond to render the full app. What this means is it means my app and all of the children took one millisecond to re-render, but the app component itself with no children took half a millisecond to re-render. And you can see here, our error boundary took 0.3 milliseconds, but it and all of its children took a total of 0.5 milliseconds and so on. And as you click through, you can see exactly what's happening and you can see exactly where each of these different components is being rendered by looking at it on here. So we can see every single place where every single one of these has been re-rendered for the entire time that our profiler ran. Another really nice thing is if you just click on one of these commits up here for the things that change, it tells you exactly what the priority was, like, is this something that's dealing with use transition that may be a lower priority, the exact time from when you started your profile to when this thing actually happened, as well as all the different durations for everything that happened, and then why this update was actually caused, which is really nice to see that, oh, our app component is why this re-rendered because that's where our state for our count is stored. We also have this ranked graph here, which just shows you how long each component took to re-render. So this flame chart is good for seeing top down, like, how was everything going through my entire application. This is good for finding individual slow components. So whatever is at the top here is the component that took the longest to render, which in our case is our app, which took half a millisecond. Honestly, super not long at all. Our application is very simple, but if you have a really complex application and you have one component that's taking a really long time to render, it'll show up right here saying that it is taking a long time to re-render. We also have this timeline view, which sometimes can be a little bit tricky. Sometimes you have to click off and click back onto it. But if we zoom into this timeline view and we look at these different sections, it'll kind of show you exactly what's going on in your application. So you can see our state was updated inside of our app and it caused our react render, which took 1.2 milliseconds here. And then we had our react commit, and then we had some passive effects, just all the different super low level stuff of exactly what to react is doing. Honestly, I find I almost never use this tab. Really, it's going to be this flame graph or this rank chart are going to give me almost all the information that I need. Now, if we really quickly dive back into the settings for this, we can understand what these do. So the first thing here, record why each component rendered while profiling, I find very useful because it gives you a little more information on why each individual component actually re-rendered in your application. So we toggled that on. What we can do is we can come and look at each one of these. And if we were to actually restart our thing by doing another profile, click this button a couple more times and stop our profile. Now you can see each one of these. If we click on a particular component, for example, our child, you can see that why did this re-render is because the comparison component re-rendered. If we check here, you can see the props change, which is why this re-rendered. If we check this, you can see in our suspense while it doesn't have anything, but our app, you can see hook one was changed. So I really like this because it tells you exactly what is causing each re-render of every single component in your application, which is obviously very useful. If you're trying to figure out why extra re-renders are happening that you aren't sure why they should happen. Another thing that's really useful is you'll notice these bars are actually ranked based on how long these different things take to re-render. So the taller bars are going to be the slower things while the shorter bars are the things that take less time. So you can really easily test your application by putting it into your profiling mode, do a bunch of stuff, stop it, and then look for your tallest bar and figure out, okay, what is making this particular re-render so much slower than all the other re-renders in my application. Another thing in our settings is we can hide commits that take less than a certain amount of time. So I can say, you know what, anything less than 10 milliseconds, just completely hide that. So if I toggle that on, you can now see immediately all these commits disappear because they are all less than 10 milliseconds long. And if we turn that back off, we can see we have everything back in place. Now, another really important thing to understand is that you probably want to be able to throttle your performance. You probably have a pretty beefy computer if you're doing development work, while a lot of people will have really low end mobile devices that they're using. So you can come in here and you can slow down your CPU and even limit the amount of threads that your processor can use to really limit the performance that you have. And now if we go back to our profiler, instead of taking like 0.2 milliseconds, if I were to start this, click the button a few more times and stop it, you can now see it's taking about 1.2 seconds or I'm sorry, 0.8 milliseconds for this instead of 0.2 or whatever it was. So it's a little bit slower. It's still really fast because essentially this code is doing absolutely nothing. So there's really no faster that it can go. But if you had a much more complicated application, obviously doing this performance throttling would help you be able to fine tune what the different bugs are inside of your code. But again, it's only going to really make a difference if you have a more complex application. Now, the final thing I want to talk about when it comes to the profiler is this button right here. If you just click on this, it's actually going to restart your application from scratch and start the profiler. So you can actually see exactly what happens with the very first render of the application. As you can see, this very first render took 3.1 milliseconds because I had to render literally my entire application. And then all these other renders are for just changing my count variable and so on. So this is a great way to see what happens when your application first starts up to see if you have any performance problems there. Now, I know I covered a ton of information in this video, but if you really like this deep dive format, I highly recommend checking out my full React Simplified course. It covers every single thing you need to know in React in the same amount of depth as this video. So I highly recommend you check that out if you want to learn React. It's linked down in the description below. And with that said, thank you very much for watching and have a good day.