Kent C. Dodds
Kent C. Dodds is a world renowned speaker, teacher, and trainer and he's actively involved in the open source community as a maintainer and contributor of hundreds of popular npm packages. He is the creator of EpicReact.Dev and He's an instructor on and Frontend Masters. He's also a Google Developer Expert. Kent is happily married and the father of four kids. He likes his family, code, JavaScript, and Remix.
Full Stack Components
Remix Conf Europe 2022Remix Conf Europe 2022
37 min
Full Stack Components
Remix is a web framework that gives you the simple mental model of a Multi-Page App (MPA) but the power and capabilities of a Single-Page App (SPA). One of the big challenges of SPAs is network management resulting in a great deal of indirection and buggy code. This is especially noticeable in application state which Remix completely eliminates, but it's also an issue in individual components that communicate with a single-purpose backend endpoint (like a combobox search for example).
In this talk, Kent will demonstrate how Remix enables you to build complex UI components that are connected to a backend in the simplest and most powerful way you've ever seen. Leaving you time to chill with your family or whatever else you do for fun.

Remix Fundamentals
React Summit 2022React Summit 2022
136 min
Remix Fundamentals
Free Workshop
Building modern web applications is riddled with complexity And that's only if you bother to deal with the problems
Tired of wiring up onSubmit to backend APIs and making sure your client-side cache stays up-to-date? Wouldn't it be cool to be able to use the global nature of CSS to your benefit, rather than find tools or conventions to avoid or work around it? And how would you like nested layouts with intelligent and performance optimized data management that just works™?
Remix solves some of these problems, and completely eliminates the rest. You don't even have to think about server cache management or global CSS namespace clashes. It's not that Remix has APIs to avoid these problems, they simply don't exist when you're using Remix. Oh, and you don't need that huge complex graphql client when you're using Remix. They've got you covered. Ready to build faster apps faster?
At the end of this workshop, you'll know how to:
- Create Remix Routes
- Style Remix applications
- Load data in Remix loaders
- Mutate data with forms and actions

Server-side Auth with Remix, Prisma, and the Web Platform
Node Congress 2022Node Congress 2022
34 min
Server-side Auth with Remix, Prisma, and the Web Platform
In this talk, we'll get a live coded demo of building custom hand-rolled authentication. When you have the right tools (and we do), authentication can be quite simple and secure. This is more (and better) than just: "Install this library and you're good to go." When we're done we'll have our own auth code that can evolve with our ever-changing requirements without a need to learn some library-specific APIs. We'll be leveraging the Web Platform the way it was meant to be done to give us simple and secure server-side authentication for the web.
You can check the slides for Kent's talk 
 as well as 
demo code

Don't Solve Problems, Eliminate Them
React Advanced Conference 2021React Advanced Conference 2021
39 min
Don't Solve Problems, Eliminate Them
Humans are natural problem solvers and we're good enough at it that we've survived over the centuries and become the dominant species of the planet. Because we're so good at it, we sometimes become problem seekers too–looking for problems we can solve. Those who most successfully accomplish their goals are the problem eliminators. Let's talk about the distinction between solving and eliminating problems with examples from inside and outside the coding world.

