
Why You Shouldn't Nest Your Code
Why You Shouldn't Nest Your Code
I’m a Never Nester and you should too.
Access to code examples, discord, song names and more at https://www.patreon.com/codeaesthetic
Correction: At 2:20 the inversion should be “less than or equal”, not “less than”
Content
0.24 -> I have to admit I'm a never Nester
4.02 -> I know shocking
6.839 -> but there are more of us than you think
8.599 -> dozens even Linus torvill does one I
12.179 -> mean I haven't asked him but I'll show
14.759 -> you what I mean in a little bit
16.379 -> you might be wondering well what is a
18.42 -> never Nester
19.74 -> I never Nester never nests their code
22.22 -> okay not never but we do have a
26.4 -> disgusting meter which grows
27.96 -> uncontrollably as the number of Tabs go
30.42 -> up
31.5 -> nesting code is when you add more inner
33.899 -> blocks to a function we'll consider each
36.36 -> open brace to be adding one more depth
39.239 -> to the function
41.04 -> so this function is one deep because
43.02 -> there's no inner blocks
45.42 -> and if we add an if statement we've made
47.46 -> it too deep
49.26 -> if we add a loop we've now made this
51.66 -> function three deep
54.18 -> and this my fellow programmers is the
56.64 -> maximum and never Nester can handle
59.16 -> a never Nester doesn't dare to go for it
61.68 -> deep
62.46 -> now the perverse among you might wonder
64.68 -> what four deep even looks like and while
67.74 -> it brings me great pain to do I
70.02 -> understand that I must show you for
72 -> science
73.14 -> here is for deep
76.42 -> [Music]
86.78 -> we've now taken a reasonably readable
89.4 -> function and dramatically increased the
91.619 -> amount of conditions your brain must
93.24 -> simultaneously hold
95.1 -> but what can we do about it
97.259 -> well there's two methods you can use to
99.479 -> de-nest extraction
102.119 -> this is where you pull out part of the
103.92 -> function into its own function
105.96 -> an inversion
107.579 -> which is simply flipping conditions and
109.56 -> switching to an early return
112.32 -> let's look at extraction first
115.14 -> we can extract the inner part of the
116.7 -> loop into its own function
121.759 -> now we can apply inversion
125.399 -> when you put the happy path of code
127.32 -> within deeper and deeper blocks it
129.78 -> creates a lot of nesting instead we'll
132.239 -> invert the condition and put the unhappy
134.28 -> first
136.5 -> first we'll flip our if else by
138.599 -> inverting the condition
141.06 -> now since we can return here we know
143.52 -> that the else block isn't actually
145.379 -> needed so we can flatten our else into
148.08 -> the main level
149.64 -> now if we hit our unhappy case condition
152.16 -> here we simply get out of the way and
155.459 -> then the main part of the code can do
156.959 -> its job
159.959 -> when you have a lot of conditions to
161.7 -> check like this we can apply inversion
164.099 -> over and over again and we end up with a
166.8 -> sort of validation gatekeeping section
169.379 -> of the code
170.7 -> which sort of declares the requirements
172.86 -> of the function
174.9 -> and then we have the Crux of the real
176.7 -> functionality here
178.739 -> and you'll notice that the happy path
180.3 -> moves down the function and all the
182.76 -> error paths they're indented
187.26 -> when reading this code I find I can
189.72 -> mentally discard the condition and focus
192.18 -> on the core code versus when it's nested
194.459 -> I find myself having to hold these ideas
196.08 -> in my head
197.879 -> I'm curious if you experienced the same
199.8 -> thing
201.54 -> let's look at a larger example
204.42 -> all right look at this beauty
207.959 -> before we go refactoring it let me walk
211.319 -> you through what's happening
214.019 -> the goal of this code is to download a
216.239 -> bunch of files from the web
218.64 -> it talks with this download class that
221.4 -> we can't alter
223.379 -> it's an async download so when we start
226.019 -> the download we have to call Process
227.94 -> over and over again
230.22 -> and each time it gives you one of these
232.08 -> results
234.36 -> if it returns in progress we'll need to
237 -> keep calling process more
239.879 -> on top of that you want to download
241.86 -> multiple files at once in the background
244.26 -> so we've created a thread that manages
246.299 -> all of them
249.12 -> the way new downloads enter the system
251.159 -> is through this append download method
253.2 -> which puts the requested URLs onto a
255.78 -> queue
257.639 -> thread then wakes up and grabs the URLs
259.919 -> from the queue and then adds them to
261.84 -> this list of current downloads
265.02 -> each download is given a state which is
267.54 -> either pending in progress or complete
271.32 -> so on each cycle of the main Loop the
273.54 -> thread walks through each download and
275.46 -> checks what it needs to do with it
279.18 -> ending
280.32 -> you start a new download
282.72 -> if it's complete we simply remove it
285.3 -> from the list
288.419 -> if it's in progress
289.979 -> we call that process method we mentioned
292.08 -> earlier and figure out what's happening
294.12 -> with the download
295.56 -> if it's completed successfully we mark
297.6 -> it as complete so it can get removed
298.86 -> from the list
300.18 -> and in progress means we do nothing
301.979 -> because it's still ongoing
304.259 -> but things get interesting if we hit an
306.54 -> error
308.34 -> the connection was okay but we got an
310.44 -> unhappy HTTP response
312.66 -> we determine whether the air is
314.34 -> retryable
315.419 -> if it is we retry up to three times
317.88 -> setting the download back to pending
321.419 -> once it's failed plenty we ejected from
324.18 -> our download list and push it to a
326.28 -> failure queue for someone else to deal
327.72 -> with
329.1 -> for connection air we retry three times
331.44 -> then we set this special connection
333.539 -> disabled flag and this causes us to
336.419 -> basically give up on every download and
338.039 -> clear the list
341.58 -> okay so there's a lot going on here and
344.58 -> it's all heavily nested in this function
346.139 -> which makes it hard to follow
348.6 -> so let's apply extraction and inversion
351.539 -> to flatten
353.46 -> the first two big candidates here are
355.86 -> the two big branches of download
357.18 -> processing pending and in progress
361.259 -> so let's extract these out
363.96 -> we'll move the pending part to process
366.12 -> pending
366.69 -> [Music]
372.96 -> and in progress to process in progress
379.4 -> foreign
381.86 -> that's a bit better
384.12 -> but this in progress function is still
386.16 -> too deep for my liking
388.62 -> the worst offender is this HTTP air
391.38 -> section so let's move that out as well
394.639 -> now we'll keep extracting further in our
397.56 -> run function
398.819 -> we have four major sections of our code
402.96 -> where we process incoming requests from
405.36 -> the queue
406.8 -> where we deal with our current downloads
409.919 -> where we clear out the in-progress
411.72 -> downloads
413.1 -> and where we wait for the signal that
414.96 -> there's new downloads to look at
416.819 -> so let's do it
429.12 -> so now our main function clearly
431.46 -> outlines the steps that are happening
434.16 -> you can see the high level logic I
436.139 -> described before
438 -> and if you were to dig into any of these
439.919 -> functions there are also concise
444.06 -> at the beginning of this video I
446.34 -> mentioned that Linus torvald is a
448.5 -> suspected never Nester
451.02 -> and I say this because in the Linux
452.94 -> kernel Style Guidelines they state if
455.819 -> you need more than three levels of
457.199 -> indentation you're screwed anyway and
460.259 -> should fix your program
463.62 -> the kernel dudes are always so dramatic
467.52 -> they visually enforce this by making the
469.56 -> tab size 8 characters wide this is what
472.8 -> eight characters look like with heavy
475.319 -> nesting
476.759 -> yeah
478.099 -> I'll admit I'm not that committed to the
481.199 -> cause but I am into limiting indentation
485.34 -> I believe that constraining how much you
487.139 -> Nest forces you to write better code
491.039 -> if you notice instead of one large
493.199 -> function that handles many things we now
496.139 -> have small concise functions that have
498.36 -> one responsibility
500.819 -> what do you think
503 -> [Music]
508.139 -> oh
Source: https://www.youtube.com/watch?v=CFRhGnuXG-4