Why You Shouldn't Nest Your Code

CodeAesthetic
6 Dec 202208:29

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

00:00

📌 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.

05:01

🔄 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

A never nester is a programmer who avoids deeply nesting their code, which means they try to minimize the use of inner blocks within a function. This concept is central to the video's theme, as it discusses the disadvantages of deep nesting and the benefits of writing more readable code. The term is used to describe someone who has a strong aversion to increasing the indentation level in their code, as seen in the speaker's own admission and the reference to Linus Torvalds.

💡Disgust-o-meter

The disgust-o-meter is a metaphorical tool used in the video to represent the speaker's increasing discomfort with the level of code nesting. It's a humorous way to express the cognitive burden that deep nesting can impose on a programmer's mind. The term is used to illustrate the speaker's personal threshold for code complexity and is a key concept in understanding their approach to coding.

💡Nesting Code

Nesting code refers to the practice of placing one block of code within another, often to handle conditional logic or loops. In the context of the video, nesting is seen as something to be minimized because it can lead to complex and hard-to-read code. The video provides examples of how adding if statements and loops increases the nesting level and suggests strategies to reduce it.

💡Extraction

Extraction is a refactoring technique where a part of a function is moved into a separate function to improve code readability and maintainability. The video demonstrates this by showing how to extract the inner part of a loop into its own function, which helps in reducing the overall nesting level. This concept is crucial to the video's message about writing clean and understandable code.

💡Inversion

Inversion, in the context of the video, refers to flipping conditions and using early returns to simplify code structure. This technique is used to avoid deep nesting by placing the 'happy path' (the most common execution path) at a higher level and handling error conditions first. The video illustrates how inversion can lead to a flatter code structure that is easier to follow and understand.

💡Happy Path

The happy path in programming is the most straightforward and expected sequence of events that leads to the successful completion of a task. In the video, the speaker emphasizes the importance of placing the happy path at a higher level in the code structure to improve readability. This concept is used to contrast with the 'unhappy path,' which deals with error conditions and exceptions.

💡Unhappy Path

The unhappy path represents the error conditions or exceptions that a program must handle. In the video, the speaker discusses how to manage these paths in a way that does not increase the nesting level of the code. By inverting conditions and using early returns, the speaker shows how to handle unhappy paths without adding complexity to the code structure.

💡Validation Gatekeeping

Validation gatekeeping is a coding pattern where a section of code is used to declare and enforce the requirements for a function's input or conditions before proceeding with the main functionality. The video uses this concept to illustrate how inverting conditions can lead to a cleaner code structure where the validation is separated from the core functionality, making the code easier to understand and maintain.

💡Single Responsibility

The principle of single responsibility states that a function should have only one reason to change, meaning it should perform one task. The video promotes this principle by suggesting that breaking down a complex function into smaller, single-purpose functions can lead to better code organization and readability. This concept is exemplified by the transformation of a large, multi-purpose function into several smaller functions, each with a clear responsibility.

💡Linux Kernel Style Guidelines

The Linux kernel style guidelines are a set of rules that dictate how code should be written in the Linux kernel. In the video, the speaker references these guidelines to support the idea that limiting indentation can lead to better code quality. The guidelines recommend against excessive indentation, which aligns with the video's theme of avoiding deep nesting and promoting clean code structures.

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

00:00

I have to admit, I'm a never nester.

00:04

I know.

00:05

Shocking.

00:06

But there are more of us than you think.

00:08

Dozens. Even Linus Torvalds is one.

00:11

I mean, I haven't asked him, but I'll show you what I mean in a little bit.

00:16

You might be wondering, well, what is a never nester.

00:18

A never nester never nests their code.

00:22

Okay. Not never.

00:24

But we do have a disgust-o-meter which grows

00:27

uncontrollably as the number of tabs go up.

00:31

Nesting code is when you add more inner blocks to a function.

00:35

We’ll consider each open brace to be adding one more depth to the function.

00:41

So this function is one deep because there's no inner blocks.

00:45

And if we add an if statement, we've made it two deep.

00:49

If we add a loop, we've now made this function three deep.

00:54

And this, my fellow

00:55

programmers, is the maximum a never nester can handle.

00:59

A never nester doesn't dare to go four deep.

01:02

Now the perverse among you might wonder what four deep even looks like.

01:07

And while it brings me great pain to do,

01:09

I understand that I must show you for science.

01:13

Here is four deep.

01:27

We've now taken a reasonably readable function and dramatically increased

01:31

the amount of conditions your brain must simultaneously hold.

01:35

But what can we do about it?

01:37

Well, there's two methods you can use to denest: Extraction.

01:42

This is where you pull out part of the function into its own function.

01:46

And inversion, which is simply flipping conditions

01:49

and switching to an early return.

01:52

Let's look at extraction first.

01:55

We can extract the inner part of the loop into its own function.

02:02

Now we can apply inversion.

02:05

When you put the happy path of code

02:07

within deeper and deeper blocks, it creates a lot of nesting.

02:11

