Reduce cognitive load for readers of your code by avoiding nesting of closures

Kent C. Dodds
InstructorKent C. Dodds

Share this video with your friends

Send Tweet
Published 3 years ago
Updated 2 years ago

It's important to reduce the amount of trivial things readers of your code have to think about so they can reserve their brain space for more important things. Avoiding nesting of closures can help you accomplish this. In this lesson we'll get a quick look at the concept and how it can help reduce cognitive load for readers of your code.

Instructor: [0:00] Here we have a function called getDisplayName that takes a first name and a last name as an object, presumably some user. The goal is to return a display name where the first character of the first name is uppercase and the first character of the last name is uppercase.

[0:15] If I come across code like this, I'll typically refactor it to pull the upper first character out of the original function like this. The reason that I do that is because it reduces the cognitive load by taking this closure and moving it out of a closure where it has access to variables that it doesn't need.

[0:34] For example, this upper first character could have access to the first name and the last name. I have to inspect the function itself to know whether it's using those variables and whether changing those variables is going to require that I change the implementation of this function. This is a pretty simple example, but if we had a bigger function, then that cognitive load is not worth the wait.

[0:56] It'd be a lot better just to move it out. When it's moved out like this, now all that I need to worry about for this function is anything that it accepts as parameters, anything that it defines as variables inside of itself, and any module-level variables like if I were to define another function, foo hi, whatever.

[1:16] Now I need to worry about whether foo is being used inside of my function, but I would need to worry about that anyway even if it were inside of this nested function. What I'm getting by extracting it is reducing the number of things that I have to think about when I'm maintaining that particular function.

[1:31] There are other arguments for doing this as well. For example, every time getDisplayName is called, we're going to be creating this function and closure, but that argument doesn't really hold water because you would have to call this function like millions of times to even run into any problems there because JavaScript is pretty fast at defining functions.

[1:49] Another argument that I hear people say is it's easier to unit test these types of functions. You can export them and then test them in isolation. This particular function is so simple that I would probably just get my coverage for that function by testing the getDisplayName directly, but that could be a pretty good argument if this function is pretty complicated.

[2:06] I've got to mention that sometimes it's unavoidable to have nested closures. For example, if I wanted to make an addThings here. We take an additive and then a bunch of numbers. Then here we're going to have our add function that takes a number and returns n plus the additive.

[2:23] Then we're going to return add. Presumably, we call this with addThings. We wanted to add three to one, two, three, and four. That should get us back four, five, six, and seven as an array.

[2:39] In this case, I have have this function I'm defining inside of addThings, but I can't extract it because additive is defined as a parameter for addThings. I could add an additive argument here. Then I guess I'd have to call add. Let's see. We'd have that number and then add number and additive.

[3:02] I'm looking at that and thinking that is way more complicated than what we had before. We don't need to be religious about this whole nesting closures thing, but it can be really nice when it's reasonable to do. It's just something to keep in mind as you're writing your code.