AHA Programming
React Summit Remote Edition 2020React Summit Remote Edition 2020
32 min
AHA Programming
Are you the kind of programmer who prefers to never see the same code in two places, or do you make liberal use of copy/paste? Many developers swear the Don't Repeat Yourself (DRY) philosophy while others prefer to Write Everything Twice (WET). But which of these produces more maintainable codebases? I've seen both of these approaches lay waste to codebases and I have a new ideology I would like to propose to you: Avoid Hasty Abstractions (AHA). In this keynote, we'll talk about abstraction and how you can improve a codebase applying and creating abstractions more thoughtfully as well as how to get yourself out of a mess of over or under-abstraction.
Hi, everyone. My name is Kent C. Dodds and I am super excited to be talking to you virtually. I hope that you're all healthy and happy and doing well. And I'm excited to be talking with you about AHA Programming. So go ahead and take your DRY and your WET programming principles, set them to the side for a little bit and let's talk about Avoid Hasty Abstractions, AHA Programming.
So I've got some links in here that might be interesting to you, like my slides. And I'm coming to you from Utah. I've got a wife and four kids and a dog and they're awesome. I've got a website on the World Wide Web and, in particular, testing If you haven't tried it already or looked at it, definitely give that a look. It'll teach you everything that I know about testing, which is not a small amount. And is going to be even bigger, such a huge amount of content that will be available to you at in the very near future. So look forward to that. Take a look at the rest of this stuff later. Let's go ahead and get into this.
Live coded contrived example of the lifecycle of an abstraction
[01:28] So this is what we're going to be covering today. This is a live coded contrived example of the lifecycle of an abstraction. So, hopefully, you can relate to this, even though it's a little bit contrived, but I think that you'll enjoy it nonetheless. And we're going to be considering what's important and why it's important to be thoughtful about an abstraction. And we're, basically, going to be taking this story ... Oh, it's an actual example of a story told Sandi Metz in this blog post around Wrong Abstraction that I strongly advise you take a look at.
We're not going to be going through slides. Most of this is in my text editor here and it's not passively consumable. So you need to decide right now whether you're going to be focusing on Twitter or on my talk, because you won't be able to do both very effectively. So just choose. I'm not offended.
[02:17] So here we are in 02.js and I'm going to be using a tool called Quokka.js. It's an extension for VS code and, among other things, it allows me to console.log in here and it will show in blue what the value of that log statement is. And so that, we're going to be using quite a bit.
So we have an application and we have a user object here. This is Phil and Phil has a name and a username, and in three different places of our application, we've got code for pulling that user's username for the first and the last name. So this is their "Display Name" that we're going to be displaying throughout the UI of our application.
[02:54] Now, you may notice we actually have a bug in here and this is our first part of the abstraction. Here, we're saying "Philip undefined," but Philip's name is Rodriguez, that's his last name. And he is frustrated that it says "Philip undefined" when he logs into our app. And so we've been given the task to fix this problem. And when I was working at a company before, I remember they would say, "Hey, we've got this bug on this page." And so I'd go fix it. And then the QA manual tester over there would say, "Hey, Kent, I thought you said you fixed it." And I said, "Yeah, I did." He said, "Well, it's broken over here." "Oh, shoot. Yeah. I guess that was copy pasted. So let's go fix it over there too." And it was a real pain.
So we build abstractions so that we don't have to fix the same bug in lots of places. And we have three places where we're doing the exact same thing. So rather than fixing the bug right here, how about we just make an abstraction and we fix it in that one place and then all of the other places will get that fixed automatically.
[03:51] So let's go ahead and do that. I'm going to make a function here called "Get Display Name." We'll take a user and then we'll return this and we'll generisize it so we'll take that user, get the name and, instead of the "First and last," we'll do "First and last." So let's go ahead and we'll replace all these with "Get Display Name" for Phil and then we'll fix it in this one place last. Ta-daa, and all of the places were fixed.
We're really happy about this because it means that we don't have to fix it in all of the other places. We just fix it in this one place. And if we ever want to make changes, we can just make changes to this one function, which is awesome.
[04:32] Well, as it happens, we do actually need to make some changes. And that is if the profile page we decide, we want to include the "Honorifics." So let's say Dr. Philip Rodriguez is, "Hey, it would be really cool if my profile page says I'm a doctor. I went to a lot of schools. So I want people to know I'm a doctor."
And so the product manager comes to you and says, "Hey, we want to add the 'Honorific' to the profile page, the display name there." And you say, "Okay, cool." So you come to code and you're, "Oh, yeah, I wrote this abstraction for this." So because the abstraction exists, our natural inclination is to go into the abstraction to enhance the abstraction to support the new use case and also just to see if it already supports the new use case. So we're just naturally inclined to go to the abstraction first and we see this and we see, "Oh, there's no support for 'Honorific' so I could either remove the abstraction here or add that use case to this existing abstraction. And it's just really natural for us to prefer to use the existing abstraction for various reasons. Maybe we think that other people might benefit from this extra use case, or maybe we just feel, since we're already using the abstraction, I don't want to walk away from all of the benefits the abstraction gives me. And in a real world scenario, that could actually be quite a bit. And so you wouldn't necessarily want to just remove the abstraction just for adding one feature.
[06:00] So it seems a lot easier to just enhance the abstraction to support the use case. So that's what we're going to do. And what we'll do is we'll take "Options," but not everybody's going to pass "Options," right? So we're going to default that to an object. And I don't want to just call this "Options." We'll de-structure this and we'll just take and include "Honorofic" and we'll default that to "False." We don't want to break existing users of this abstraction. So we'll say "Include honorific here." We'll grab a "Display Name" and return the "Display Name." So that's just a regular re-factor. We haven't changed anything yet. Now, we'll take that "Display Name," and if there's "Include Honorific," then we'll say the "Display Name" is what it is. We'll put that in a template literal there, but we'll include the "Honorific." So we'll say "" Great. And then down here in the profile page, we can say "Include Honorific?" "Yes." And boom, we've got it. We're super happy about this. We commit that, we get it reviewed and people are, "Wow, cool." We re-used the abstraction.
Now look at all the power that we've got with this abstraction. Let's go ahead and write a couple of unit tests to make sure that we don't break this feature that we've added. And we move right along and, in the future, somebody comes around and says, "Hey, we need to support a username for the user card. So we want it to say their name and then in parentheses their username. And so you say, "Okay, that should be pretty straightforward." We go to the abstraction again, we see that's not supported. And rather than removing the abstraction from our code, we're going to add this feature to the abstraction, but we don't want to break the existing stuff and so we're going to touch as little as possible. And we'll just add another option here for "Include Username." And we'll default that to "False," because we don't want to break existing users of this abstraction. And we'll say "If include username," ... Except you've got to spell it correctly otherwise it won't work. And we'll say the "Display Name" is the "Display Name" as it is currently and then parentheses and then whatever the username is. So user.username. Great. And then down here we can say "Include username." "True."
[08:14] Perfect. This is exactly what they wanted. We were able to encode that into the abstraction and we add a couple of tests to make sure that this is supported. And actually in the process of adding tests, we realize that there's some combinations of these options that we don't actually support or we don't actually need in our code base, but our abstraction supports. And maybe we realize that maybe we don't, but we know that those use cases are supported where you could provide both of these as "True." And so we add tests for that just to make sure nobody breaks that existing feature so in case anybody might want to use that feature in the future.
And so it's not too complicated. It's a pure function. It's really easy to test. And so we go ahead and add a test for that. And then later on we get another feature request for this code and they say, "Hey, our navigation, we want that first name to not be a first name, but to be a first initial." And so you go back to the abstraction, you say, "Okay, that's not supported today." I don't want to lose the benefits of having the abstraction. It's well tested. And so I'm just going to add my stuff here, but I don't want to break anything that already is there. I don't want to break existing codes. So I'm going to take a first initial. We'll default that to "False," so existing users of this abstraction aren't broken. And we'll take that first initial as an "Option." And we'll say, "If the first initial ..." Then we want the first name to be just the first initial.
[09:40] So what I'm going to do is we'll take this out. We'll just call this "First" and we'll actually assign that to a "Let" here for "First equals username first." And then if the first initial is "True," then we'll say, "First it's actually going to be equal to the First," and we'll slice off the first character and add a dot. Okay, cool. And then we can come down here and say "Include ..." Or actually it's a, "First initial is True," and boom, we've got all of these use cases supported our abstraction. We add a couple more tests in here and we're really happy with this.
And there are two things I want to call out about this: First off, we now have three uses of this abstraction and maybe there are more throughout the code base, but these three don't look anything alike. They have nothing in common with one another other than the fact that some of them show the first and the last name, but each one of them has very distinct differences from the others. And so this is actually pretty common to happen to abstractions is that eventually the abstraction evolves beyond the initial use case and that's not necessarily a bad thing, but all of the use cases have diverged from each other pretty significantly. And so even though our abstraction supports so many things, they actually are supporting use cases that aren't entirely related to one another.
The other problem with this is, as we're writing tests for this, we're going to be writing tests to support use cases that we don't actually have. And while that's maybe not a terrible thing, here's a problem with that. As we write all of these tests to test use cases, when we come in to re-factor this, if we want to make improvements to it, then we have to make sure that our re-factorings support everything that our tests say our abstraction supports.
[11:30] But the only thing that cares about that use case is the test. So it exists for itself, and that is super useless. The test is intended to make sure that the use cases that you need to support are continuously supported. And if the only one who cares about it is not the users, but the tests, then just delete the test and now nobody cares about it.
And so thoughtlessly adding features to this abstraction, we wind up in a really hairy situation and it doesn't stop here. No, we've got some more to do. What if the profile page no longer wants the "Honorific?" So we're, "Okay, that's fine. We can just remove the 'Honorific.'" Boom, it's gone. We're happy, we save this, commit it, push it, it's merged. We're happy about this because all it took was removing that option. And this is what normally happens. And we don't actually think about pulling out the "Honorific" option and getting rid of the code that's specific for the "Honorific." Or maybe we do think about that. And there are a couple other reasons why we might not want to remove it. For one thing, the cost of keeping it in place is pretty low, or it feels low. And the risk of removing it and accidentally breaking something, that actually feels high. And so with that cost versus risk analysis there, we just decide, "Oh, let's just keep it in there. I don't want to break anything." We do this a lot with CSS in particular, like global CSS.
[12:54] I'd much rather add something new than modify something existing or, heaven forbid, delete something existing, because it's so hard to identify if really that's being used. And then there's always the lingering thing in the back of your mind, like maybe someday we'll want to include the "Honorific" in the future. So we'll just leave that feature and then nobody will have to make any changes to support that use case in the future. And that also is problematic because we have Git and we could go back and look at what the code was at that time.
So it is not a costless thing to leave this code in place because we have to maintain it as we make refactorings to it if we leave it in place. And the only one who cares that this code exists is the code and the test itself. So if we remove them, then nobody cares and that's fine.
[13:45] So we're not quite done though. What if our user card here, instead of the first and last name they decide, "Hey, I actually just want to show the last name." Now, doing that with what we have here is actually really easy. We just remove the abstraction and then we just say. "Phil.username." But because the abstraction exists, it just draws us in and we think, "You know what? Instead of "Include username," I'll have an "Only username." And then up here I'll accept that "Only username," We'll default that to "False" so we don't break other people. And I don't want to touch any of this stuff. So I'm just going to add this here to the bottom and say "Only username. Display name equals user.username."
And there we go. We've got support for this new feature and we have now two options that nobody cares about except for the code itself and the tests that were written to make sure we don't break those use cases.
[14:40] So we've wound up with an abstraction that's actually quite a bit more complicated than it needs to be and we can re-factor it, but we've got all these tests now that are making sure that we don't break these use cases that we actually don't care about. And so it's just become a tangled mess. And this is a pretty simple function. It's just concatenating the strings together. Think about your complicated React components or your Angular components or whatever it is that you're writing and all of these different abstractions that you've built around this stuff, and it's pretty easy to build yourself up into an abstraction that's just scary to work with.
How to avoid building scary abstractions
And so how do we avoid this problem? Or how do we back out of this problem when we're in it? And this is something that Sandi Metz talks about in her blog post The Wrong Abstraction. I really advise that you take a look at this because it's really great. And she has a talk here that you can give a watch to. But, in here, what she says is that, "The fastest way forward is back." So the idea is first you reintroduce the duplication inlining and then with each color you use the parameters being passed to determine the subset of the inline code that's specific for the colors, what the color executes, and then delete the bits that aren't needed for that particular color. And so, in this case, that, basically, means we'll make three copies of "Get display name," and inline it into each one of these and then remove the pieces from each one of those that are no longer needed.
[16:07] So let's just walk through that really quick. What I'm going to do is console.log right here. And I just need to have a console.log right here that's the same as this one. And ours is pretty simple. So I don't really need to make a separate function. I'll just look at the function and grab the pieces that I need. So here we just need the first initial and then the last name. So that's, pretty much, all this code that I need for this. So what I'll do is I'll grab this right here. We'll put it right there and we're going to get the first from "" Okay. So that's getting our p-dot and then the rest of this is right here. So let's grab that. And instead of "User" that's going to be "Phil."
Okay, those two things are the same. So we can grab this now and put it in place of the abstraction. Now, this situation, or this navigation file, is no longer using the abstraction. And we could come in here and delete the stuff that's not being used anymore, but let's keep going and inline the abstraction into all the places where it's used and then we can remove it.
[17:11] So the next one is just the first and the last name. And so that is right here ... Or, no, it is this part right here. So let's just grab that. We'll add a console.log right here. And the first is going to come from a "," and this is going to be "" And we're going to need to put that in a template literal there. There we go. Cool. And that's exactly what we need. So we'll just replace those. Get rid of that. And now we've removed the abstraction from that one. And then for our last one, it's just the username, and all that we're using from the abstraction for this is just So we'll come down here and that's so easy. I'm just going to say, "Phil.username." There it is. We have the exact same thing that we had before. And, as it turns out, we can remove this whole abstraction. It's gone from our code base. That really big, hairy, scary thing that you were worried about is gone. And maybe you have it just all inlined like this. Or maybe that was a big component and you have four different copies of the same component that are just slightly different for each use case.
Now that you have those four different copies, you can see the similarities between some of them and maybe there are two different categories of that same abstract and there's the one that shows the dropdown and then there's the category that doesn't. And so we'll just keep those as separate things, whatever the case may be. But, because you've done this, you're able to identify the commonalities between the different abstractions and the differences. And in your current state in building this today, you're a lot more able to create an abstraction that works for what we have today. And because you've experienced ... You have some battle scars on bad abstractions, you're more thoughtful about the abstraction that you're making.
[19:02] So with all of this, I just want to wrap up with a couple of takeaways: First off, Do not Repeat Yourself, or DRY, that's not necessarily a bad thing. Do not Repeat Yourself in theory is a good idea because it does allow us to get rid of some business logic bugs in one place, or just even some typos if you're not using TypeScript, but it can really help you avoid some duplication. Duplication is not inherently bad, but it can be a problem and it can just propagate a bunch of bugs all over the place. So Do not Repeat Yourself itself is not necessarily bad.
But the key here is that you can't tell the future. So the only thing you should really be optimizing for is change. So one thing that Sandi Metz talks about is, "Duplication is far cheaper than the wrong abstraction." So preferred duplication over the wrong abstraction. I agree with that wholeheartedly and I think that, as you duplicate things and just wait for commonalities in that duplicate code to scream at you for abstraction, then those abstractions become so much more obvious for you and you can build out the right abstraction for the use cases that you have present for you at the time.
[20:15] So as you're building out stuff and you have all these ideas like, "Oh, cool abstraction here. Cool abstraction there," just keep duplicating stuff, copy, paste, move it around, and then once you're all done, you can see what you have and you see the commonalities and be, "Oh, actually these two things are not as common as I thought they were when I first wanted to abstract them. So I'm glad I didn't. We'll just leave them as separate things." Or, "These two things are really common. There's just three things that I could parameterize," and then you can make an abstraction for it.
If you have shared code with lots of branches, then I recommend to you to resist the urge to add more conditionals to it and instead re-factor it first. And go and learn everything that you can about the users of that abstraction. And maybe there's something that you can learn about the abstraction as a whole so that you can maybe split the abstraction up into multiple pieces that will be easier to manage themselves.
[21:11] So I've got a couple resources for you: Sandi Metz gave a talk that is really good around this same idea called All the Little Things. Definitely give that a look. And then the blog post, of course, is also great. And then I have a blog post about this concept, AHA Programming, you can and check out on my blog and I have a testing variant of that, as well. And yeah, follow me on Twitter because I tweet things. Thank you very much. I hope you have a wonderful time at the conference. Stay happy, stay healthy and subscribe. Thank you.
[21:45] Jason Lengstorf: All right. That was excellent. Kent, as always, that is a wonderful talk. If you are new to the AHA Programming concept, I think it's such a cool thing. I always love seeing what Kent does. And so now let's bring Kent back to the stage and we will do some Q
A. We've got some great questions in the Slack. Kent, welcome back.
[22:09] Kent C. Dodds: Thank you. Thank you. I'm so excited to be here and I always enjoy spending time with you, Jason, and our 4,000 friends or however many people are watching right now.
[22:20] Jason Lengstorf: Yeah, I think we're up above 4,000 right now on the live stream. So, holy crap. So I had a question because actually I've been following you for a long time and I remember the origin of AHA and so I'm going to put you on the spot a little bit. But AHA wasn't always called AHA. So can you talk a little bit about the origins and how you got to now?
[22:44] Kent C. Dodds: Yeah. So AHA was my frustrations with DRY programming as a practitioner early on and I learned about Do not Repeat Yourself and how important it is that you create abstractions for things. And then I found out what ... I think most people find out with that is eventually the abstractions you create are really bad. And then I heard about WET programming, which is Write Everything Twice. And I was frustrated that, as well, because then you have to fix bugs in multiple places. And so I just thought they were both way too dogmatic. And so I decided let's just be more mindful of the abstractions we make and then everything will be better, hopefully. And so in the process of writing a blog post about this, because I have to write a blog post about everything that I think of, I decided, "Okay. Well, it's not DRY. It's not WET. What's not those things? I guess, it's moist." And so that's what I called it at first, was Moist. And I don't really like the sound of that word and I know a lot of people see it really cringy, but I was, "Hey, it's okay." And I couldn't really think of what that could stand for. So I didn't even make what that acronym is. And I tweeted about it and I got so many people, "That is so gross," or just laughing hysterically about it. So I was, "Okay, okay. I need to come up with a different name." And Cher Scarlett gave me a perfect name, and AHA, Avoid Hasty Abstractions. It was perfect. And it's light bulb moment. I love it for every ... It's just the perfect acronym. So that's where that came from.
[24:30] Jason Lengstorf: Ah, that's great. You briefly mentioned this, but I want to talk ... Well, actually, you know what? You answered it. I'm not going to talk. You talked about the difference between DRY and AHA. So let's go to the Slack and someone asks ... There's a great question here: "How do you implement this project-wise? If you were going to roll this out into a given project, how do you work that into your process?"
[22:54] Kent C. Dodds: Oh, that's such a great question. I think that it's so tempting when we're ... If you're starting a brand new project or you're coming into a project and you're, "Wow, look at the mess of abstractions that we've got here," or whatever, it's just so tempting for you to instantly want to architect the entire thing from the very beginning. And that is an enormous mistake to make. You automatically ... You have a code base of 3000 lines of codes so far and you are architecting it for a three million line code base. You're going to wind up in bad abstractions and you'll never make it to that three million line code base. So it's not one that you want to work in.So I recommend just taking a really iterative approach. Don't worry about duplication. And if you come into a code base and it's got bad abstractions, then what I talk about in the talk and referencing Sandi Metz there, inline those abstractions, and then you can just pretend that it's always been this way, and you're, "Oh, wow, there's an abstraction just sitting here for me," but it'll be totally different from the bad one that you inlined before. So, at least, hopefully, it will be. But that's what I'd recommend, is just be really thoughtful about the whole process. Don't try to architect your whole application for something that it's not today.
[26:14] Jason Lengstorf: So a question here that is, I think, ... "In the context of an abstraction, do you feel abstraction should not be extended? Or would it be better to just extend it and see what happens until you end up with three to four functions and then change?"
[26:32] Kent C. Dodds: So maybe I'm not totally understanding the question, but my thought process normally, and this is something that I really had to fight for, but as I'm working on some code, before I've committed anything, I'm just toying around with stuff, I am constantly thinking, "Oh, this looks a lot like this and so let's just put that in a function." And I really had to fight myself and say, "No, no, no, no, no. Don't do that yet. Just copy it." Even if it's five lines of code, it seemed so duplicate, just copy, paste that because eventually you'll find out one of two things: You'll either find out that you didn't need it at all in the first place. And so taking the time to make the abstraction, create the variable names and genericizing that function was a waste of time anyway. Or you find out that they weren't as similar as you thought they were. So I don't know if that answers the question because maybe I misunderstood it, but that's just-
[27:27] Jason Lengstorf: Well, I'd like to follow up on that actually. So when you say that you realize that they're not as similar as you thought they were, do you have an example? Because I feel that's one of those things that it's easy to say in the abstract and hard to put into concrete terms. So if somebody's thinking about this, when's the case when the same code that you've copy pasted isn't as similar as we think it is?
[27:52] Kent C. Dodds: Yeah. That's a great question. So an example of this that I just experienced recently, and especially it's a React conference, so a React example, I had a "Login" and a "Register" button, very similar, just different words or different Reo labels for the modal, they pop up, different colors and stuff. And I thought, "These are really similar. I could make a React component, just take a couple of props. But I've held off, and I found that if I were to make a component for this, there would be so many little props that are this is what the Reo label should be. This is what the title of the modal should be. This is what the type of button it should be. And I just don't see that type of an abstraction being any simpler than the duplication that I have instead. Each one is six or seven lines of code. Now, there is a little piece in there that the modal that it pops up has a little "Close" button that is styled specifically for the "Login" and "Register" modals. And so all I did for that was I just extracted the CSS for it because there's no variables or anything ... Or not the CSS, but the JSX for it. So I just created a JSX element and then I inlined that element as a variable. And so I'm able to take that little piece of commonality without making it a whole function component that has 12 props on it.
[29:17] Jason Lengstorf: That's a really interesting distinction too, because in both cases you're talking about code that would visually look the same, what shows up in the browser, it visually looks the same. It's a "Close" button or it's a registration form, but the implementation is where the difference starts to come in. If you have to change every part of those attributes, you're not really writing an abstraction, you're just giving yourself chores.
Kent C. Dodds: Yes, yeah. Exactly.
Jason Lengstorf: Yeah, that's-
[29:42] Kent C. Dodds: Anytime you want to make anything that makes them slightly different you have to add another argument, another prop and it's just more homework for you. And, at the end of the day, what you end up with is either copy pasted JSX that's just two copies of almost the same thing. Or-
Jason Lengstorf: Right.
Kent C. Dodds: ... a function component that you're calling ... That is almost the same amount of lines of props. So what are you buying yourself there? Not much. Just chores.
[30:10] Jason Lengstorf: Totally. Totally. Okay. So another question, just following that, "Is the cost of a bad abstraction usually much worse than that of duplicating the code in tests and possibly duplicating bugs?" What's your experience with that then?
[30:27] Kent C. Dodds: That's a great question. And it's pretty nuanced because like, I don't want anybody coming away from my talks saying, "Oh, Kent likes duplication. He hates abstraction." That's absolutely not the case. As a library author, clearly, I make many libraries and I see the value of abstraction. I just see there comes a point where the duplication becomes a real problem. For this "Login" "Register" example that we just shared, that duplication, it's right there, and if there's a bug in one, it's really easy to just fix the bug in the other. Not too much of a problem. But if you find yourself duplicating over many, many files, then maybe there's a good case for an abstraction there. So I can't give you a rule because there is really no rule about this. It's all just nuanced and ... Sorry. That's not very helpful, but hopefully, the talk was.
[31:23] Jason Lengstorf: No, I think that's great. And with that, we are going to start moving on. That's all the time we've got. Kent, thank you so much. It's always a pleasure and we'll see you-
Kent C. Dodds: Thank you.
Jason Lengstorf: ... in the Slack.
Kent C. Dodds: All right. See you.