Instead, we'll invert that condition and put the unhappy first.

02:16

First, we'll flip our if else, by inverting the condition.

02:21

Now, since we can return here, we know that the else block isn't

02:24

actually needed so we can flatten our else into the main level.

02:29

Now, if we hit our unhappy case

02:31

condition here, we simply get out of the way.

02:35

And then the main part of the code can do its job.

02:39

When you have a lot of conditions to check like this,

02:42

we can apply inversion over and over again

02:45

and we end up with a sort of validation gatekeeping section of the code

02:50

which sort of declares the requirements of the function.

02:54

And then we have the

02:55

crux of the real functionality here.

02:58

And you'll notice that the happy path moves

03:00

down the function and all of the error paths.

03:04

They're indented.

03:07

When reading this code, I find I can mentally discard

03:10

the condition and focus on the core code versus when it's nested.

03:14

I find myself having to hold these ideas in my head.

03:17

I'm curious if you’ve experienced the same thing?

03:21

Let's look at a larger example.

03:24

All right.

03:25

Look at this beauty.

03:28

Before we go refactoring it,

03:30

let me walk you through what's happening.

03:34

The goal of this code is to download a bunch of files from the web.

03:38

It talks with this download class that we can't alter.

03:43

It's an async download.

03:45

So when we start the download, you have to call process over and over again.

03:50

And each

03:50

time it gives you one of these results.

03:54

If it returns InProgress, we'll need to keep calling process() more.

03:59

On top of that, we want to download multiple files at once in the background.

04:04

So we've created a thread that manages all of them.

04:09

The way new downloads enter the system is through this append download method,

04:13

which puts the requested URLs onto a queue.

04:17

The thread then wakes up and grabs the URLs from the queue

04:20

and then adds them to this list of current downloads.

04:25

Each download is given a state

04:27

which is either pending InProgress or Complete.

04:31

So in each cycle of the main loop, the thread walks

04:33

through each download and checks what it needs to do with it.

04:38

If it's pending we start a new download.

04:42

If it's complete,

04:44

we simply remove it from the list.

04:48

If it's InProgress, we call that process method we mentioned earlier

04:52

and figure out what's happening with the download.

04:55

If it's completed successfully, we mark it as complete

04:58

so it can get removed from the list and InProgress means

05:01

we do nothing because it's still ongoing.

05:04

But things get interesting if we hit an error,

05:08

if the connection was okay, but we got an unhappy HTTP response.

05:12

We determine whether the air is retriable

05:15

If it is, we retry up to three times,

05:18

setting the download back to Pending.

05:21

Once it's failed plenty, we ejected from our download list

05:25

and push it to a failure queue for someone else to deal with.

05:29

For connection error, we retry three times.

05:31

Then we set the special connection disabled flag and this causes us

05:36

to basically give up on every download and clear the list.

05:41

Okay, so there's a lot going on here and it's all heavily

05:45

nested in this function, which makes it hard to follow.

05:48

So let's apply extraction and inversion to flatten

05:53

the first two big candidates.

05:55

Here are the two big branches of download processing:

05:58

Pending and InProgress.

06:01

So let's extract these out.

06:04

We'll move the pending part to processPending()

06:12

and InProgress

06:14

to processInProgress().

06:22

That's a bit better.

06:24

But this in-progress function is still too deep for my liking.

06:28

The worst offender is this HTP error section.

06:31

So let's move that out as well.

06:35

Now we'll keep extracting further in our run function.

06:38

We have four major sections of our code.

06:42

Where we process incoming requests from the queue;

06:46

Where we deal with our current downloads;

06:50

where we clear out the InProgress downloads,

06:53

and where we wait for the signal that there's new downloads to look at.

06:56

So let's do it.

07:09

So now

07:10

our main function clearly outlines the steps that are happening.

07:14

You can see the high level logic I described before.

07:18

And if you were to dig into any of these functions,

07:20

there are also concise.

07:24

At the beginning of this video, I mentioned that Linus

07:27

Torvalds is a suspected never nester.

07:31

And I say this because in the Linux kernel style guidelines they state

07:35

if you need more than three levels of indentation, you're screwed anyway

07:39

and should fix your program.

07:43

The kernel dudes are always so dramatic.

07:47

They visually enforce this

07:48

by making the tab size eight characters wide.

07:52

This is what eight characters look like with heavy nesting.

07:56

Yeah.

07:58

I'll admit I'm not that committed to the cause, but I am into limiting indentation.

08:05

I believe that constraining

08:06

how much you nest forces you to write better code.

08:11

If you notice, instead of one large function that handles many things.

08:15

We now have small, concise functions that have one responsibility.

08:20

What do you think?

Rate This

5.0 / 5 (0 votes)

Verwandte Tags
CodingPhilosophyNeverNesterCodeReadabilityFunctionRefactoringLinusTorvaldsLinuxKernelProgrammingBestPracticesCodeSimplificationIndentationLimitsSoftwareDevelopment
Benötigen Sie eine Zusammenfassung auf Deutsch?