Why You Shouldn't Nest Your Code
Summary
TLDRThe video script discusses the concept of 'never nesters,' programmers who avoid deeply nesting their code due to a strong aversion to excessive indentation. It explains the negative impact of deep nesting on readability and suggests two methods to reduce it: extraction, which involves breaking out parts of a function into separate functions, and inversion, which involves restructuring conditions to simplify the code. The script provides examples of how these techniques can transform complex, nested code into a more manageable and readable format, ultimately promoting better coding practices.
Takeaways
- 🚫 A 'never nester' is a programmer who dislikes deeply nested code, aiming to keep the indentation level low.
- 📈 The 'disgust-o-meter' for never nesters increases with each additional level of nesting in their code.
- 🔽 Nesting refers to adding more inner blocks to a function, which increases the depth of the code structure.
- 🚨 Never nesters consider a function with four levels of nesting to be the maximum complexity they can handle.
- 🔄 Two methods to reduce nesting are extraction (pulling out parts of a function into its own function) and inversion (flipping conditions and using early returns).
- 🔄 Extraction involves creating separate functions for parts of the code that are frequently repeated or complex.
- ↕️ Inversion involves flipping 'if-else' conditions and restructuring the code to prioritize the 'happy path' or successful execution.
- 🔄 Applying inversion repeatedly can lead to a validation gatekeeping section at the beginning of the code, which clarifies the function's requirements.
- 📚 The Linux kernel style guidelines discourage more than three levels of indentation, reflecting a preference for less nested code.
- 📈 Limiting indentation encourages writing better, more concise code with single-responsibility functions.
- 🤔 The speaker suggests that never nesters, like Linus Torvalds, may produce cleaner and more maintainable code by avoiding deep nesting.
Q & A
What is a 'never nester' in the context of coding?
-A 'never nester' is a programmer who dislikes or avoids nesting code, which is adding more inner blocks to a function, as it increases the complexity and difficulty in reading the code.
What is the 'disgust-o-meter' mentioned in the script?
-The 'disgust-o-meter' is a metaphorical measure of a never nester's discomfort with the increasing level of code nesting, which grows uncontrollably as the number of tabs or indentations goes up.
What is the maximum depth of nesting a never nester can handle?
-A never nester can handle a maximum of three levels of nesting in their code.
What are the two methods to reduce code nesting?
-The two methods to reduce code nesting are extraction, which involves pulling out part of the function into its own function, and inversion, which involves flipping conditions and using early returns.
How does extraction help in reducing code nesting?
-Extraction helps by taking the inner part of a loop or complex block and moving it into its own separate function, which simplifies the main function and reduces the overall nesting.
What is the purpose of inversion in code refactoring?
-Inversion is used to flip conditions and switch to early returns, which helps in simplifying the code structure by moving the 'happy path' (expected flow) to the top and indenting the error or 'unhappy' paths.
How does the script's example of downloading files illustrate the concept of never nesting?
-The script uses a complex, nested function for downloading files as an example. By applying extraction and inversion, the code is refactored to be less nested, making it more readable and maintainable.
What is the significance of the Linux kernel style guidelines in relation to never nesting?
-The Linux kernel style guidelines suggest that if a program requires more than three levels of indentation, it indicates a problem that should be fixed, aligning with the never nester philosophy of limiting code nesting.
How does limiting code nesting lead to better code quality?
-Limiting code nesting forces programmers to write smaller, more concise functions with a single responsibility, which improves code readability, maintainability, and overall quality.
What is the benefit of having a 'validation gatekeeping section' in code?
-A 'validation gatekeeping section' at the beginning of the code declares the requirements of the function and filters out invalid or error cases early, making it easier to focus on the core functionality.
How does the script's approach to refactoring impact the readability of the main function?
-By refactoring the code to reduce nesting and separate concerns into distinct functions, the main function becomes clearer and easier to understand, outlining the high-level logic without the complexity of nested conditions.
Outlines
📌 Understanding Never Nesters
The paragraph introduces the concept of 'never nesters,' programmers who avoid deeply nesting their code. It explains that nesting increases with each additional inner block in a function, and a never nester's discomfort grows with the number of tabs. The speaker identifies with this mindset and suggests that Linus Torvalds might be one too. The paragraph outlines the issue with deeply nested code and introduces two methods to reduce nesting: extraction and inversion. Extraction involves creating separate functions for parts of the code, while inversion involves flipping conditions and using early returns to simplify the code structure.
🔄 Applying Extraction and Inversion
This paragraph delves into the practical application of extraction and inversion to refactor code. It describes a complex code scenario involving a download system with multiple states and error handling. The speaker demonstrates how to extract the main branches of the download processing into separate functions and then further flattens the code by extracting the HTTP error handling. The result is a clearer, more maintainable code structure with distinct functions for different responsibilities, aligning with the never nester philosophy of limited indentation and better code quality.
Mindmap
Keywords
💡Never Nester
💡Disgust-o-meter
💡Nesting Code
💡Extraction
💡Inversion
💡Happy Path
💡Unhappy Path
💡Validation Gatekeeping
💡Single Responsibility
💡Linux Kernel Style Guidelines
Highlights
The concept of a 'never nester' is introduced, referring to programmers who avoid deeply nesting their code.
Linus Torvalds, creator of Linux, is mentioned as a potential 'never nester'.
A 'disgust-o-meter' is humorously described as a measure of discomfort with increasing code nesting levels.
Nesting code is defined as adding more inner blocks to a function, with each open brace increasing the depth.
The speaker suggests a maximum nesting level of three for 'never nesters'.
The negative impact of deeply nested code on readability and cognitive load is discussed.
Two methods for reducing code nesting are presented: extraction and inversion.
Extraction involves pulling out part of a function into its own separate function.
Inversion is explained as flipping conditions and using early returns to simplify code structure.
The speaker demonstrates how extraction and inversion can be applied to a complex code example.
The importance of focusing on the core functionality of a function is emphasized.
The Linux kernel style guidelines are referenced, advocating for limited indentation levels.
The speaker shares a personal preference for limiting code nesting and the benefits of writing concise code.
The transformation of a large, nested function into smaller, single-responsibility functions is illustrated.
The practical application of these techniques is shown through the refactoring of a file download system.
The speaker's approach to code refactoring is presented as a way to improve code quality and maintainability.
Transcripts
I have to admit, I'm a never nester.
I know.
Shocking.
But there are more of us than you think.
Dozens. Even Linus Torvalds is one.
I mean, I haven't asked him, but I'll show you what I mean in a little bit.
You might be wondering, well, what is a never nester.
A never nester never nests their code.
Okay. Not never.
But we do have a disgust-o-meter which grows
uncontrollably as the number of tabs go up.
Nesting code is when you add more inner blocks to a function.
We’ll consider each open brace to be adding one more depth to the function.
So this function is one deep because there's no inner blocks.
And if we add an if statement, we've made it two deep.
If we add a loop, we've now made this function three deep.
And this, my fellow
programmers, is the maximum a never nester can handle.
A never nester doesn't dare to go four deep.
Now the perverse among you might wonder what four deep even looks like.
And while it brings me great pain to do,
I understand that I must show you for science.
Here is four deep.
We've now taken a reasonably readable function and dramatically increased
the amount of conditions your brain must simultaneously hold.
But what can we do about it?
Well, there's two methods you can use to denest: Extraction.
This is where you pull out part of the function into its own function.
And inversion, which is simply flipping conditions
and switching to an early return.
Let's look at extraction first.
We can extract the inner part of the loop into its own function.
Now we can apply inversion.
When you put the happy path of code
within deeper and deeper blocks, it creates a lot of nesting.
Instead, we'll invert that condition and put the unhappy first.
First, we'll flip our if else, by inverting the condition.
Now, since we can return here, we know that the else block isn't
actually needed so we can flatten our else into the main level.
Now, if we hit our unhappy case
condition here, we simply get out of the way.
And then the main part of the code can do its job.
When you have a lot of conditions to check like this,
we can apply inversion over and over again
and we end up with a sort of validation gatekeeping section of the code
which sort of declares the requirements of the function.
And then we have the
crux of the real functionality here.
And you'll notice that the happy path moves
down the function and all of the error paths.
They're indented.
When reading this code, I find I can mentally discard
the condition and focus on the core code versus when it's nested.
I find myself having to hold these ideas in my head.
I'm curious if you’ve experienced the same thing?
Let's look at a larger example.
All right.
Look at this beauty.
Before we go refactoring it,
let me walk you through what's happening.
The goal of this code is to download a bunch of files from the web.
It talks with this download class that we can't alter.
It's an async download.
So when we start the download, you have to call process over and over again.
And each
time it gives you one of these results.
If it returns InProgress, we'll need to keep calling process() more.
On top of that, we want to download multiple files at once in the background.
So we've created a thread that manages all of them.
The way new downloads enter the system is through this append download method,
which puts the requested URLs onto a queue.
The thread then wakes up and grabs the URLs from the queue
and then adds them to this list of current downloads.
Each download is given a state
which is either pending InProgress or Complete.
So in each cycle of the main loop, the thread walks
through each download and checks what it needs to do with it.
If it's pending we start a new download.
If it's complete,
we simply remove it from the list.
If it's InProgress, we call that process method we mentioned earlier
and figure out what's happening with the download.
If it's completed successfully, we mark it as complete
so it can get removed from the list and InProgress means
we do nothing because it's still ongoing.
But things get interesting if we hit an error,
if the connection was okay, but we got an unhappy HTTP response.
We determine whether the air is retriable
If it is, we retry up to three times,
setting the download back to Pending.
Once it's failed plenty, we ejected from our download list
and push it to a failure queue for someone else to deal with.
For connection error, we retry three times.
Then we set the special connection disabled flag and this causes us
to basically give up on every download and clear the list.
Okay, so there's a lot going on here and it's all heavily
nested in this function, which makes it hard to follow.
So let's apply extraction and inversion to flatten
the first two big candidates.
Here are the two big branches of download processing:
Pending and InProgress.
So let's extract these out.
We'll move the pending part to processPending()
and InProgress
to processInProgress().
That's a bit better.
But this in-progress function is still too deep for my liking.
The worst offender is this HTP error section.
So let's move that out as well.
Now we'll keep extracting further in our run function.
We have four major sections of our code.
Where we process incoming requests from the queue;
Where we deal with our current downloads;
where we clear out the InProgress downloads,
and where we wait for the signal that there's new downloads to look at.
So let's do it.
So now
our main function clearly outlines the steps that are happening.
You can see the high level logic I described before.
And if you were to dig into any of these functions,
there are also concise.
At the beginning of this video, I mentioned that Linus
Torvalds is a suspected never nester.
And I say this because in the Linux kernel style guidelines they state
if you need more than three levels of indentation, you're screwed anyway
and should fix your program.
The kernel dudes are always so dramatic.
They visually enforce this
by making the tab size eight characters wide.
This is what eight characters look like with heavy nesting.
Yeah.
I'll admit I'm not that committed to the cause, but I am into limiting indentation.
I believe that constraining
how much you nest forces you to write better code.
If you notice, instead of one large function that handles many things.
We now have small, concise functions that have one responsibility.
What do you think?
5.0 / 5 (0 votes)