Letās debate debugging techniques! Do you print debug or dive deep into debugging tools? KBall & Jerod argue that print statements are all you need while Amal & guest Eric Clemmons take the other side. Who will win and why will it be Jerod? š
Featuring
Sponsors
Fastly ā Our bandwidth partner. Fastly powers fast, secure, and scalable digital experiences. Move beyond your content delivery network to their powerful edge cloud platform. Learn more at fastly.com
Fly.io ā The home of Changelog.com ā Deploy your apps and databases close to your users. In minutes you can run your Ruby, Go, Node, Deno, Python, or Elixir app (and databases!) all over the world. No ops required. Learn more at fly.io/changelog and check out the speedrun in their docs.
Typesense ā Lightning fast, globally distributed Search-as-a-Service that runs in memory. You literally canāt get any faster!
Changelog News ā A podcast+newsletter combo thatās brief, entertaining & always on-point. Subscribe today.
Notes & Links
Chapters
Chapter Number | Chapter Start Time | Chapter Title | Chapter Duration |
1 | 00:00 | It's party time, y'all | 00:40 |
2 | 00:40 | Welcoming our debaters | 01:01 |
3 | 01:41 | Amal intros Eric | 01:33 |
4 | 03:15 | Setting the debate stage | 03:34 |
5 | 06:48 | Amal's opening statement | 01:40 |
6 | 08:28 | KBall's rebuttal | 02:00 |
7 | 10:28 | Eric's turn | 01:29 |
8 | 11:57 | Jerod's response | 02:52 |
9 | 14:48 | Amal round 2 | 00:44 |
10 | 15:32 | KBall round 2 | 00:59 |
11 | 16:31 | Eric round 2 | 01:04 |
12 | 17:35 | Jerod round 2 | 01:21 |
13 | 18:56 | Amal round 3 | 01:06 |
14 | 20:02 | KBall round 3 | 01:20 |
15 | 21:22 | Eric round 3 | 01:13 |
16 | 22:35 | And the winner is... | 00:59 |
17 | 23:34 | Sponsor: Changelog News | 02:08 |
18 | 25:42 | Real thoughts begin | 11:32 |
19 | 37:14 | How Eric finds bugs | 01:31 |
20 | 38:46 | Bug sources > symptoms | 02:49 |
21 | 41:34 | One thing at a time | 00:40 |
22 | 42:15 | On intuition | 03:00 |
23 | 45:15 | Happy path assumptions | 02:43 |
24 | 47:58 | It's almost always your code | 02:36 |
25 | 50:34 | Check out patch-package | 02:40 |
26 | 53:15 | replay.io | 02:38 |
27 | 55:53 | Time-travel debugging | 02:34 |
28 | 58:26 | Closing time | 01:31 |
29 | 1:00:04 | Outro | 01:00 |
Transcript
Play the audio to listen along while you enjoy the transcript. š§
Hello, internet. Iām Jerod, your friend, and Iām here joined by some master debaters. I have Kball with me. Whatās up, Kball?
Iām looking forward to this one. Hello.
Good to have you. And Amal is back. Whatās up, Amal?
Hey, hey. I need a soundboard effect right now. Like, you know, āDung-dung!ā Like, Law and Order meets like Rockyā¦
Hold tight, Iāll get you somethingā¦ [We love JavaScript. We addicted to it. We love it all the time. We want it in our veinsā¦ Give me more. More, more.] Thereās your soundboard for youā¦
Thatās a new one. Okayā¦ [laughter] Iāll take it.
Do you remember saying that?
I mean, vaguelyā¦ But yeah. Alright, Iāll take it.
Thatās a cool one. I like that one.
Thatās a cool one. Thatās a very cool one.
And weāre joined by a special guest debater. Itās Eric Clemmons. Eric, welcome to JS Party.
Hey! Happy to be here. Ba ba ba ba bam
Ooh, he brought his own soundboardā¦ [laughter]
I donāt have a soundboardā¦
Yeah, weāll fix that up in post. So Amal invited Eric to debate with herā¦ Heās on your team, so why donāt you do the proper intro and tell folks who Eric is, so he doesnāt have to?
Yeah, Eric Clemmons is like a JavaScript gentleman from Texasā¦ I donāt know if thatās even giving you justice.
Iāll take it.
Heās a huge open sourcer, incredible lead engineer, heās worked a number of places, weāve spent some time together at Stripeā¦ And heās just kind of just overall ā I donāt know, Iām gonna get bleepedā¦ Heās just a JavaScript badassā¦ Really into kind of like solving problems when it comes to the developer experience. Heās got some really cool libraries out there. Oneās called click-to-component, and it lets you kind of inspect your elements real-time. Heās got some other really cool utils around testingā¦ I donāt know. Eric is just awesome, and Iāve wanted to have him on the show for a while, and glad heās finally onā¦ But Iāll let him introduce himself.
Here he is. Did she miss anything, Eric? Anything to add?
I donāt think there is. Iām kind of blushing and tearing up at the same time. Thatās really sweet. But yeah, the DX part is a very huge aspect of it. Anywhere that thereās friction in the experience, gotta burn it with fire. You know, kind of like console.log, and print debugging, that sort of thingā¦ [laughter]
Ohh, heās beginningā¦ The debate hasnāt begun yet, Eric. So for our longtime listeners ā
Those are baked. Why you gotta add friction?
Kball, the debate hasnāt begunā¦ Letās hold it back. Theyāre chomping at the bit here. So longtime listeners know that we routinely do debate episodes, where we pick a premise, and then we assign people to a side. They donāt get to pick their side, because that wouldnāt be as funā¦ And we debate whether or not that premise is true or false. We donāt call it true or false, we call it Yep and Nope, because of our friend Alex Sextonās classic yepnope.js feature detection library from way back in the jQuery days. Alex was actually one of the original panelists on JS Party, so itās a nod to him. Itās called a Yep/Nope, and weāre gonna play that today.
Todayās premise, if you havenāt guessed already, is about debugging. And the question that weāre trying to answer is āIs print debugging good enough?ā So print debugging - what is that? Well, thatās anytime that youāre just putting print statements in, however you happen to do that. Most likely, in our world, console.log. It used to be alert debugging; youād have an alert statement, and you would try to put some stuff in there, and itād pop out and youād read it and itād say āobject objectā. And then you wouldnāt have any help from that whatsoever. But console.log is significantly better than the bad old daysā¦ But is it enough? Is print debugging good enough? Arguing the positive will Kball, and your humble moderator, even maybe not so humble moderatorā¦ Me. I will be arguing today, because scheduling conflicts. So thatās the Yep side.
And on the Nope side, arguing that print debugging is not good enough will be Eric and Amal. We do this semi-formal, so we actually have a timer, and we have a buzzer, but we also have a shoestring budget, so our buzzer noise is Chris Hiller saying Wut. So if you hear this sound, [Wut?] your time is up. And if you donāt stop talking, I will hit that button profusely, until you do. I might even do it to myself, which would be weird.
I might just break out into song, if you knowā¦ What, what, what-what, whatā¦ You can put a beat to that.
Iām never gonna stop you from singing, Amal. Iām just sitting here in anticipation, soā¦ Whenever you break out into a song, Iām here for itā¦ Because we need more soundboards.
Eric, do you beat-box? Yāall could do a duo.
[beat-box 00:05:19.17]
Go, Amal.
Oh, goshā¦ On-demand isnāt the way it works. Itās when it comes. It comes in its own schedule.
She may be the Beyonce of the web platform, but sheās not actually Beyonce.
Right, right. That is very accurate, on many levels.
Thatās fair.
Yeah. But thereās some guitars behind Eric, for those of you listeningā¦ Eric plays a lot of music.
Thatās true. Eric, are you musical?
I am. This was part of the compromise to move to Texas from like Seattle, was I got to bust out all my musical instruments again. In Seattle I just didnāt have the room for the instruments, but now I do.
I was gonna say, youāve got a drum kit back there as well.
Yup. My very first drum set Iāve found when I was six in the church dumpsterā¦ So I havenāt been able to quit playing drums since.
Wow. What kind of music do you play?
Honestly, just anything Iām listening to in the car that sounds like it has a good beat, I come home and basically just replay it.
[06:16] Very cool. Well, we will cue you later to begin singingā¦ Iām sure Amal will work you in. Letās start this debate before we lose all of our listeners, and the debate hasnāt begun. So two minutes on the board, okay? Youāll have two minutes to state your case, and then weāll rotate back and forth between teams. So we will start with our guests - well, our guest is Eric. Amal, youāre on his team. Ladies will go first, so weāll let Amal go firstā¦ And you are arguing āNo, print debugging is not good enough.ā Thereās two minutes on the board. Amal, letās hear it.
Thank you, Jerod. And hello, listeners. Print debugging is certainly one way to do it. Itās not wrong. But the web has evolved. We have so many better ways to debug and inspect. Thereās lots of engineers that have created awesome tools and protocols that allow you to kind of connect with your code in a more intimate way than just logging statements.
So why would you limit yourself to just a bunch of logs, which arenāt always even ā you never know where youāre even logging from sometimes, unless youāre in a Node environment and you can print a context as wellā¦ And so logs are great, but thereās so much more. And hopefully, Eric, and I will be getting into all the thingsā¦ And with all the new features that have come into Chrome Dev Tools, which is kind of a shared universal protocol between a lot of browsers - why limit yourself to just logs? You can do things like even mock your HTTP headers now.
So weāve gone way beyond the days of just kind of breakpointsā¦ Weāre now able to manually trigger errors, and say, āHey, I want to kind of always have this network request fail, and so letās see how resilient my app is for when this network request fails.ā You can do all kinds of things, like conditional breakpoints, you can watch all the variables in your execution contextā¦ Thereās so much, so why limit yourself to just logs? Thereās more than logs.
[Wut?] Alright, very good. Opening case by Amal. Kball. Make our opening case for us, please.
Alright. Amal, in previous debates, you have said something along the lines of āJust because you can do it doesnāt mean you should do it.ā You have argued about the dangerous path that extensive developer experience-focused tooling React and other things have led us towards, and how those are poisonous for the web. And so I want to say, as developers, weāve got to master the basics. Weāve got to stay with whatās real, whatās built-in, what works wellā¦ And when it comes to debugging, that is console.log or printf debugging. You know, itās a ākeep it simple, stupidā type of situation, right? Like, keep it simple. This is all you need.
What are you doing in debugging? Youāre trying to understand the state of things as theyāre going alongā¦ And you said something like āYou never know where youāre logging from.ā Have you ever heard of logging āI got hereā? Thatās a core to printf debugging, āI got here.ā I got here, too. Keep it going.
So fun.
But in a slightly more serious frameā¦ There are so many different environments that youāre gonna want to debug in. Sometimes youāre able to debug something totally locally, other times a problem doesnāt emerge until youāre out in production, youāre in a distributed application, you have race conditions, and all these other thingsā¦ And the thing that all of these fancy debugging tools do so much of the time is they will freeze you in time. But now you have gotten rid of your race condition. Your bug goes away, you get a heisenbug, and if thatās how you teach yourself to debug, youāll never be able to use the tooling that happens in real time, flowing out data, and giving you that availability. Console.log becomes observability in production. It becomes, āLetās understand the state of many things happening at onceā, and it becomes a foundation for you to debug all of those complicated environments and other situations that show up outside of your packaged development environment.
[10:13] [Wut?] Alright, perfectly coming in on time, like the pro that he is. Llike the winner that heās gonna be. Eric, itās now your turn to spend two minutes talking about logging or not logging. Go.
Yeah, I mean, Kballās not wrong.
Good startā¦
I mean, if you have like one tool in your tool belt, that tool looks pretty good. And it pays to be proficient with a lot of other tools. Because I mean, if we talk about logging - yeah, thatās one piece of it. But itās missing the rest of the history of how we even got there, especially if weāre talking about the userās machine. If youāre console-logging, youāre on your machine. Youāve already gone into the codebase. What about everything else that happened before then? What made their environment unique, those race conditions that only they got to see, because they have a different environmental config, or a different browser, or maybe even like a different backend configuration that youāre just not aware of, that doesnāt match what youāve been testing or developing against?
So yeah, itās a tool weāve had, thereās not a lot of friction to it, it kind of reminds me of that meme with this cavemen with a square wheel, and someone else offers them a round wheel, and theyāre like āNo, thanks. Weāre too busy.ā Yeah, if you like to be effectiveā¦ I mean, we could learn from other people in the industry. For example, Next.js - big topic - has just launched their app routerā¦ And Tim Neutkens has even mentioned that like thereās 20 super-complicated bugs that would have taken days to reproduce and actually investigate if it wasnāt for improved logging tools. So half of the story is actually whatās going on on the userās machine who isnāt a developer, who doesnāt have console.log developing. So itās not ānoā to debugging, but maybe just grabbing the wrong tool for the job.
[Wut?] Alright, I will now respond. Itās interesting, Eric, that you mentioned improved logging toolsā¦ Weāre all for improved logging tools. We want the best logging tools that there are. But at the end of the day, these are logging tools, and logging is good enough. Print statements are good enough. Kball mentioned the KISS principle, right? Keep it stupid simple. Iāll also mention this - you want to be able to learn something thatās transferable. So I have logging skills, and Iāve worked in many different areas, with many different languages, and many different runtimes, and my ability to print stuff has paid off everywhere Iāve gone. Now, I also learned a little bit of GDB, the GNU Debuggerā¦ And let me tell you how inscrutable that tool is. And I learned how to use it, and I got some value out of it, and then I went into the web browser and I realized 0% of my GDB skills actually transfer into the web browser. And so now I invested a bunch of time learning a very sophisticated, powerful power tool, and I couldnāt take that anywhere.
Now, I could dive into Chrome DevTools and learn all the intricacies of Chrome DevTools, and maybe theyāll change, and my knowledge will be gone. Or Iāll switch to the backend, and now all of a sudden I donāt know the backend tools. And so thereās a real value in simple tools, easy to learn, easy to transfer, and good enough to get the job done most of the time.
Now, I still have 40 seconds left, so I will start our classic move of appealing to authority, and I will read some quotes at this time. āI donāt like debuggers. Never have. Probably never will.ā End of quote. Linus Torvalds.
āAfter over 30 years of programming in assembler, Fortran, C, C++ etc. I feel no desire to use a debugger.ā Neal Butterworth.
āIāve met junior developers who feel like they donāt know how to use a debugger, or they donāt know what theyāre doing, and they just put print statements out. Thatās completely legitimate. In fact, it tends to be my go-to thing doing that.ā Matt Ryer. [Wut?] And my time is up.
Thus concludes round one of our debate. So far, the Yups have it, the Nopes are struggling, but weāll see what happens in round two.
Amal, weāre back to you now. You have one minute; you can answer any of the things that weāve said, or you can just go off and say whatever it is you like, for one minute.
[14:13] Can we first start by acknowledging that the moderator is the non-neutral party? And so you get to add to the hype factor of your team, which really ā I mean, letās be honest, is it a tool? Is logging a tool? Or is it just like a thing?
Wait, is this your time? Okay, Iām gonna start your time? Youāre just launching into an argument before your time startsā¦
[laughs] Iām rolling it.
Okay. Your timer is going, Amal.
This is preparation for the reality of the corporate world. The moderator is always biased. [laughter]
Right, right. Itās a hard, cold lesson in capitalism, or something. But okay, so yeah, logging, as Eric mentioned - not wrong. Itās certainly a thing that you could do. But given the variety of options that you have at your disposal when trying to problem-solve, why limit yourself to the most rudimentary option?
So when you, for example, are able to actually stop at a breakpoint, and inspect your code, and see where ā you can look at the call stack, youāre able to look at not only how you got here, but where, because of the variables and all the things in scope, where youāre going to potentially head to nextā¦ [Wut?] Thereās so many other options. Why limit yourself to logging? I mean, for me, thatās the ultimate argument. [Wut?]
Alright. Kball, one minute.
Letās be real - debugging is a means to an end. The point is not the debugging process, itās to find that stinking bug and get rid of it. And you could do the classic developer thing, which is spend your three weeks learning your tools, digging in, getting it set up, perfect debugger, learning the changes that happened since the last release statement, and then youāre one day to debug. Or you could use the same tools that have been working the same way since the dawn of programming, and get to your bug a heck of a lot faster. And I know, as developers, we love to dig into fancy tools. Like, thatās one of the reasons we got into development. And itās great if youāre doing it for fun. But if your goal is debugging, and getting to the end of that bug, stick with the tool that you already know, that works well, thatās going to be transferable, as Jerod said, and fix your bug that much faster.
[Wut?]
ā¦or slower.
Coming in right on time. Alright, Eric, your turn.
Right on. I think itās wise for us to recognize that code is a means to an end. But itās also pragmatic to say that how we work, how we do the job that people are paying us to do, the faster we can shorten that time between āThatās not doing the thing that we paid you to do. Make it do the thing that we paid you to doā, is in the best interest of the company, and also kind of what makes you valuable as an employee.
So there are going to be non-transferable skills at any sort of job - who to talk to, what the bug tracking system is, how the release management process works, what the codebase even looks like; is it going to be different from the last place? Thatās largely non-transferable.
So if we level-up our tools to be able to get us to āWhere is the problem actually happening?ā and let us get us into a reproducible state faster, as fast as it was for the user to experience that bug, thatās going to shave off a ton of time of us trying to set up an environment, us trying to do console.logging replaying, and constantly changing our print statements until we can actually identify where it was, where we could have had the information to begin with, versus throwing it away. [Wut?]
One minute for meā¦ I will now continue reading quotes off of the internet. No, Iām just kiddingā¦ [laughter] But I will mention that I have polled the audience, our Changelog community, and 55% of respondents mostly use print statements. And only 45% mostly use a debugger. So thereās wisdom in the crowd, and proficient, crowdly devs find print statements to be good enough. As do I.
[18:00] So I will now tell an anecdote of my life. I have been developing software for 20+ years, various stages of qualityā¦ And so that can be up to the reader of the code, I suppose. But Iāve put up production systems, and Iāve built all kinds of thingsā¦ And like I said, back in the day, I learned GDB, and I learned how to use a debugger, and I see the value in it. Ultimately, the ROI on that tool is lower than Iām willing to invest. And so as I move on in my life to the next phaseā¦ Oh my gosh, I just got started. Hold on, I now allow myself 20 more secondsā¦ [laughter]
Just gonna lean on that scale a little more thereā¦
Yeahā¦ Iāll stop, because I am a fair moderator. Iām not biased. Iāll stop right there. But yāall know where I was driving with that little story. And I was going to a really good place. Okay, weāll give Amal one more minute. Do you want another minute? Have you got anything else to say? Or are you all out of arguments?
Yeah, sure.
Alright, go ahead.
I mean, I feel like Iāve been arguing against logs, but really what I should be doing is arguing for all the things that you can do beyond logging. So look at how the web has evolved. So we have tools like Lighthouse, that allow you to kind of debug all kinds of issues in your application real-time. And thatās something that you canāt do from a logger. You can record your performance, you can look at your heaps and get snapshots of kind of how much bandwidth youāre utilizing. Or device compute youāre utilizing. You can figure out how long API requests are taking. Thereās all this kind of conversational ā thereās a kind of a huge conversational element, and almost like a query-like elements to debugging, which you canāt get from just plain logs. [Wut?] And so yeah, why limit yourself?
Kball, one more minute.
The world is ā itās a big, big place out there.
[Wut?] Listener, disregard the last thing Amal said. It didnāt count. It was outside of the time. Okay, Kball, go.
So I think fundamentally we might be disagreeing about what logs are. So when I want to debug something that happened to a user in production, I go and I look at the information I have about what happened to them. Itās in my logs. I go and look up the exception trace. What was the exception that it threw? Thatās a log. I go and look at my observability of like āOkay, how many other people have hit this? What are the data on that?ā Thatās an aggregation of logs.
Fundamentally, logs is whatās underneath all of these advanced tools. And if we start from thinking about what data do we need to log - and I donāt just mean āWhat data do I need to log now to debug this problem that Iām doing now?ā But if I start from a log-centric mindset, I am thinking about āWhat do I need to be logging throughout my applicationās path, such that when something goes wrong, I have the information that I need in order to track down what it was?ā Because I canāt predict what is going to go wrong, or when itās going to go wrong. I donāt have a controlled environment for when things go wrong for usersā¦ [Wut?] So I need to be thinking from a log mindset what needs to be there for that future self.
Log mindset.
Do not pay attention to the last thing Kball said, unless it was really good for you, then go ahead and keep it. Alright, Eric, final statements. Youāve got one minute. Go, sir.
Yeah, I mean, if weāre gonna talk about how we store data, like the .har files that we record in browsers, and everything we store, we might as well say yup to JSON, and Iāll be on the same page and end the show now. But itās more to that. If we look at the patterns of when logging is good enough, weāre seeing engineers keep ā like that quote from earlier, just like āI see junior engineersā¦ā Yeah, because itās a low-level tool and primitive. You learn that day one of programming. But if you want to stay at a junior-level debugging experience, then thatās perfectly fine. But as we improve and grow, one of the things that we should be doing is having faster, rapid iteration loops, and a lot of that comes from leveraging the tools that are applicable to the environment weāre in, thatās in the stack that weāre in, and the company that weāre in, and using those tools so that way we can go from zero to fixed as soon as possible. And if that means moving console statements around, you can just look at the number of typing, like how many key presses youāve been using to debug something to realize that this is kind of an inefficient process. If you could have gone to what the end result is faster, where that undefined came from, youād be done. [Wut?]
[22:34] Okay. So as moderator, I will defer my final minute in order to tally the resultsā¦ And we had ā letās see, carry the threeā¦ Okay, over hereā¦ Wow. After this scientific result calculating, it turns out that for the first time in Yup/Nope history Jerod didnāt win. We all win. [Win, win, win, win, win. We all win.] So congratulations to both sides for presenting excellent cases. We all win, guys. How does it feel?
Not riggedā¦ [laughter]
Alright, well, dear listener, obviously, you have a real winner in mind, and so you can email us, you can tweet at us, and you can just tell us that it was me, and then weāll feel better about it. But Iām not going to declare myself the winner, because Iāve transcended such things. But finally, at the end of the day, weāre happy, because we all are going to find that stinking bug. [Ah-hah! Iāve found ya, ya stinkinā bug!]
Break: [23:35]
And thus ends our Yup/Nope debate, but weāre not finished talking. So letās now just discuss freely amongst ourselves - no timers, no moderator, no Jerod winning everything, but just giving you guys that olive branch and saying that we all won, even though we really know what happenedā¦ Instead of all that, letās just discuss debugging tools, techniques, what do you all doā¦ Are you representing the side that you actually believe in? I will say that I do use console logging for most situations. There are obviously scenarios where you get a particularly sophisticated bug, and you do need a little bit more firepower in that circumstance, and so I will move on from thereā¦ But I do find that for most things, itās enough to use console.log. And because of the power of the dev tools, console.log has so many features, like right-click āStore as global variableā - thatās basically print debugging, but itās going beyond print debugging, isnāt it? ā¦because now youāre actually interacting with the environment as it is, and thatās incredibly useful for diving into an object and seeing what data is there and all that. So thatās my actual take, because I do mostly do print statements, but I also like to hop into the runtime and stop things, and try things when itās sophisticated, or difficult, or when print statements arenāt quite good enough, even though mostly they are. So thatās what Iām thinking. Eric, whatās your stance? How do you debug? What are the tools that you use in these circumstances?
Itās a lot of the same. And really, the biggest problem isnāt so much of where to put that print statement, or if Iām going to run Node Inspector, and debug this thing in Chrome, and set a breakpointā¦ I find actually breakpoints be more of a hindrance; Iāve recently learned how to do like the variable watching, which has been way more useful for meā¦ To just say, āLet me know what this value is and how it changes.ā Weāve talked about race conditions earlier, Kballā¦ Itās kinda like that example, is I want to see the thing run and play, and then just get into the iteration loop. But thatās not really where the friction is. Most of the friction for me is trying to get to the reproducibility part; itās all the stuff outside of my control. Iāve spent so much time over my career trying to have reproducible environments, and trying to like log in as and impersonate some special user sessionā¦ And that ā I mean, thereās tools solving for that now, but I see that as being where like most of the āWorks on my machineā issue is coming from; the code part has become easy to actually debug once you have reproducibility.
Yeah. Good point. Reproducibility is killer. A lot of the work is just getting to that spot, or finding that spot. Yeah.
Yeah, I would second that breakpoints can be annoying AF. However, helpful AF. However, I think for me that ā I didnāt want to argue this earlier, because it wasnāt team logā¦ But console.log has really gotten very souped up; thereās really smart things you can do now. Thereās console.assert, that lets you kind of do a conditional console.log, where you can say - your first parameter is what your truthy or falsy value isā¦ So you can do a check to say āIf this is true, then do a log.ā So if you donāt want to end up ā
Yeah, that is such a useful tactic.
So good.
Itās so helpful.
Yeah. I mean, itās way better than a breakpoint, because then you donāt have to find ā thereās all this context switching, right? So thereās that, and then just being able to kind of also view your data in a richer way, like things that youāre logging, with console.table, console.dir, whether youāre trying to kind of open up arrays, or objectsā¦ Thereās nice ways to kind of quantify the data that youāre printing. So logs are great, but for me, thereās just nothing more beautiful than also just typing debugger-semicolon and just letting your code rip, like run. And being able to just kind of inject a breakpoint from code. I think thatās also just really nice, and something that I donāt see developers utilize enough; you donāt have to kind of futz about.
However, I think some of our pain points around using breakpoints have greatly smoothed over in the recent versions of Chrome. Everything from kind of like auto-ignoring third party scriptsā¦ Like, donāt you hate it when youāre just trying to like walk, get to a place, and then itās like āWhy am I in all this obfuscated JavaScript that I havenāt written? Get me out of here.ā So being able to ignore third-party scripts; and then being able to even just click on entire directories from within your debugger and just say ignore; like, your Node modules, or any other directory that you want to ignore.
So thereās lots of kind of nice UX improvements, I think, that have happened around working with breakpointsā¦ So if itās been a while, or if youāve hated breakpoints your whole life, Iād say give them another chance. I think thereās a lot of really nice improvements that have come in over the past year and a half.
[30:35] I think itās also worth pointing out that thereās kind of different kinds of debuggingā¦ Because a lot of the debugging that I do is actually just development. So Iām actively coding, and Iām just like shaking out bugs while Iām coding. And so in those cases, console.log is darn near all you needā¦ Because youāre like coding, youāre doing a thing, youāre like āOkay, this is not working. Whatās wrong with this object here? Okay, Iām gonna print it, Iām gonna look at it. Okay, no wonder; it didnāt have this property. Okay, go back to my code.ā
And so Iām debugging while I code. In that case, I donāt really find ā I do like to stop the world every once in a while, but I donāt find it to be super-useful. But then you have the one that is like ā somebody opens a ticket, and itās like āOkay, this āā And it comes back to what Eric was talking about, with reproducibility. Itās like, this bug exists in production, and it exists for this user, at this time of day; they happen to live in San Diego. But the production database is in Tokyo, or something. And now youāre like āOkay, Iām not like actively doing stuffā¦ Iām just here to solve a problem. Where do I start?ā And a lot of the difficulty is, āWell, how do I get my system that Iām working on to look like production, to look like that user?ā And Eric, you mentioned shadowing techniques, or like login as, or masquerading as a user kind of things, which - that stuff is very valuable, but you end up having to develop that yourself, or you have to like buy a system that allows you to do thatā¦ So a lot of times, I think thatās the really complicated part of debugging.
Having a local production environment, something that connects to the production databases, but lets you reproduce in a local environment is super-helpful for that. That was something that I hadnāt seen that much, and then my last job had that, and I was like āOh, this is really cool.ā
Are there guardrails around that?
In that case, there were. So the default was you were in read-only mode. So you could log in, youāre accessing it, but youāre read-only; writes are just ignored. And that was implemented at the data layer, so it would have been very, very hard to mess that up. That was the biggest guardrail. There were others. There was like a banner on, āYou are in production modeā, or whatever. āBe careful.ā Things like that.
So thatās something that somebody at your previous employer put together, right?
They built, yeah. And it was easier to do in that environment because they were operating in a world where even the development environment was connecting to a cloud databaseā¦ So you didnāt have this local versus cloud split in the same way. So the environmental change was not that differentā¦ Though if youāre already implementing a cloud environment for your production, and youāre already thinking about how that works, adding a local prod version of that, so long as you have your tunneling things figured out, which is kind of the key question, is like permissions and tunneling, and how are you doing itā¦ We were operating in a trustless mode for everything; we didnāt have, āOh, this is a trusted network and this is notā, which once again, that setup makes that a lot easier to generalizeā¦ If youāre having the āOh, weāre inside the cluster, so weāre trustedā type of setup, itās a lot harder to implement a local production environment.
Coming back to this question of debugging - youāre totally right, Jerod, a lot of debugging is in flow with development. When I think about debugging, I donāt even think about that. Thatās just like, thatās development. Okay, Iām working on that in whatever the tool is for the job. And when I think about debugging, a lot of times the things that I would get brought into, especially my last few positions, itās like āThis is something that happens somewhere in production, and we donāt know why, and we donāt know what reproduces it.ā So sometimes itās figuring out how do you get your reproducibility, and in some cases there is no way to get to reproducibility. It only happens when certain things align.
[34:15] And so then it really becomes about how do you ā it is this observability question, extension of logging, of like āHow do you get enough stuff in place in your application environment, so that when the problem happens, the information is captured, enough information is captured that you can reproduce what actually went on there?ā And I do think in that situation ā the āconsole.logā debugging is a closer mindset to that, but itās reallyā¦ Like, weāre starting to talk about observability, and this question of āHow do you log out sufficient application state to understand what went on when youāre looking at it after the fact?ā, rather than āI have an environment where Iāve reproduced an issue, and Iām doing things, and Iām able to tinker and go back and forthā, which is where both the inflow of development debugging happens, and also where a debugger or tools like that tend to be very useful.
Thatās a really good point, Kball. I think for me, just listening to you, I was reminded of console.trace; something else that Iām ā at one point in my career I remember I just like substituted all my logs for traces. It was super-annoying, but it was helpful. Annoying because you get this long outputā¦ But yeah, itās nice to be able to see how you got there. I forgot that you canāt actually do that with a log.
Is that the same thing where it gives you a full stack trace? What does console.trace do?
It basically it prints out, you know, if you give it a thing to print out, but then after that, you see how you got here. So we are in this function, and before this we were in this function, and this functionā¦ So itās kind of like your stack trace, but it gives you that, I donāt know, five or six lines deep of everything that happened; what contexts were you in before you got to this context, basicallyā¦ Which is very, very helpful.
But I think for me, debugging is just about piecing together the map of your state, your application stateā¦ And I remember the first time I debugged, it wasnāt even in a JavaScript context. It was like in Python, and Rubyā¦ All these ā similar to the debugger statement in JavaScript; you know, in those languages you can put like a binding pry, or IPDB
Right. Pry is a tool in Rubyā¦
Exactly. And so you immediately open up this repl context where you can actually query and see āOkay, what is my application state right now?ā And I think for me, thatās the secret sauce power of being able to actually stop and pause in an execution context, is actually understanding āWhat are the values of all these variables right now, and whereās the disconnect?ā Because youāre there because something isnāt happening as you expect it to be. And so I think thatās very useful. And I think tools like TypeScript have reduced the need for some of that, to be honest. I think thereās a little more predictability in our overall state because of TypeScriptā¦ But still.
But still.
*bleep* still happens, yes.
So Eric, in your work, when you get a ticket, or you get an issue, or a colleague comes to you and says, āHey, Iāve got this bug. I canāt figure it outā, what do you generally do? Where do you start? What are the steps that you take to get through that?
The very first thing is always āAlright, show me with a video, a reproducible repoā, something like that. Itās usually ā itās kind of like āHave we logged enough?ā If I find myself going to Data Dog to look at raw logs for what happened, I already know Iām going to be having a bad day. Iām like āThis is too far in. I know Iām missing off on network requests, and everything.ā Yeah, but once you get into āOkay, I can point to where the problem isā, itās kind of like normal development, like you mentioned, Jerod. Weāre constantly logging, seeing what the state is of how somethingās workingā¦ And I have a nagging voice in the back of my head thatās like āYouāre putting all these console.logs in here.ā And I have a personal rule that says āItās okay for bugs that happen once.ā Hopefully, employers arenāt listening, butā¦ You know, āItās okay for bugs happen once, but just not twice.ā
[38:14] And so anytime I do something ephemeral, like putting into console.log, that ultimately gets deleted from that bug, that nagging voice is saying āWell, you could have been doing test-driven development for this, right? Couldnāt this have been a test to make sure it doesnāt happen again, instead of you just logging out, āOh I wasnāt doing a typecheck here,ānNow the undefined isnāt happening, and I fixed it.ā So thatās usually how the flow goes, is identification, reproduction, and then whether or not that fix is going to be resilient to more code changes in the future.
I think thereās something really important in that, which is trying to identify not just what was the immediate source of this bug, but what is the underlying fragility, whether itās in our processes, or our systems, or whatever, that led to this bug being possible. Ad bugs are gonna happen, we are all human, humans make mistakesā¦ But you can often start to detect things like that, where you might say, āOh, weāre using JavaScript instead of TypeScript, and so we have this whole set of things.ā Maybe if we move to TypeScript, this wouldnāt be possible.ā Or we have a set of types that are not sufficiently constrained here, and so weāre running into challenges. Or maybe you can say, āOh, this system is developed in a way or works in a way such that it results in lots of buggy code. Itās really hard to work with, and people tend to misinterpret it because the API is shaped funnyā, or something like that. Okay, letās identify those patterns that lead to the bugs, and then say, āOkay, when we have time, or let us make some timeā¦ How do we address that systemic issue so this class of bugs completely disappears? ā¦not just letās whack a mole them down as they show up.ā
Yeah, well said. And I think, Eric, your point about adding tests - I mean, thereās no better time to add a test than when youāve just fixed a bugā¦ Because now you know exactly one thing that could go wrong, and you can add a test that just makes sure that at least that one particular thing is never going to go wrong again. So even if you donāt TDD it, you can at least add a regression test after the fact, that just tests for that bug. But it actually is a good way to debug, is once you know what the problem is ā
I was gonna say, even better is before.
Yeah. You write that as a test, and then you make the test pass, and life is good from there. I will say, when it comes to actually identification - so Iāve worked on a lot of network systems, Iāve worked on a lot of web apps and stuff, and there are certain people that you work with over time who are just really good at findingā¦ You know, a lot of times youāve got to find the bug; thatās all the work. So reproducibility is the name of the game; itās like āHow do I reproduce this?ā And sometimes you can just get yourself in this general arena of the bug, but youāre not really sure exactly whatās going wrong, but you know itās not this subsystem, or that subsystem. Itās over here in this subsystem, and youāre trying to feel around in the dark. Depending on your tooling, it could be more or less dark, but a lot of times it is, for what exactly is causing that circumstance. And people that Iāve learned from that are really good at that - some of it eventually expertise turns into intuition, and theyāll just kind of know whatās wrongā¦ And youāre like āHowād you do that?ā and they canāt describe it, and youāre like āDang.ā
[singing] I feel it in my fingerā¦
Yeah, exactly.
No, Iām just kidding. See, Iāve found an opportunity to singā¦
Oh, no, but then you stopped short. We want you to launch into it. Eric will grab his guitar, and then Kball and I will just dance.
Yeah, exactly. [laughs] Yeah, weāll just be squashing bugs.
Weāll have an actual partyā¦ But if you donāt have that intuition, Iāll say this - only change one thing at a time. Thatās how you find it. You keep everything ā like, caeteris paribus; everything else is the same. Iām going to change one input, Iām gonna test it. Then Iām gonna put that input back to what it was, and Iām gonna change my next thing, and Iām gonna test it.
[41:51] Never change three things and then see āOh, Iāve reproduced it all of a sudden.ā Well, which one was it?ā āI changed three.ā āThose three together? Or was it two of the three? Or was it just that one?ā āI donāt know.ā And now I have six more things I have to go try before I actually have confidence that the bug is fixed. So thatās like the best, for me, advice; when you donāt have the intuition, eventually youāll get there, I think, if you develop long enough. Just change one thing at a time, until you land on it.
When you mentioned that intuition - how much of that is the building up of the skill of being able to identify where problems can happen, those types of problems, the entire classes that we ideally want to remove? Or is it intuition of how the system works? Like, where the systemās fragile, where the system is resilient, that sort of thing.
Yeah. I would say that Iāve seen it be both; itās kind of hard to actually dissect that and say either or, because Iāve been with people who are deeply into a system, like they know that system inside out. And thatās the guy or gal that youāre gonna go to with the bug, because they know the system. And then Iāve also ā I have one individual in mind specifically, whoās just good at finding bugs in anything. And so it didnāt matter if he has the domain expertise, or he wrote that subsystem or not, itās like āHey, George, or whateverā, Iāll keep it anonymous, to not embarrass somebody with complimentsā¦ Heās just good at debugging things generally; itās like, he just knows how to ā I donāt know. So Iāve seen people that are kind of in both camps. Does that align with you guys, orā¦?
Yeah, thatās very aligned with my experience. Thereās some people who have just been doing this for so long, they are very familiar with āOh, youāre seeing this problem, and it has these symptoms? Oh, itās likely due to XYZ.ā And they donāt know your system at all.
Right. Theyāre like āItās DNS.ā And youāre like āNo, itās not DNS.ā And then 17 hours later, it was DNS.
Right. And then thereās the people whoāve been there so long, theyāre familiar with all the problems. Theyāre like āOh, when this thing happens, itās because this API system and this thing, or this thing are down.ā Like, theyāre very familiar with the specifics of that. And to that, I would say that ā when youāve been there long enough that you know all the things that could go wrong, maybe we should be putting more resilience in strengthening that part of the code, if itās so problematic that everyone knows āWhen this thing happens, itās this problem.ā
But for me, the debugging is ā I think Eric kind of mentioned this earlierā¦ Itās really your best way of reducing that time to solving a problem, is āWhatās your observability stack?ā Because I donāt feel like teams invest in that enough often; itās always an afterthought, absorbability, both from just analytics metrics, things like Sentryā¦ All kinds of just ways to kind of log out your application state, and getting a baseline; the sooner you have all that stuff in, you have a baseline of ānormalā, and itās easier to kind of see when things are going haywire. You can set thresholds, you can monitor for changes etc.
So I would say really donāt sleep on observability. Itās very much like the public health versus kind of ER; like, proactive versus reactive. But it usually really goes a very long way into kind of reducing how long it takes you to figure out whatās going wrong. Itās an important part of the debuggerās toolkit.
I want to take something that Jerod said and extend it. So Jerod, you talked about changing one thing at a time, and I think that is an example of something that Iāve found to be very important with debugging, which is just being extremely systematic about understanding what is true and what is not true. Iāve found with a lot of newer engineers, or people who struggle with debugging, theyāll jump to conclusions about whatās probably going on, and then spend their time trying to verify that conclusion. And it comes back to - itās hard to prove something is true, itās much easier to prove something is not true. And so I always start with, āOkay, what is going on? Show me the situation.ā
āWhat is going on?ā Yeah, thatās what Eric said earlier. Yeah, āShow it to me.ā
[45:59] What do we know is true? What do we know is true? Can we confirm that? So going back to if weāre using logs, or weāre using a debugger, or whateverā¦ If you know the error is happening in a particular function, donāt jump to somewhere down in the function and try to figure it out. Logout what is true when you enter that function. What arguments were passed? Do those match your expectations, or is there something unexpected happening on there? Start from validating those very basic, fundamental assumptions, because usually, bugs donāt arise because our assumptions were correct and then we implemented it wrong. Usually, they arise because there was a gap in our assumptions; we were assuming that something would be true, that it turns out in some situations is not true.
And so the sooner that you can get to the point of āOh, hereās the place where my assumptions are not being validatedā, the sooner youāre going to be able to figure out, āOkay, why? And is the problem that I need to handle this other case, or is the problem that something upstream is breaking and sending me invalid things?ā It gets you arrowed into that much quicker. But I think a lot of folks start with, āOh, I think the problemās hereā, and they jump right in, and they never take the time to validate their assumptions and move systematically.
Brilliant. It reminds me just how little we do as kind of like engineers to test for like the non-happy paths; those assumptions are baked into so much code. I mean, you can look at failure statesā¦ And itās actually one of the beautiful things about being in the frontend space as a web developer, is that thatās a portable skill, of being able to work in the browser. You hand me a URL if somethingās going wrong, and Iām going to be able to look at these really rich tools that you donāt get when you console.log in Node. I can actually expand out variables, and copy to the console, like you mentioned. Itās almost always like at the network layer, where we see that some happy path assumption isnāt true anymore. And then thatās whenever all the problems arise.
Iāll give one other bit of generic adviceā¦ This maybe more along the āWhile Iām coding, troubleshooting, debuggingā, less so than just āHere comes a production ticket.ā In my experience, itās almost always your code. And this is just a humbling ā I mean, 9 times out of 10. I mean, sure, the further you get away from your code, the least likely it is to be where the problem lies. The fact ā like, is it in the Linux kernel? Probably not. Is it in Node.js? Probably not. Now, there are bugs there, there are problems, and there are things that change out from under youā¦ But thatās like the 1 in 10 cases, like āWell, Nodeās API has a bug in this version.ā And most of the time, 9 times out of 10, if youāre looking for the problem, look in your code, and then look in the code thatās touching your code, and then work your way down. Because I, especially as a young man, would immediately ā I was a Ruby on Rails developer, and I would dive into the Rails codebase immediately, and be like āWhat are they doing wrong this time?!ā And it was always me. I was like āWait a secondā¦ā Talk about checking your assumptions, right?
So just be humble enough to start with your own code, and stay there for a while, even when you canāt find it, before you decide āIām gonna hop into Chrome Dev Tools and open up the source code for the dev tools. Maybe the dev tools are actually printing this wrongā¦ā Thatās how strongly I would not let myself be the source of the bugā¦ So itās almost always your fault.
Almost always.
Yeahā¦
Butā¦
Butā¦?!
Well, it is almost always true, and you are absolutely correct, thatās where you should start. And we did an episode where we shared debugging horror stories, and I will say the horror stories usually have to do with something in the environment.
Yeah. Thatās why I said nine out 9 times out of 10. I mean, if you do enough bugs - I mean, 1 out of 10 is a decent clip. If youāre gonna do 100 bugs a month, itās gonna be somebody elseās fault. And thatās a made-up number, of course, but itās almost always yours.
Everything was working, until you put your code in. And then now itās broken, soā¦ Yeah, that is the one variable, is yourself.
[50:01] Yeah. Itās also the thing that you can control the bestā¦ Upstream bugs are the worst, because now youāre like opening a ticket, it goes into a queueā¦ Hopefully, you have a workaround that you can do for now, and then you put a little note in there, like āOnce this issue gets closed, I can take out this monkey patchā, or whatever. And then that lives for like seven years in the codebase, of courseā¦ But the further away the bug is from your code, actually the less agency and autonomy you have. And so itās better than it is your own, because you can just change your own code. Whereas upstream - youāve got bigger problems. But they do happen.
Have you used patch-package for issues like that?
No, please explain.
I see Kball is nodding over thereā¦ I discovered it a few years ago, but effectively, you find an issue in some upstream package, something in your Node modules, you try your code, your code is flawless, as usual, and so you trace up, and then you find itās some sort of Node moduleā¦ And you go in there and you change the code for the Node module, and you fix it. So what this patch-package does is itāll do a diff of your Node module, create a diff of that, generate a PR for the upstream package that has the issueā¦ Meanwhile, anytime you install that dependency again for anyone else on your team, a patch will be applied to it, a Git patch will be applied to itā¦ So that way, your fix for it before it lands upstream is at least in your project, and you can benefit from it. It works pretty well in my experience, with the exception of the more transpilation npm projects have, where they have like one single index.js file thatās giant, it makes the utility a little bit lower.
Yeah, itās really useful. It works best also with projects that are likely to accept your patch sooner, because the more thereās churn ā like, if you update the package, you need to now update your patch in patch-package, because otherwise it wonāt necessarily apply cleanly if thereās been other changed aroundā¦ So if you have a package that changes frequently, but doesnāt accept your change, it either youāre pinning to the version that you have, or youāre having to continually keep redoing that work.
Yeah, I donāt see how it would work without pinning a versionā¦ Because if you canāt guarantee that your merge is gonna get accepted, youāre risking it just randomly breaking for others. But thatās so cool, Eric; thanks for sharing that.
Yeah, Iāll link that one up in the show notes.
Yeah. I mean, open source code is battle-tested, thereās more people using it, so to Jerodās point - yeah, start with your code first, because itās likely the least ā especially if itās new, the least battle-tested code in your stackā¦ But I mean, considering that only one out of every ten lines is code that you write in your application, for every 10 lines that you ship, 9 of those are from third party librariesā¦ I mean, itās pretty amazing that we donāt have more issues.
Itās a large surface area.
ā¦more issues around the integration layer.
It is. Sometimes Iām still amazed at all it works.
Itās really amazing. And not only that, just with security issues too, that thereās not more burning security issues every time. Thatās also very impressive.
Alright, do we have any final thoughts on debugging, tools you like etc. before we call this a conversation?
I want to look into Replay. Iāve seen a lot of discussion about it. Replay.io. And the biggest question I kind of have is like when a bug has already happened, how can I get to that replay? Does it require like a Chrome extension, does it require an app to be running? What does this mean for like an end user versus as a developer tool? And I donāt have the answers. I donāt know if anyone else is has used itā¦ But the promise of something that can give me a replayable session is - thatās where I want to be, like developer experienceā¦ I want to do my job normally, let the bugs normally happen like they do, and then try to just go back in time and be like āOkay, now letās pretend the code was actually this, and I did it right the first time around. Now does it play through cleanly?ā Thatās where I would like to be in a developer world, of not have to have that stop because of an error and that cold start problem again.
[54:18] Right. Yeah, if reproducibility is the biggest time-sink for us, and like the one that you have to work through, if you can provide that, you can reduce the time to reproducibility, and provide an option to like just replay history with this code, versus the code that currently existsā¦ I mean, youāre gonna save a lot of people a lot of time. And so thatās great. I hadnāt seen this before.
Yeah. Do you want to just give people context or what Replay is, Eric, and if itās available outside of the React world, orā¦?
I unfortunately donāt. Itās one of those tools to where youāve got to invest the time into researching it. But itās only been ephemeral, of like ā I brought up the Tim Neutkens quote earlier, and it just struck a chord with meā¦ Like, yes, super-complicated bug that would have been days to reproduce - I spent some time over at AWS, and every customerās environment is different. And because of that, the way one thing behaved would be entirely different from something else because of some statefulness of their specific backendā¦ And itās like āIf only I could see exactly how their backend was configured, Iād be able to figure this out.ā
So I think thatās kind of like the thing, is that having ā like, Kball mentioned, where Iām at now is similar to where we used production data, with like a low ā and thatās been fantastic. So if that were extended even further, it would introduce time and recording into production, like real data with local files, that would be my sweet spot for just day to day work. And naturally, part of that is like debugging.
Yāall remember back in the day when Redux first came out, I think the biggest kind of a-ha was the time travel debugging feature? And I heard this straight from the maintainersā¦ Itās funny, actually, Mark Erikson, as well as Brian Vaughn from the React team, and Mark Erikson, both friends of mine now work at Replay, the startup that youāre talking aboutā¦ But Mark is one of the maintainers for Redux, and he mentioned that surprisingly, not that many people took advantage of time travel debugging, despite it being the thing that people were most excited about, because it gave that predictability of like your state and being able to replay it. So yeah, Iām curious to see if ā I think maybe Replayā¦
Did he say why that was the case? Maybe it was too hard to do, orā¦?
I think config, setupā¦ The pipeline around kind of, okay, once you capture the replay, how can you see it? I think Replay, the startup, is actually kind of smoothing that experience out.
Right. Thatās what theyāre trying to do.
Yeah. So if they make it a service, Iām excited to see if thereās more adoption around it.
Yeah, because a mixed app with that has more than Redux wouldnāt get to benefit from time-travel debugging; only the state from the Redux store.
Right.
I think thatās kind of the problem, is that itās kinda like betting on the web and betting on the environment weāre in; all the statefulness that really matters is there in the browser, is there when youāre doing that console.log or your debug. So if the statefulness is managed there, thatās the ideal, irrespective of how my app looks today in Redux, versus MobX, versus Prisma, or whatever else the next iteration is.
Well, and this is pointing towards something that might be worth touching on, which is writing code that is debuggable. And one of the biggest sources of challenge, as weāve highlighted, is reproducibility. Reproducibility has to do with state. You have to get this thing, whatever it is, into the state that reproduces the bug. The more that you can separate state from functionality and implementation, and have your state encapsulated, and then have your functions encapsulated - and this is pointing towards functional styles of development, this is pointing towards declarative development, which was a direction weāve kind of moved in for a lot of web frontend stuff at leastā¦
[58:08] But the more you could separate those things out, so that you can test your logic independent of your state, and pass in all sorts of different states, and the more that you have state in a place that itās easy to snapshot it and replay, or do things like that, the more debuggable your code is going to be, and the easier all of this is going to be.
Well said. Alright, we are hitting up against our time hereā¦ Eric, thanks so much for coming on the pod today. Weād love to have you back anytime. You donāt need to wait for Amal, or another debate episodeā¦ Just give us a holler if youāve got something to talk about. Weād love to have you on the show more often. Where can people connect with you? Where can they get to know you, talk to you etc. on the internets, besides going to Texas and finding your house? I mean, that would be weird.
Just over barbecue, or somethingā¦ Yeah, Iām still on the Twitters, @EricClemmons, so just my full name. Otherwise, the GitHub, andā¦ But yeah, Twitter is the best place to ping me.
Sounds good. Amal, Kball, thanks for debating with us as masterfully as you always do.
I donāt like debates, but this was fun. I donāt do well with time pressureā¦
Hey, I meanā¦ On this debate we won, you won, the listener wonā¦ We all win. It does get any better than that. Maybe because itās Friday, weāre recording on a Friday and Iām just feeling gracious today. Iām just allowing others to finally get in on the good, good wins that I usually rack up. The only person who lost today, letās be honest - it was Nick Nisi. Because a) he didnāt win the debate, and then b) we barely mentioned [His beloved TypeScript]. Soā¦ Thatās two losses for Nick, which is a good note to end on.
Iām Jerod, this is JS Party, on behalf of Amal, Kball and our guest, Eric Clemmons, thanks for listening. Weāll be back next week with an awesome episode, Iām sure. So stick around, and weāll talk to you all on the next one.
Our transcripts are open source on GitHub. Improvements are welcome. š