Kent C. Dodds: Consume, build, and teach — and level up your career
14 min
Kent C. Dodds: Consume, build, and teach — and level up your career
Even though his bio offers quite a hefty reading, he only applied for one job in his career. The rest came along as he was building his name as a renowned speaker, teacher, and a prolific figure of the open-source community. How did Kent do it? “Commit to creating high-quality content,” he says.
What led you to programming?
I had a friend when I was a teenager who was really into it, and he tried to teach me. But I just couldn't get it — it didn't make any sense to me. So I never really thought I'd get into programming, but I liked computers a lot, and I ended up going to school for electrical engineering. 
Well, that didn't work because I'm not good at math. But right when I started the program, I got a job at a company uploading videos to YouTube and that sort of thing. The work was tedious, so I decided to write a computer program to automate lots of the work I was doing with the knowledge I had about programming. And that was the first spark of things for me to use programming to solve real-world problems. 
What is the most impactful thing you ever did to boost your career? 
Committing to creating high-quality content. That might sound obvious because I'm a full-time educator now, but I would not have gotten my job at PayPal if I hadn't been so active with my blog. In fact, lots of my jobs came out of me being involved in the community around meetups, conferences, or open-source projects. 
How do you choose topics for the content you create, be it for your blog or podcast?
I don't think too much about the content other people are creating. And I don't often consume it. My ideas come from the things that I'm working on, things that I'm learning myself, or — when I was working with a team of developers — the things that I had to remind people of in code reviews regularly. Anytime that I would have a code review comment that was pretty long to describe my position, that was an excellent opportunity for a blog post. Also, if people ask me about a topic regularly, I'll make a blog post rather than answer that question multiple times.
What would be your three tips for engineers to level up their career? 
The number one thing I tell people is to be a nice person. I know that sounds fluffy or silly, but it cannot be overstated. You will get so much further in your career and just in life in general if you're a nice person. That doesn't mean that you take people being jerks lying down, but how you interact with others is out of kindness. You could be the best engineer in the entire world, but if you're not a nice person, you will not reach your full potential or accomplish your goals, whatever they may be.
Second, it's just as important to decide what you are not going to learn as it is to decide what you are going to learn. You could jump into countless things — and there are successful people who are polyglot programmers, but I can't speak to that a whole lot. All I can tell you is that in my experience, focusing on specific things that I want to be truly good at has worked out great for my career. That doesn't mean that I closed myself off to other things. With my
website rewrite
, I have been doing a lot of dev ops-related work and a lot of back-end stuff that I've typically not been involved in. You want to keep your head up on what's going on outside of what you're doing so that you know what direction to go in when you come across problems you need to solve. However, finding a focus on what you want to be good at has helped me a lot. That way, you feel a little less stressed.
And the third one? 
Learn how to learn effectively. It's a three-step process: you consume, build, and teach. The consumption of newsletters and Twitter and whatever inspires you, but you don't want to spend too much time doing that — implementing it into actually building something matters. This happens naturally if you work at a company, but maybe you're not making the things you want to learn, so you may want to start a side project. The building phase is where you get experience, but you also want to solidify that experience. How? You start teaching. You don't necessarily have to teach it to people, it could be stuffed animals. The goal of the teaching is to retain in your mind what you've learned through the building process.
What are you working on right now? 
The big thing I'm working on right now is a rewrite of my website. It'll be much more than just a developer portfolio — I'll have user accounts, and there'll be fun things that you can do with it. And because it's more than just a website, I'm using
, a new cool framework in the React ecosystem. I'm also working on updating my material on
and a TypeScript course as well. 
So, whatever I'm working on, it ends up resulting in lots of opportunities for content.
Do you have some rituals that keep you focused and goal-oriented? 
I have a notepad where I keep all of my notes of what I'm going to do for the day so that when I'm checking things off, I'm not distracted notifications. I've tried apps for that, and that does not work well for me. 
I also am a firm believer in inbox zero. I have my work inbox and my personal inbox, and I keep them both at zero. And I kind of use that as a to-do list. 
And if I'm not feeling excited about working for some reason, I will often hop on my Onewheel, which is an electric skateboard that only has one giant wheel in the middle. It's just a total blast, and I'll hop on that with my backpack and a charger, and I'll go to a Starbucks or a park just to declutter my mind.
What things in the React universe are you excited about right now?
React version 18 is coming out soon. The experimental version is out there, and it's fun to play with. I'm just really thrilled that it's no longer a concurrent mode but concurrent features that you can opt into. Cool things like that will enable React server components in the future. 
But the biggest thing I'm excited about is Remix. That's huge. It eliminates a lot of problems that are solved well other tools, but when I'm using Remix, I don't have those problems, so I don't need those clusters.
You already said that teaching is an integral part of the learning process, and you stand your word since you're also a full-time educator. What inspired you to enter this field?
I have been a teacher for as long as I can remember. I grew up in a church where you talk in front of your peers from a very young age, and my mom was an elementary school teacher, so teaching has just always been a part of me. 
I really just enjoy sharing what I'm learning with others. As far as teaching technical topics, I gave my first workshop when I was still a student at Brigham Young University. With my fellow, we taught how to use AngularJS, and I got Firebase to sponsor pizza so they would show up, and that was pretty fun.
Then I started teaching on the side at
right after I'd graduated. That was when I first got a paycheck for teaching. And I realized that teaching could be quite lucrative and support my family and me as a full-time endeavor. So I did it — I quit my job. I'm a very risk-averse person, so I'd done teaching as a side hustle for four years just to verify that I could make this work.
When TestingJavaScript was released, and I got that paycheck, I realized that I didn't need my PayPal salary anymore. I could just focus my daytime on teaching and give my evenings back to my family, which was a nice trait.
Apart from that, how has teaching impacted your career? 
Earlier I mentioned that pretty much all of my jobs came because I was perceived as an expert. After the first job, where I was an intern and then converted into full-time, I never applied to another. I worked for four different companies, and they wouldn't have recruited me if they didn't know who I was and what I was doing. My content is how they knew who I was — I just made it easy for them to find me. Teaching made that impact. It made my career. 
We talked about React and Remix. Are there any other open-source projects that you'd recommend keeping an eye on or contributing to?
I have some myself. React Testing Library is probably the biggest one that people are familiar with. And if React isn't your jam, then other framework versions of the testing library. 
React Query is also really popular. If you're using Remix, you don't need it, but if you're not, I strongly advise using React Query cause it's a stellar, fantastic library, and Tanner Linsley, the creator, is a stellar and fantastic person. 
What pieces of your work are you most proud of? 
Probably the biggest thing I've ever done is
. It has helped tens of thousands of people get really good at React, improve their careers and make the world a better place with the skills that they develop. My whole mission is to make the world a better place through quality software, and I feel like I've done that best with Epic React. 
There are things that I've built at other companies that are still in use, and I'm proud of those cause they've stood the test of time, at least these last few years. But of everything, I think Epic React has made the biggest impact.
Follow Kent on Twitter
 and listen to his favorite 
Spotify playlist

Consume ➡️ Build ➡️ Teach
React Summit 2020React Summit 2020
29 min
Consume ➡️ Build ➡️ Teach
How do you level up? How do you jumpstart your learning when getting into something new? Nobody has more than 24 hours a day, so how do you maximize the impact of your limited time?
In this keynote, I'm going to tell you a bit of my own story, and some tips and tricks that I've learned so you can be as productive as you can be at learning new things and solidifying that knowledge so it's there when you need it.