Why You Shouldn't Nest Your Code

Поделиться
HTML-код
  • Опубликовано: 24 дек 2024

Комментарии •

  • @tristanneal9552
    @tristanneal9552 2 года назад +8194

    I once nested 20 layers deep. Much like inception, time reading the code becomes exponentially longer the deeper you get... It's a miracle I'm even here today.

    • @onlyhereforthefish9924
      @onlyhereforthefish9924 2 года назад +376

      I worked at a place that had SQL stored procedures calling stored procedures sometimes 10 or 15 deep. It was nuts.

    • @christianschmid1440
      @christianschmid1440 Год назад +87

      Welcome. It's good to have you back!

    • @BiP00
      @BiP00 Год назад +124

      Perhaps the dream became your reality.

    • @voster77hh
      @voster77hh Год назад +35

      it's a learning process. We all start there

    • @maurobrandolt2166
      @maurobrandolt2166 Год назад +15

      LMFAO

  • @CodeAesthetic
    @CodeAesthetic  2 года назад +3427

    A few of you, rightly so, pointed out that the inversion at 2:20 should be `

    • @Handlessuck1
      @Handlessuck1 2 года назад +38

      You are doing so well! I can already see you growing into a popular channel!

    • @lonkwuzhere4433
      @lonkwuzhere4433 2 года назад +83

      don't worry, people on the internet are always nitpicking like that. Your editing style and video structure definatly make up for minor mistakes like that haha.

    • @code-dredd
      @code-dredd 2 года назад +9

      Posted the same prior to reading this. Deleted mine.

    • @malloc7367
      @malloc7367 2 года назад +17

      My day was ruined until I read this.

    • @SixOThree
      @SixOThree 2 года назад +17

      @@beqa2758 I don't allow conditionals without braces in my projects. I don't care if the braces are on the same line as their contents, but you _must_ have braces.
      The reason is very literally almost every time I have seen if or else statements without braces, I have seen another person break them unintentionally.

  • @PrimerBlobs
    @PrimerBlobs 2 года назад +8131

    I will admit to being an out-of-control nester, but I'm recovering. It really does make code easier to understand.

    • @tomzitiger
      @tomzitiger Год назад +119

      Primer! ❤

    • @linebreaker8751
      @linebreaker8751 Год назад +141

      Also I didn't know I was a never nester. I just thought I had to code like that. Also I am a strong single liner because I hate scrolling my code.

    • @linebreaker8751
      @linebreaker8751 Год назад +9

      Oh boy how did you end up in coding? Can you make a video about it if you are able to?

    • @thiagoassisfernandes
      @thiagoassisfernandes Год назад +1

      and easier to test

    • @voster77hh
      @voster77hh Год назад +4

      It's a learning process. We all start there

  • @aleceastman
    @aleceastman Год назад +1391

    I think this is actually crucial to teach to beginners. Holding exceptions and conditions in your head makes a code base really hard for others to read.

    • @anibalubilla5689
      @anibalubilla5689 11 месяцев назад +71

      Not only for others but for oneself.
      I find myself comming to a week old code, and wonder who nested all that code.

    • @chaosa928
      @chaosa928 10 месяцев назад +3

      I'm quite glad I came across this video...

    • @greyrifterrellik5837
      @greyrifterrellik5837 10 месяцев назад +15

      Imma be honest.
      At least in my situation, I fail to see any reason why any of this matters.
      I'm a solo dev, nobody else is working on this code but me so nobody else is gonna be seeing it but me.
      And I'm looking at this "un nested" code and it's honestly HARDER for me to read than nested code.
      The unnested code blurs together, while nested code creates immediate, obvious separations.

    • @chaosa928
      @chaosa928 10 месяцев назад +5

      @greyrifterrellik5837 so you can't see why others would prefer this way?

    • @greyrifterrellik5837
      @greyrifterrellik5837 10 месяцев назад +9

      @@chaosa928 Well I mean I can't see how it's easier to read this way, which is the claimed benefit, so no not really.

  • @jakobbarger1260
    @jakobbarger1260 Год назад +1534

    I just want to applaud the visual design of this video, especially the code. The blurring, previewing important definitions, uncluttered diagrams, use of color, typewriting, introducing motion to draw/hold attention. It really communicates the intent of the code better than I've seen anywhere else.

    • @LinkEX
      @LinkEX Год назад +40

      Seconded. The whole presentation is incredibly elegant.
      It doesn't seem like much but managed to deliver on a lot of aspects.
      Subtle but refined, directing the viewer's attention while not distracting and letting them think on what is being said.

    • @AliAhmad-qy2sf
      @AliAhmad-qy2sf Год назад +22

      @@LinkEX I do have to though sometimes when the code was blurred it took me a while to find it. idk if thats just be being slow or perhaps an optimization could be made there. Maybe a little more contrast in the part thats not blurred, or a small arrow would help

    • @KeithCooper-Albuquerque
      @KeithCooper-Albuquerque Год назад +4

      @@AliAhmad-qy2sf Thanks: You said what I wanted to say. Thanks also to LinkEX too for the thoughtful comments.

    • @astropgn
      @astropgn Год назад +1

      Yeah, it is a good approach. Code in videos are so boring, even for people who enjoy programming, it is a hard task to make them interesting.

    • @robbybankston4238
      @robbybankston4238 Год назад

      Agreed. The visual aids make it very clear to understand. Excellent job.

  • @jonesmartins
    @jonesmartins 2 года назад +6521

    Update: He fixed it. Nice! :-)
    I'd suggest using a lighter background when highlighting code and darkening the rest instead of blurring the rest, so that it's faster to find the line.

    • @cyberprompt
      @cyberprompt 2 года назад +626

      true, my eye went to the animation blurring then I had to scan around.

    • @LordBeef
      @LordBeef 2 года назад +46

      Same for me

    • @dirkniblickable
      @dirkniblickable 2 года назад +129

      Came here to say this. Darkening (and blurring) the “unimportant” code would improve readability.

    • @ChrisAthanas
      @ChrisAthanas 2 года назад +7

      Yes please

    • @Muhammed_English314
      @Muhammed_English314 2 года назад +78

      A highlighting rectangle will help too

  • @jsonlee01
    @jsonlee01 Год назад +1031

    Out of control nesting is definitely bad but sometimes when the guts of the code are extracted into smaller and smaller functions it also makes following the flow of the logic hard as well. You still have to try and keep track of what the parent of the parent is doing. At that point you are still in a nesting scenario, you’ve just shifted into smaller chunks of separated code. It’s a fine balance. Guard clauses help to get rid of unnecessary if/else conditions.

    • @bufdud4
      @bufdud4 Год назад +138

      Facts. The flow of logic seems much more straight forward when nested.

    • @mrosskne
      @mrosskne Год назад +26

      @@bufdud4 less straight forward*

    • @janiscakstins2846
      @janiscakstins2846 Год назад +91

      @@bufdud4 nested code is often untestable because you don't have control over it. When you have code in small chunks, then it becomes easier to test individual components. Test driven design is great because it forces you to design testable code in the first place. As long as the interface is testable, then there is nothing wrong with nesting, but you need to have tests in the first place, which rarely is the case.

    • @codejunki567
      @codejunki567 Год назад +20

      ​@mrosskne If you ever worked in a legacy back end system. 95% of things are the nested kind. Way easier to follow. Especially if you have 30 scripts to get by the end of the week.

    • @codejunki567
      @codejunki567 Год назад +22

      ​@janiscakstins2846 That sounds crazy, any piece of logic should be testable. If you can't get to a nested part of code in your tests, either the test or code is flawed.

  • @tomdarank1272
    @tomdarank1272 8 месяцев назад +1106

    Nobody tell this guy about HTML

    • @thedude142
      @thedude142 7 месяцев назад +15

      xD

    • @ricer3301
      @ricer3301 7 месяцев назад +5

      Yea

    • @TinyDeskEngineer
      @TinyDeskEngineer 7 месяцев назад +47

      Or XML.
      Or JSON.

    • @Pityke4
      @Pityke4 6 месяцев назад +25

      Well yes, but in modern frameworks you can easily create components.
      In Angular, you can even create templates in the same html file - which is similar to extracting a function and also saves you all the boilerplate to create a new component.
      Probably you cannot adhere to the 3 deep rule everywhere, but it's not impossible.

    • @tonybox4496
      @tonybox4496 6 месяцев назад +34

      This guy's focus is on algorithm, not data structure.
      On instruction flow, not relation map.

  • @johnheaney3349
    @johnheaney3349 2 года назад +1363

    Just wanted to point out a common error when inverting logic. At 2:20, the inversion technique is demonstrated. Before, the "happy" case was (top > bottom), which made the "sad" case (top = bottom). This creates a classic "off by one" error. In the case where top and bottom are equal, the former returned 0 and the latter returns one iteration of the sum equal to the result of filterNumber().
    I know that isn't really the point of the example, but you do need to be careful when using logic inversion.

    • @kakaopor
      @kakaopor 2 года назад +99

      I knew that mistake would probably happen before he made the change. Don't ask me why. Pls don't.

    • @jebwatson
      @jebwatson 2 года назад +34

      An excellent point and a mistake I've seen (and made) countless times.

    • @idselseno2306
      @idselseno2306 2 года назад +29

      Like in welding. Beautiful doesn't mean good.

    • @reasonable1
      @reasonable1 2 года назад +60

      True, a lot of people get inverting boolean logic wrong. Another one I saw recently was inverting (a && !b) to (!a && b). Instead, first invert the whole expression and then apply De'Morgan's law: !(a && !b) => (!a || b).

    • @fff-kd8kg
      @fff-kd8kg 2 года назад +8

      In this case, top==bottom would return 0 too, so it isn't logically incorrect. but yeah, I get your point.

  • @techman2553
    @techman2553 2 года назад +494

    Just code for clarity. Sometimes that means breaking complex methods in several simpler routines, other times that means combining several micro routines into one larger method. Sometimes nesting gets really confusing, other times nesting adds clarity to the code. Sticking to any one type of code structure religiously just adds complexity in different ways.

    • @Axel_Andersen
      @Axel_Andersen 2 года назад +77

      Being dogmatic about anything is wrong. Code for clarity, agreed!

    • @kindlin
      @kindlin 2 года назад +28

      Thank you! Exactly. Nothing is black and white. Everything has its place. Even a few nests deep...

    • @Finkelfunk
      @Finkelfunk 2 года назад +24

      I've never, and I mean _never_ seen clear code that is nested more than 4 deep. At 4 deep it becomes super tedious already. There is a reason they made this a kernel rule. I highly suggest you increase your tab width in your IDE of choice and you will quickly realize that there is almost always a way cleaner and easier method without nesting. It forces you to code better and come up with cleaner solutions, which ultimately leads to easier to read code that is much more maintainable.
      Gate clauses are a very easy example for that. Having a nested code means if you come across more exceptions your code needs to handle you need to escalate nesting into deeper and deeper parts of the code which will eventually lead to refactors anyways.
      Instead, having gate clauses at the top makes it a million times easier to add exceptions and still maintain readable code.
      Like sure, your 4 deep nest might "not look too bad" now, but wait until 16 different people have started adding conditions and you'll quickly end up with more nests than you can count. Nesting - not even once.

    • @kindlin
      @kindlin 2 года назад +14

      @@Finkelfunk
      I'm 5 deep right now, about 100 lines of code. It's quite clean, clear and concise. Each section of the code is purposefully labeled and does it's own little bit just fine. I think this instance, tho, is one of the few times this makes sense, and that's a select/case, where the logic going into the select and under each case needs to work individually, so it's already naturally broken into sub functions, that's just how cases work. I guess I could break out my Line function and my Square function, etc. but there is no need, they are all right here, easy to see, edit and compare.

    • @jackreacher963
      @jackreacher963 2 года назад +32

      “Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.” - John F. Woods
      That quote came in my mind while reading your comment.
      It may be ok for you personally but if you start working professionally you have to write clean and maintainable code because someone else could be forced to maintain it. Nested code in switch-cases is always smelly code at least.

  • @tobene
    @tobene 2 года назад +979

    Extraction should be done carefully. I've often seen code with lots of once-used & poorly named extracted functions, just to hide nesting. So the code is just as nested as before but you have to jump from function to function to understand whats going on.

    • @VeganSemihCyprus33
      @VeganSemihCyprus33 2 года назад +5

      Truth should be shared 👉 The Connections (2021) [short documentary] 👀

    • @nazeefahmadmeer
      @nazeefahmadmeer 2 года назад +191

      I swear. What people don't realise is any added function is one extra layer of indirection. So only add a function if you have a good reason for it. I have seen people adding functions just for the sake of keeping method under a few lines

    • @Gloubichou
      @Gloubichou 2 года назад +105

      @@nazeefahmadmeer I find that the right limit for extraction is when you start struggling to name the new functions. If it does not bear any meaning, then it probably does not deserve to be a function on its own. Also, respecting the single responsibility principle helps a lot (in the OOP paradigm, that is). If a class has too many methods, and you can't easily find your way around, it probably does too many things.

    • @MikkoRantalainen
      @MikkoRantalainen 2 года назад +30

      The problem is not extraction but the poor naming. Yes, coming to with good names is sometimes hard but if you don't like doing that, maybe programming is not something you should do.

    • @ObjectsInMotion
      @ObjectsInMotion 2 года назад +93

      Never extract something that’s only used once is my philosophy. A function needs to be called at minimum twice before it deserves defining. If it were up to me, thrice.

  • @kilianbalter
    @kilianbalter Год назад +184

    I'm a huge fan of "guard clauses" (simple if's at the start of the function which basically just return because the return value is obvious due to a special case input). So I was VERY bewildered when in my early programming classes (In 2020!) it kept being blanketly repeated that "a function should never have multiple returns". If you have one return 50 lines in and another 100 lines in, sure... but then you probably haven't split up the function correctly to begin with.
    You can write much simpler and cleaner code when you filter out all the special cases at the beginning as much as possible.
    One simple example would be a power function:
    pow(base, exponent)
    if(base == 0 && exponent == 0)
    throw Exception; (if you'd want to treat it as undefined)
    if(exponent == 0)
    return 1;
    if(exponent == 1)
    return base;
    ...rest of function to actually calculate the power
    Now this definitely goes against a different technique called branchless programming, but unless your function is called very very often in some heavy computing task, the readability far outweighs the speed.

    • @icedreamer9629
      @icedreamer9629 11 месяцев назад +28

      The best thing about guard clauses is that they are a perfect match to how you should be thinking when designing your program and writing your tests for it when following TDD practises. If you are designing complex functionality, the way any business describes it to you should be massaged into first the error conditions, then the happy path once all business concerns are satisfied.
      This lets you go and immediately write a test structure from the ticket, and then implementing the test structure automatically creates a flattened guard clause implementation.
      I find it incredible how many professional programmers haven't figured this out yet.

    • @shikyokira3065
      @shikyokira3065 11 месяцев назад +22

      The problem with branchless programming is, it is often written in a way that you need to write comments to explain what kind of monster you have created, because the next programmer who will be taking up your project is likely more stupid than you.

    • @owenreynolds8718
      @owenreynolds8718 10 месяцев назад +31

      "Never have multiple returns" was a good rule for the time. Because way back a "stack trace" meant manually adding debug lines to each function: "entering Q" and "leaving Q with value X". Return-from-middle (which is what I've heard it called) made old-time debugging extra-tough.
      So you may have been taught by someone who got their first job in 1982 and never worked anywhere else.

    • @shikyokira3065
      @shikyokira3065 10 месяцев назад +9

      @@owenreynolds8718 Now that you put it this way, it does look quite logical to have this rule.

    • @ccampau
      @ccampau 10 месяцев назад +1

      Plus 1 for Guard classes. Had a coworker that insisted on writing out exception handlers every time. Needless to say his code was a mess.

  • @erichobbs4042
    @erichobbs4042 Год назад +818

    I think that decomposing your mega function into a bunch of single responsibility micro functions definitely makes unit testing a lot more straightforward. But one thing that I have found is that I still need to write the mega function first. Once it's all down and working, I can then refactor it into something more sensible, but trying to write out all the single responsibility functions first, takes me more time than doing a "first draft" and then editing. It's like premature optimisation. Don't do it until you know that you have something you need to fix.
    I'm also a big fan of kicking out bad paths at the start. Not only is it easier to read, but when you discover a new unexpected bad path, you can just add another concise return block instead of having to nest something deeper in the function, and possibly missing a spot where you also needed to return rather than execute.

    • @alessandrotommasi9941
      @alessandrotommasi9941 Год назад +51

      Paul Graham (I think) once wrote: good code is like good prose: it requires constant rewriting.

    • @owenrowell
      @owenrowell Год назад +65

      I'm the complete opposite. I find it way easier to create a main function and complete that with unimplemented functions and then go and implement these one at a time. This way I can start by planning out the overall process of what I want to do and then handle each individual implementation of sections independently. Sometimes if when I then implement a function and it ends up just being a few lines of code I'll then move it back it back to the main function - but I still got the benefit of using placeholder functions to write out how I would approach the problem

    • @cybyrd9615
      @cybyrd9615 Год назад +9

      Or you can ask GPT to de-nest

    • @thunder____
      @thunder____ Год назад +3

      I find it certainly depends on what I'm doing; currently, I'm working on a PHP project with a bunch of POST forms, and the flow of those is generally extremely predictable, so I've been creating a main function with unimplemented functions to start off with for that. But when the structure of the task isn't so predictable from the start, I do generally find that jumping in and getting my hands dirty with a rough draft, and then refactoring that rough draft as needed, is a better way to quickly start turning that structure from nebulous to definite so I can start encountering and resolving unknown unknowns.

    • @b03tz
      @b03tz Год назад +9

      I feel like once you get more and more experienced you don’t need that draft function anymore. But it might be just a way that you think / work it out. I hardly do it anymore unless really rapid prototyping a method or several implementations. I almost instantly know what piece of code should be a private method or even its own class.

  •  2 года назад +388

    100% on what you said about separating the error paths from the good paths, it makes it so much easier reading the code months or years down the line. That approach really shines when writing code: you think of the error conditions first, handle them, then continue writing the good paths, but with a lot less to think about.

    • @gangulic
      @gangulic 2 года назад +3

      trouble is when you need to follow for example MISRA and there you have: "A function should have a single point of exit at the end." - you can use only one return in function

    • @pvanukoff
      @pvanukoff 2 года назад +34

      @@gangulic That's a silly rule, but if it must be followed, you could always utilize some sort of "proceed" boolean. At the top of the function, set it to true. Do your input validation steps, and if one of those steps fails, set the proceed boolean to false. When you get to the meat of the function, check that boolean first and only perform it if it's true (you can also utilize this boolean at each validation step after the first). Does this make it more complex than simply nesting? Maybe, maybe not, it depends on how many conditions you are checking, but it should satisfy the rule and allow for some de-nesting. Basically it turns a bunch of nested if statements into a flattened list.

    • @lollertoaster
      @lollertoaster Год назад +2

      @@gangulic does exception counts as a point of exit? If you can't use those, then "do {} while(0);" and use break instead of return if you want to be polite or use "goto" if you want to send a message on what you thing about this rule.

    • @tanvirrahman7339
      @tanvirrahman7339 2 месяца назад

      @@gangulic This is silly. Not sure why people teach this. Validating inputs and some other data before proceeding to calculation should end the process/function as needed. This can be in the form an exception, null/empty return, just exit/end the function, etc. Depending on the situation, the validation could be its own function and the main function can proceed based on that output.
      Recursive functions have multiple exit points. I have yet to see one with a single exit point that wasn't poorly written or convoluted.
      Someone else made a comment so I going to quote it: "Code for clarity".
      And I'll add to that - add comments, if you can't read minds don't assume I can read yours.

  • @cc3
    @cc3 Год назад +493

    The "validation gatekeeping section of the code" can be summarised as "guard clauses". We use it all the time, especially in the backend of our stack where requests must be validated. I didn't think I was a never nester before this video but I've got a bit of a problem with long line lengths so avoid unnecessary nesting if possible.

    • @lefran229
      @lefran229 Год назад +12

      + also known as the “early return” pattern

    • @911muha
      @911muha Год назад

      Dad d

    • @georgeyoung2684
      @georgeyoung2684 Год назад +8

      I love how Swift has an actual ‘guard’ keyword, that makes it just like an if statement, but forces you to return as part of it

    • @markhollas7585
      @markhollas7585 Год назад +4

      I have always called it "short circuiting". nice to learn other vernacular

    • @erichermann1962
      @erichermann1962 Год назад +3

      To add to the "fail fast" concept, I will typically go a step further and put my guard clauses into a guard function, abstracting all the negative scenarios away.

  • @jmilen
    @jmilen 11 месяцев назад +14

    I was already doing this but not aware of all the benefits outlined here. I've always used extraction and inversion (without knowing their names) simply because it's cleaner and easier to read. Great video.

    • @LudvikM
      @LudvikM 9 месяцев назад

      +1 :)

  • @ahmed.._.
    @ahmed.._. 2 года назад +580

    As a comp sci student, I'm loving these videos! These topics aren't really talked about at my university, and the way you present them really makes me consider things from a different perspective. Keep it up! :)

    • @Lucas-hh4oh
      @Lucas-hh4oh 2 года назад +15

      luckly my uni has one non mandatory class that talk about refactoring, pattern and code smells

    • @marcusrehn6915
      @marcusrehn6915 2 года назад +29

      Many university teachers have never worked in the real world, so they simply dont know

    • @ThePowerRanger
      @ThePowerRanger 2 года назад

      Same

    • @christopherw1248
      @christopherw1248 2 года назад +1

      @@Lucas-hh4oh do you have a recommended public resource for that topics? appreciate it if you have something.

    • @sineme
      @sineme 2 года назад +8

      @@christopherw1248 refactoring guru (website, I left the dot out just to be safe), SOLID-principles, object calisthenics are things worth looking into

  • @SJrad
    @SJrad 2 года назад +676

    Reminder to not go overboard with extractions as it creates a readability issue having to excessively jump from function to function. Especially if they’re not placed near each other and/or poorly named.

    • @blazerorb
      @blazerorb Год назад +39

      Skill issue lool
      (Skill of your IDE, that is, ayy)
      Even the VSCode basic C extension will show tooltips when you mouse over a function that show the signature and grab any preceding comments
      Rest of this is a stupid rant I wrote because I’m procrastinating studying, but I want to post it anyway. Sorry eh
      Also disclaimer, I’m new, and the fullest featured IDE I’ve used is IntelliJ for like 2 months
      I just think it’s kind of sad and ironic how much bending over backwards, or even thought at all, still has to be done in the name of readability, when this is literally how you create a UI. Like some people refuse to admit they’re bound by the same kinds eyes, hands, displays, and memories as someone doing anything else on a pc. Like anything beyond static, possibly colour coded text on solid background is some perversion. Like you should be able to just understand and hold the whole thing in your head, who needs eyes to know what code means?
      “What, a function reference that drops down when you hover or click to show you the definition? Comments being extracted and shown to the side or on hover or any other way than standard inline with the code? Shaded areas instead of a squiggly people can’t agree on because it wastes space wherever it’s put? Brackets that resize like you would on paper instead of alternating colours and fucking with the rest of the colour code? Any other idea you’ve had yourself for rendering the code window and then forgotten?”
      “Hell naw that’s for bitch-ass kids, I will continue to deal with the same basically-notepad limitations and inconveniences that my predecessors did. While I work on the dynamic UI for this CAD tool or map visualizer or browser game or whatever.”
      Like, is scratch not presented the way it is so that the reader can intake information visually, separate from encoding the information in text on the screen you have to read? Isn’t the readability issue one of us being limited in how easily or quickly we can understand the code on screen by reading the text, and wanting to increase it by being able to infer program behaviour or structure based on visual structure? Just feels like it sucks that in the age of OLED, VR, web frameworks, chatGPT, etc,
      some cool tabs can still be peak fkn technique

    • @litpath3633
      @litpath3633 Год назад +1

      @@uusfiyeyh hmm interesting idea

    • @PaladinJenkis
      @PaladinJenkis Год назад +22

      Not if your name it properly

    • @nik325007
      @nik325007 Год назад +75

      It is very frustrating when trying to debug someone's code, you jump from one function to another, to another file, and then you realize that you are looking at the wrong section because the errors is in the previous step that you have to find what is calling that function and what is calling that function and so on. I come across this too often as a web debugger and mod creator, so thanks, i hate it

    • @PaladinJenkis
      @PaladinJenkis Год назад +18

      @@nik325007 You can't expect engineers writing 8500 line long functions because you "code" in Notepad++.
      Ever heared of an IDE?

  • @sebobafett1652
    @sebobafett1652 2 года назад +296

    I've love the way that you animate code code changes. It makes it really easy to follow.
    I like the disgust-o-meter, it is often how I decide whether or not to request a change on a PR and now I've got a name for it.
    This was a nice way to advocate for the Single Responsibility Principle, better than the 7-line methods Bob preaches about.

    • @SixOThree
      @SixOThree 2 года назад +3

      I very much wish Visual Studio had a smooth scroll; especially when navigating to definitions in the same file.

    • @papasmurf9146
      @papasmurf9146 2 года назад +2

      I've never heard of the "never nester" concept -- but take "single responsibility principle" very seriously. Just checked my code and it looks like never nester.

    • @Dyanosis
      @Dyanosis 2 года назад +1

      I mean... not really. Single Responsibility is for classes, not methods. And while you COULD apply it to methods, it doesn't always work out as well as you think.
      However, it's much easier to enforce it with classes because classes should be performing 1 type of operation and be handing off other operations to other classes.

    • @papasmurf9146
      @papasmurf9146 2 года назад

      ​@@Dyanosis You're right. I misused Single Responsibility here. It is supposed to be "this code is fulfilling one person requirements, and no one else's."
      I was looking at "this code should only do one thing and do it well." I suppose both principles have the number one in them, but they are very different.
      Good catch.

    • @IndellableHatesHandles
      @IndellableHatesHandles 2 года назад

      On a PR?

  • @shanehebert396
    @shanehebert396 Год назад +18

    At 2:24 in your inversion, "if (top > bottom)" doesn't invert to "if (top < bottom)", that potentially introduces a bug. It probably should be "if (top

  • @asdfz0mg
    @asdfz0mg 2 года назад +551

    I'm a never nester myself and I've used the extraction and condition inversion techniques many, many times. I just wanted to comment and say I found this video very pedagogical. I really liked how you visually showed how you refactor a function (with extraction and inversion) using animations rather than just live coding it. It's more work for you to edit that stuff but I think it's easier for beginners to follow along.
    The only thing I would suggest you to change is to more clearly highlight the code you're talking about. The blurring didn't quite work for me all the time and I had to really concentrate to see what parts where blurred or not. Maybe it's just me and it's time to get some glasses though. Over all a very nice video!

    • @simulatrix
      @simulatrix 2 года назад +6

      Agreed. I like it when they grey out the unhighlighted code, like a comment would

    • @dylanh333
      @dylanh333 2 года назад +2

      There wasn't any blurring in the video - it was just your eyes!

    • @paulkanja
      @paulkanja 2 года назад

      just popped here to say if you have too many nests, then yeah, you are screwed,, also just a question for all other folk down here: branched/branchless?

    • @nonzz3ro
      @nonzz3ro 2 года назад

      I agree, my eye was drawn to one of the blurred texts first, then I'd see the other blurred text, then I'd be able to focus on the code he was talking about.

    • @ArifBasri
      @ArifBasri 2 года назад +1

      my brain were exercised well, but my eyes were straining hell

  • @TheFrostFyr
    @TheFrostFyr 2 года назад +232

    I've generally found people call the block of returns at the top of a function after inversion to be "Guard Clauses" I've always found them to make everything amazingly clear just like the content in your video shows and suggests.
    Keep up the good work, can't wait to see more.

    • @evancombs5159
      @evancombs5159 2 года назад +21

      This style of coding really should be what is taught, but a long time ago the idea that you should only return at the very end of a method was very popular. I'm sure there may have been a good technical reason back then, but it is an objectively worse way to code. Today we don't have a valid reason to stick with the only return once at the end dogma.

    • @Ashebrethafe
      @Ashebrethafe 2 года назад +13

      @@evancombs5159 I think it's a misunderstanding of the "single entry, single exit" principle, which is actually something that object-oriented languages automatically enforce: that you should only enter a function or routine at one point (the top) and only exit _to_ one point (right after where you came from). Older languages like BASIC allowed you to jump to any line by using a command such as GOTO or GOSUB, or by changing the pointer stored by GOSUB to tell RETURN where to jump to -- so in the case of BASIC, the principle meant "don't use GOTO; use GOSUB only to jump to lines immediately after a GOSUB, RETURN or END; don't change the RETURN pointer; and RETURN from every GOSUB".
      The one thing it's still useful for is freeing allocated resources (which you have to do before any exit) -- but Java lets you use "try" and "finally" instead of duplicating that code, or allocate the resources in the opening statement of the "try" if they can be freed automatically when it's exited.

    • @jeffreysun7983
      @jeffreysun7983 2 года назад +1

      I've heard it referred to as a "gauntlet pattern." I swear by it.

    • @SI0AX
      @SI0AX 2 года назад +4

      ​@@evancombs5159 In my company, I teach beginners the guard clause method because it makes a massive difference in readability. I tell them that else should never be used.

    • @jakemarquez3118
      @jakemarquez3118 2 года назад

      "Guard Clauses" that's a great name for it. Super great pattern, although I notice I implement a second tier of them within a nested scope if the right situation calls for it

  • @kirlian5399
    @kirlian5399 2 года назад +682

    I used to be a never nester myself. Now I’m more of a it-depends-on-the-case nester. Does extracting code into a separate function make it easier to understand? Well, sometimes. Do early returns make it easier to focus on the actual core of the procedure? Again, not always. It’s good to know these techniques of extraction and inversion, but as everything else in programming, you shouldn’t use them just because you can.
    That said, the video is really well done! The animations make it easy to follow all the moving parts, and the explanation is clear and concise. Great work!

    • @ade8890
      @ade8890 2 года назад +22

      Could you elaborate? I would argue that if you can you should. Reading heavily nested code sucks balls. Reading code can take quite awhile for you to finally absorb what's going on, and minimizing nesting helps keep the high level logic in the foreground for the readers. Things like guard clauses just seem like good coding practices, up there with making sure you comment your code and try to use descriptive/accurate names for variables and functions.

    • @almicc
      @almicc 2 года назад +56

      I said in my own comment, and that kinda answers Ade's question, so I'll repeat it here. It does depend, a lot. Sometimes, but not always, extracting code to a function can help, provided everything still remains in one file or one compact section of the file. I've had the unfortunate experience of trying to dig around programs and, in order to understand the full procedure, I end up clicking around to find the function declarations. This is the worst for triple or quadruple nested functions, where you basically have to scroll up and down constantly just to follow the flow of code. Nested code might be bad, but similar to reading a book, I'd rather stick to one or two continuous pages instead of bouncing around dozens of pages just to read a couple sentences here and there. My general rule is that it needs to be a big chunk of code to be it's own function, or so self descriptive and simple that you don't need to keep the implementation in mind. A good example of the big and small functions would be the big "handle http error" and "is even" in the video. However, sometimes I see functions that are two or three lines, and aren't so descriptive that you actually need to keep the implementation in mind everywhere you see it used. An example might be an error logging function, which depending on a boolean variable, may call another function that can affect the code going forward, like terminating the program or changing a variable being used. In that case, it would definitely be better to either split that function in two and just call what you need, or take the nested function call out and call it when needed. Or, best idea, don't use the function if it's only called in one place and just leave the code where it came from originally.

    • @almicc
      @almicc 2 года назад +15

      @@ade8890 I definitely think guard clauses are the best way to go, and should be used whenever possible. I can't really think of a reason to not invert code like that. Worst cases, where there's a lot of clauses interspersed between big sections of code, adding a comment just before some part reminding you "Hey, the number cannot be 5 here anymore, that was covered above" is great. I've written code with over five clauses like this, with enough code between to push it out of view, so having those comments to remind me and others is very helpful. This does get a little hairy when you have multiple different variables being filtered, so instead of "number isn't 5 here" it'd be more like "the number isn't 5, the object is null, and this enum color is either RED or BLUE now." But still, that's where I write the comment stating that. Good IDEs also understand this in static analysis, so I sometimes use that to check myself by testing a variable, and pray the IDE tells me "that is always true/false here."

    • @kirlian5399
      @kirlian5399 2 года назад +21

      @@ade8890 For example, you know which parts of the code get executed when everything goes well simply by looking at the indentation. Having a single exit point is tidy and organized.
      Also, sometimes it’s difficult to give a name to a specific part of the code, so it’s better to leave it inlined without a name. A name that is unclear and/or inaccurate can make things worse than just plain inlined code.
      At least, this is what works for me. It’s how my mind thinks and processes information. But that might not be everyone’s case.

    • @ade8890
      @ade8890 2 года назад +2

      @@almicc " Sometimes, but not always, extracting code to a function can help, provided everything still remains in one file or one compact section of the file."
      Yeah I agree with this. You shouldn't extract code to a separate file if where you are extracting it is only ever used in one spot.
      " I've had the unfortunate experience of trying to dig around programs and, in order to understand the full procedure, I end up clicking around to find the function declarations."
      I'm not sure if I understand the issue here. Most IDEs allow you click into a function call to auto-navigate to the declaring section. And aslong as that function is only used once, you can click the function signature to be brought straight back into the calling body. This gives you the best of both worlds, where you can click into more specific logic that you need to understand, or you can jump back out and just focus on the high level details.

  • @nickgovier
    @nickgovier 9 месяцев назад +40

    0:11 as soon as I found out Linus Torvalds is a never nester, it made me want to nest more

    • @delian66
      @delian66 4 месяца назад +5

      I hope you will grow up.

    • @lilyalexander963
      @lilyalexander963 4 месяца назад +10

      Bill Gates wrote this comment

  • @garethjacobsnz
    @garethjacobsnz Год назад +213

    I'm an old school programmer that cut my teeth on COBOL and C. We were taught to only nest to 3 levels and use functions to simplify code. This is how I still program today nearly 40 years later and works well for modern scripting languages such as PowerShell which I use extensively.

    • @OpenGL4ever
      @OpenGL4ever Год назад +8

      This is interesting. 40 years ago that was the time when compilers did not yet produce good code and every avoidable If condition and every function call was expensive and function inlining was also avoided because memory was also limited.
      In order to save computing time, it made sense not to outsource performance-hungry code to functions and to nest If conditions so that the code was as efficient as possible. A multiple nested if else construct was often more performant or meant fewer steps for the CPU than executing each IF query multiple times just so that you don't have to nest.
      How did you manage to nest on only 3 levels? Was a fast runtime speed not a requirement for the code? Did you have plenty of memory available?
      Today that may not be such a big deal, the compiler optimizes it all away anyway and inlines the functions again, but it just wasn't like that in the past.

    • @sillymesilly
      @sillymesilly Год назад

      @@OpenGL4everingenuity

    • @medekhgui
      @medekhgui Год назад +1

      I go 2 levels. 3 only if absolutely necessary.

    • @autochton
      @autochton Год назад +5

      @@OpenGL4ever 40 years ago was 1983, so not quite at the punch-cards age. 😉 Compilers didn't have quite the level of optimization they do now, of course -- four decades of improvement are a beautiful thing -- but they could handle function calls and conditionals to a reasonable degree in most languages I'm aware of. Of course, if you were writing highly-responsive or real-time code all bets were off, just like today, but for most purposes, human readable code was a goal then as now.

    • @OpenGL4ever
      @OpenGL4ever Год назад

      @@autochton The Microsoft C compiler was improved a lot between the release of Windows NT 3.1 in 1993 and Windows NT 3.5 in 1994. That resulted in a big performance improvement of the newer Windows NT 3.5 solely because of the much better compiler.
      This was 10 years later than 1983. The C compilers in the 80s where still in its infancy.

  • @the24throguecannon
    @the24throguecannon 2 года назад +220

    The blur is really cool, but I think also including the more traditional background highlight rectangle is still helpful because it pops out more.
    (in other words, maybe it still looks cool using both techniques at the same time!)

    • @fabioneto03
      @fabioneto03 2 года назад

      I totally agree!

    • @vibaj16
      @vibaj16 2 года назад +3

      or just blur more

    • @blankRiot96
      @blankRiot96 2 года назад

      Agree on this one, the blur is slightly harder to follow for me

  • @shugyosha7924
    @shugyosha7924 Год назад +174

    One other positive to this approach is that because you extract pieces of logic into functions, you can give them a function name that describes the logic. This alone goes a long way to making your code more immediately comprehensible.

    • @akulkis
      @akulkis Год назад +8

      Sometimes this makes sense. And sometimes it doesn't.
      Also, every function call has significant overhead: Saving the execution frame of the calling function onto the stack, and then throwing all those values onto the stack for the function being called... then when returning, restoring the execution frame from the stack to resume the calling function. Do that inside a loop, and the execution overhead can be ENORMOUS.
      That's this being a hard and fast rule that should never be violated is retarded.
      And let's not forget how much nesting of decisions structures there can be in an interrupt handler. Putting a function call INSIDE an interrupt handler is equally retarded, because interrupt handlers should be as fast as possible. If you can't understand the code, then you're not commenting enough.

    • @shugyosha7924
      @shugyosha7924 Год назад +11

      @@akulkis "that should never be violated" → As they say, never say never. In art and engineering I think rules are more like best practices that you have to learn first before you understand when to break them.
      In a lot of cases, I think readability (i.e. maintainability) is more valuable than cutting edge performance. If performance is an issue there are likely algorithmic changes you can make before changing whether something is extracted out into a function or not.
      About comments, I'm personally persuaded by the idea that the code should be as readable as possible without comments. I.e., if the code requires comments, that's a sign that maybe the code is getting quite complex. Sometimes that's unavoidable, but a lot of times it isn't.
      It would be one thing if comments were free but they're not: they require diligent upkeep or else they're liable to confuse rather than help. Learning a good balance between code readability and commenting is just another skill acquired on the journey of becoming a somewhat competent developer.

    • @tkg__
      @tkg__ Год назад +4

      @@akulkis most compilers inline functions and even inline loops anyway.

    • @akulkis
      @akulkis Год назад +1

      @@shugyosha7924
      "that should never be violated" → As they say, never say never. In art and engineering I think rules are more like best practices that you have to learn first before you understand when to break them.
      -- that's why I wrote that saying it's a hard and fast rule is retarded.

    • @akulkis
      @akulkis Год назад

      @@shugyosha7924
      "About comments, I'm personally persuaded by the idea that the code should be as readable as possible without comments. I.e., if the code requires comments, that's a sign that maybe the code is getting quite complex. Sometimes that's unavoidable, but a lot of times it isn't."
      The GREATEST thing that learning to program in various assembly languages is this:
      1. Write the comments for the function BEFORE writing the function itself.
      A. You are creating a "mission statement" for that function
      B. You are going to describe the strategy used to go about solving whatever that function is supposed to use.
      C. If you can't describe the algorithm(s) in plain old everyday language, there's literally no way that you're going to write it in code correctly.
      Too many programmers treat commenting as an afterthought. In assembly language, you literally can't get away with that. You're going to comment before you code, and then do more commenting while you code. ... every single line.
      I haven't written anything in assembly in decades, but those habits described above have always garnered heartfelt appreciation from others who have had to read and/or modify what I wrote.
      Remember this: "Self documenting code" is a myth. Yes, use meaningful variable names, but believe me, what one person thinks is clearly readable without comments will leave someone else scratching their heads. Suppose you have a for loop in C/C++, and for whatever reason, you do this
      loop_variable += skip;
      If you're not commenting SOMEWHERE (I would suggest both before the loop AND next to that line) why you're screwing with the loop control variable, SOMEONE is going to be confused, and chances are, you aren't going to be around to explain it. Or its' 20 years later, and your thinking and problem solving style has changed so much that you literally cannot understand why you yourself wrote something like that.
      I've never seen source-code with too many comments. I've seen source-code with lots of comments that are unnecessary because they tell you what the code itself tells you:
      int counter; /* counter is an integer */
      But that's a different problem -- it's just being redundant. Comments should generally focus on answering the question: "WHY? " and occasionally on "How?" (comment blocks for functions, and generally longer for loops and long if statements and long assignment statements ( x = LOTS of factors and terms)) and occasionally WHAT (data structure declarations)
      And remember, the more CLEVER your code, the more comments you need so that someone can understand what you're thinking without you being there to answer their questions.
      Compiler writers added commenting ability for a reason. If it were simply a matter of teaching "write self-documenting code" then we wouldn't need comments. But the fact of the matter is, a good portion of code is NOT self-documenting, and for most programmers, it's a FAR larger proportion of their own code than what they think.

  • @nicksrub
    @nicksrub 8 месяцев назад +2

    I rewatch this video every few months to remind myself to do this. Thank you for making it so clear and simple

  • @CodingwithGPT
    @CodingwithGPT Год назад +346

    Dude I have been teaching CS for 10 years and honestly this is the best piece of communication on general best practices that I have ever seen

    • @xbzq
      @xbzq 11 месяцев назад +6

      What? Did you just say? What the what what? What was that? Did you say what? 10 years and this garbage is the best? And you... you teach? 10 years and you teach for 10 years and this garbage is the best you have ever seen and you teach.
      That is scary. I guess so your students must be hyper dense.
      Job security for me, I guess. No competition. Lol.
      10 years huh. And this is it.

    • @pixelgreen5837
      @pixelgreen5837 11 месяцев назад

      ​@@xbzqCongratulations, you win the flexing competition, here's some internet validation

    • @RubixstewYT
      @RubixstewYT 10 месяцев назад +7

      ​@@xbzq brother is stuttering in text. There's no need to be scared

    • @soupman8165
      @soupman8165 10 месяцев назад +4

      ​@@xbzq are you okay

    • @xbzq
      @xbzq 10 месяцев назад

      @@soupman8165 Why you ask

  • @shubtakkorathinasapostle1159
    @shubtakkorathinasapostle1159 Год назад +541

    I didn't realize I was subconsciously a never nester but I thank my professors for subtly teaching me good practices

    • @ConnerTurmon
      @ConnerTurmon Год назад +16

      Same! When writing graphics code I noticed that if there was some check I needed to do, like if the renderer initialized or not, I would return out of the function rather than nesting all the "happy code" inside passing checks. I didn't realize this was an actual concept lol, I just thought it made it way easier to read.

    • @BetaTester704
      @BetaTester704 Год назад +3

      I taught myself programming from scratch, interestingly this is one one the things I figured out myself.

    • @simonvutov7575
      @simonvutov7575 Год назад

      same!!

  • @PaulSinnema
    @PaulSinnema Год назад +30

    I totally agree. This was a nice example of refactoring code. When I start a new piece of code I always force myself to not go into the details right away but create a fundament that outlines what I'm trying to build. Extracting routines and give the names of what I need to do in them and handle any results. This way I can start to think about the bigger picture before diving into the details. It helps me tackle the whole problem more easy. When I get to the nitty gritty of the details I may need to refactor some of the outline I made but most of the time it is not needed. Chopping the problem up like this lets me focus on each little detail independent of the whole problem. When I find that an extraction is becoming too big I create a little more outline before diving into the details again. Works very well for me. Sometimes I find that the way I thought about the fundament is totally wrong. No problem. I didn't write much code so far, so starting over is not very costly and I've learned a lot setting it up the wrong way.

  • @ajuc005
    @ajuc005 Год назад +84

    In general I agree. I especially like early returns and splitting conditions/validation from operations. But sometimes nesting is better. For example when you have algorithm that is inherently nested (like you have 4 tight for loops indexing some arrays etc.). Better to have the whole looping/indexing in one function and extract the "doing" into another function than to extract part of looping to another function. Because it makes the algorithm less clear and if you do 4 loops with complex indexing you better be aware what you're doing.

    • @pizzapunt3960
      @pizzapunt3960 Год назад +5

      I think the problem is that you wrote an algorithm that requires 4 loops.

    • @ajuc005
      @ajuc005 Год назад +24

      @@pizzapunt3960 there are algorithms that inherently require 4 or more loops. Some faster versions of matrix multiplication for example. Or pathfinding.

    • @pizzapunt3960
      @pizzapunt3960 Год назад +1

      @@ajuc005 they don't need nested loop. If you are using nested loops you're being slow. You need parallel processes (might be called differently, every programming language implements it differently). If you look at a* for example, doesn't require a single nested loop. It's not something inherent to the algorithm but to your lack of skill.

    • @cantthinkofaname1029
      @cantthinkofaname1029 Год назад +16

      ​@pizzapunt3960 you are aware that some environments disallow multi threading, yes? Have you ever even heard of an MCU?

    • @BodomsScythe
      @BodomsScythe Год назад +18

      @@cantthinkofaname1029 Who hasn't heard of the "Marvel Cinematic Universe", at this point? :P

  • @jj-big-slay-yo
    @jj-big-slay-yo Год назад +225

    I think this happy path / sad path disctinction is also called a "guard" clause - in which you guard the important part of a function with the guard(s) that are checking for invalid conditions and then bounce if the conditions are not ok before ever reaching the important parts.

    • @dahlola
      @dahlola Год назад +2

      Yep. I recently started programming in Swift and there "guard" is an actual keyword. I have been doing much more "happy path" programming before but will refactor some of the code I done in Kotlin.

    • @zackyezek3760
      @zackyezek3760 Год назад +10

      Guard clauses aren’t “never nest”.
      Guards simply mean you simply have a flat set of “if” validation checks on your inputs (and error handling) before you start using them in the function’s business logic. In effect you’re writing all your functions like they were main(), weeding out as many error conditions as possible as early as possible.
      This is a good design pattern that has nothing to do with obsessively avoiding nested logic. It simply eliminates many wasteful and unnecessary layers of nesting by doing error checks in sequence (with error returns). There are times where 5-6 or even more layers of nesting is perfectly good, efficient code for the business logic. Especially if you’re doing something functional, like creating several layers of nested objects in one statement, where indenting the nested calls on new lines makes the code way MORE readable.

    • @JamesBalazs
      @JamesBalazs Год назад +8

      ​​​@@zackyezek3760 100% agreed, the thing these videos often ignore is that you have to apply common sense, logic, and your own experience to decide whether to nest or not, whether to split something out into a function, whether to chain calls on the same line, or split it up. Etc etc.
      Obsessively applying some arbitrarily rule to all situations results in code that is consistent, but often consistently wrong. You have to both consider what you gain by making a certain style choice, and the disadvantages as well. Normally readability, performance, and maintainability (ease of making changes in the future) will fall on one side or the other, and you have to compromise. But always prioritising readability at the expense of all other factors is often the wrong choice.

    • @Whitecroc
      @Whitecroc Год назад +1

      I like to think of them as getting rid of the boring stuff beforehand so I can focus on the stuff that actually matters.

  • @Accelerando_poco
    @Accelerando_poco 2 года назад +155

    I'm all for extracting code into functions as long as these functions are given names which clearly convey what they do. If they are not named properly, I would rather have the code written out explicitly than having to jump though the functions in order to find out what it is actually supposed to do. If one finds the process of naming the functions difficult, it might be a strong indication that the block of code should be extracted in a different way - perhaps it is better to extract the code into two different functions rather than one, or perhaps the rest of the code needs to be sorted out first. Too many times, I see developers hastly jump to the conclusion that "extraction == good" while forgetting the larger goal at hand, which is to improve readability.

    • @jakubjakubowski944
      @jakubjakubowski944 2 года назад +31

      Exacly. The problem with multi-nesting is that you have to understand a lot of code at once while also making big chunks obfuscating flow of code. If we have one very short (thus not obfuscating) nest then replacing it with badly named function actually makes problem WORSE because it forces reader to jump over multiple places to process one procedure.
      Obvious solution is to name stuff descriptively, but naming is hard sometimes. There is no golden bullet.

    • @MrTrilbe
      @MrTrilbe 2 года назад +17

      Also comments and documentation helps, I know not everyone likes commenting and likes self descriptive code and not everyone thinks documentation even exists, but sometimes a short sentence of intent helps, even if it's in the reference code and not in the compiled code or the documentation.

    • @NotExplosive
      @NotExplosive 2 года назад +4

      Sometimes I need to extract first in order to figure out the name. I'll extract a function and give it a temporary nonsense name like "Banana." Then see how the function is used, what goes in, and what comes out. From that I discover a name and I rename Banana to the name it ought to have had all along.
      If the name is long-winded and complicated, that's a hint that I need to extract it further, or perhaps I extracted the wrong thing.

    • @MrTrilbe
      @MrTrilbe 2 года назад +21

      @@NotExplosive 3 weeks and 10 projects later "WTF is 'banana?' " lol

    • @jbird4478
      @jbird4478 2 года назад +19

      And that is a problem you do run into when applying this too much. You'll get a lot of small functions for which it's sometimes damn near impossible to think of a sensible name. Sometimes just keeping the nesting is a fine solution as well; and add a comment if it's somewhat unclear.

  • @biltongza
    @biltongza 2 года назад +225

    The bit about mentally discarding the unhappy path is what I try to drive into my junior devs brains! Less stuff in working space of my brain = less stuff to think about = less stuff to go wrong. The mental model is so important! Very glad you mentioned this and I'll be sharing it :)

    • @guytech7310
      @guytech7310 2 года назад +11

      Not really the case, if you dividing your code into a lot of tiny functions it can make it difficult to read since you spend a lot of time scrolling around for all the functions called, plus if you modify several function & it breaks something, but scrolling around all those functions trying to determine which function is the culprit, and you still have to track it all in your head. Worse is when you use nested functions:
      function A() {
      if (x > y) {
      result = Function B(x,y);
      } //endof if (x> y);
      } //endof functionA
      Function B (x,y) {
      if (x == (y +1) ) {
      z = y +1;
      result = Function C(x,z);
      } //endof if (x == (y +1) )
      else
      result = Function D(x,y);
      } //endof Function B (x,y)
      All your doing to making it harder to read and debug. I would be much easier if all this was in Function A, and not have to jump arround all those functions trying to figure out the bug, especially if the functions are either in different source code files, or your source code file has thousands of lines of code and the functions are located far away from the main function.
      You can use comments to divide your code blocks into groups to make them more readable. Also add comments to all closing brackets to make it more readible\trackable. ie "} //end of if (x == y)" . Code your levels like a FIFO stack, so that for each level you add the closing bracket before inserting the first line of code in the new level.

    • @biltongza
      @biltongza 2 года назад +17

      @@guytech7310 this is why we have tools that make it easier for us. Your comments on the ends of code blocks are handled automatically by modern IDEs showing you where braces are related, and you don't have to worry about changing functions and breaking stuff if you have unit tests. "But who has unit tests?" I hear you ask. You, because you didn't write your code to be testable in the first place. Or you inherited a codebase where someone else made that mistake for you. I don't know, I'm not your boss. The point is it's better to leave things better than you found them and this is one way of doing it.
      The gist of this all is, if I know that a certain function or piece of code works, I can *entirely* disregard it from my debugging process. Skip it entirely. Not even a thought is spared for it (unless it has side effects, in which case, you have bigger problems). I don't care about code jumping around because my debugger is handling it for me. If I have to have an entire god function's state in my brain's working memory, that's very taxing and slows me down. Too many possibilities and variables to keep track of. I'll let me brain do what it is good at: think of things logically one thing at a time. Break down the task into smaller chunks. Check my assumptions. "The result of this function should be x, and I got x, so my problem is not here" and I never need to remember that that code even exists. So I move on to the next thing. Keep doing that until a) I find something that doesn't match my assumptions or b) run out of assumptions, in which case, more often than not, the princess (bug) is in another castle.

    • @rahpat01
      @rahpat01 2 года назад +11

      ​@@guytech7310 what makes things hard to read is the inadequate naming. And unnecessary comments are a classic evil trying to compensate the lack of effort on finding expressive name for variables, functions, etc...

    • @davestorm6718
      @davestorm6718 2 года назад +9

      @@biltongza I program in C# and find so much relief that Visual Studio 2022 keeps track of darn near everything (how many references to any function anywhere, no matter if it's in another file, inside a dll, or what-have-you). Even deep nesting display is color coded and you can collapse code at any level (the best feature ever - though most IDEs have this) and keep it collapsed (not to mention, it's all customizable!). This plus intellisense, and keeping track of all external stuff, git, etc, makes programming a lot less stressful. This is the what ALL IDEs should be doing: keeping track of everything. Coming from a background of writing code on a text editor, devs today have no idea how good they have it!

    • @biltongza
      @biltongza 2 года назад +4

      @@davestorm6718 precisely!!! Use the tools you have!!! They are there for a reason!

  • @keldwikchaldain9545
    @keldwikchaldain9545 6 месяцев назад +2

    The problem that I have with never-nesting is that method extraction can at times be exceedingly painful in terms of the number of values which must be passed to a function because the path that's being extracted is so tied up in the values which are extracted above it.
    If I extract those things to functions, then I now have to think about that function as a piece of reusable code in the context of the entire scope the function is available in. Either the compilation unit, the module, or the entire project if it's added to the public interface due to being a template function or similar.
    Having lots of small functions in a compilation unit is worse than having a few very large functions, because it requires that I hold more possible uses of each function in my head at once, a combinatorial explosion of possibilities rather than simply a big function.
    Best IMO would be a proper way to have local-private functions which are only available for a single definition, like haskell where clauses. You can do this is some C-lineage languages, but it's always with extra nesting by being inside the scope of the outer function, and can often make things a bit harder to follow.

    • @danwl9708
      @danwl9708 2 месяца назад

      Might want to structure your data differently in that case then pass that structure as a single argument

  • @IterativeTheoryRocks
    @IterativeTheoryRocks 2 года назад +390

    I remember working with an ‘ever nester’ once.
    Rapidly scrolling down his code, there were large gaps between function definitions.
    Weird, I thought.
    Scrolling to one of the gaps, then scrolling to the right, I found the missing code. It was nested so far it had disappeared off the right hand side of the screen!

    • @Infiny92
      @Infiny92 2 года назад +55

      This should be illegal.

    • @user34274
      @user34274 2 года назад +34

      Disgusting. Just reading that sent a shiver of revulsion down my spine.

    • @BarackBananabama
      @BarackBananabama 2 года назад +10

      Nestscape.

    • @mingyenwu9621
      @mingyenwu9621 2 года назад

      XD

    • @VeganSemihCyprus33
      @VeganSemihCyprus33 2 года назад

      Truth should be shared 👉 The Connections (2021) [short documentary] 👀

  • @toddbarton1049
    @toddbarton1049 Год назад +247

    I particularly like Extraction because then you can give the function really descriptive names, then when you read thru the top function it's almost like you're just reading a book, instead of interpreting the logical flow of the code. I often combine Extraction and Inversion, in that after I invert, I'll extract the inverted code into its own (descriptive) function.

    • @Knowbody42
      @Knowbody42 Год назад +32

      Choosing descriptive names for your variables and functions is a big part of making code easy to read. The less thinking you have to do to understand what a variable is for, or what a function does, the better.

    • @Baby4Ghost
      @Baby4Ghost 11 месяцев назад +13

      "you're just reading a book"
      Thats what I expect from my code, consistency and appropriate semantic naming are key. The code should be as readable and understandable as a book telling a story.

    • @sebastiang7394
      @sebastiang7394 11 месяцев назад +7

      And that’s why you shouldn’t need comments in 99% of all cases. Extract all logical units into their own function and give it a descriptive name. Much better than lengthy comments that never get updated when someone changes the code.

    • @LordxJoe
      @LordxJoe 10 месяцев назад +5

      Biggest thing with this is to group the extracted methods logically. I can't tell you how many times i had to ctrl+click a method only to end up at the bottom of a 5000 line file because the developer who implemented new code couldn't be bothered.

    • @ccampau
      @ccampau 10 месяцев назад +3

      It's also makes the call stack much more informative when an error occurs. Easy to see "error in the foo method" vs the 1k line method had "object not set to an instance of an object"

  • @CoolAsFreya
    @CoolAsFreya 2 года назад +120

    Whilst I'll probably never be a strict never-neater this video has certainly helped me consider some ways to make my code more readable!

    • @VeganSemihCyprus33
      @VeganSemihCyprus33 2 года назад

      Truth should be shared 👉 The Connections (2021) [short documentary] 👀

    • @AlexRenfro-ux8th
      @AlexRenfro-ux8th 2 года назад +1

      unreadable code is job security, mate 😄

  • @daniellewis984
    @daniellewis984 6 месяцев назад +1

    I tend to strongly favor inversion and not extraction, and I need to explicitly consider which is the correct approach for each step.

  • @arjunmehta2853
    @arjunmehta2853 Год назад +38

    I used to do a ton of nesting when I was a beginner, but as I invested more time, I automatically learnt better methods of writing code by watching tutorials and reading documentations, and also got used to them, its great to know that I have improved over the years and already use good practices without actively trying to.

  • @mike200017
    @mike200017 2 года назад +168

    I would consider myself a "never nester" too, but I can also recognize that there are drawbacks to it that might be good to point out, with some tips to avoid them.
    1) The inverted conditions can sometimes be less obvious, especially if there are some logical operators (and, or, not) that can be hard to invert correctly or understand afterwards. I think a good mitigation for that is to avoid compound conditions by either splitting up individual conditions, i.e., instead of "if any of these conditions are not met, return early", itemize each condition with its own early return, which also encourages more helpful error codes or exceptions, or putting the compound condition in a function with a good name.
    2) Although putting all the error conditions up front cleans up the "good path" below, it can also put distance between checking for a problem and the code that would fail. So, either you can't understand the check before you see the code that needs it or you can't remember that the check was already done by the time you read the code below. The way to remedy this is typically to decompose into smaller functions (e.g., instead of 20 checks up front, and 5 chunks of "good path" code below, you split into 5 functions, each having around 4 checks up front).
    3) In a similar vein of scoping issues, decomposing into many functions can encourage broadening the scope of code and variables. This is especially common with object oriented code when decomposing member functions (aka methods). It's easy to create new "decomposed" functions that are not self-contained, i.e., they take in and/or return variables or (self-)objects in a state where they are in the middle of some broader processing (the parent function), and invariants are temporarily invalid. That can be error-prone in future changes or additions to the code. It's also easy to make what should just be local variables of the parent function into member variables of the class or (God help us) global variables to avoid having to pass them in and out of the child function. And finally, it's easy to overly expose functions that are really just implementation details. Avoiding this just takes discipline to minimize the scope of variables and functions as much as possible.
    4) Another obvious issue is that splitting up code into many single-use functions, and often, for other practical considerations, having to scatter them in different places in the code, does create readability problems due to having to jump around, and also because it can be hard to name functions that don't have a well-defined purpose outside of that one call-site. This can sometimes be mitigated by using "local" functions (or closures, or lambdas, or whatever, they go by many different names). A relatively common pattern you see is a bunch of checks up front, then some helper functions defined (typically closures or lambdas), and finally the main "good path".

    • @raducuvlad2187
      @raducuvlad2187 Год назад +5

      This is exactly what I was thinking, also referencing "A philosophy of software design" about deep and shallow classes/modules

    • @nuckm
      @nuckm Год назад +5

      @@raducuvlad2187 Best book in the universe for any programmer EVER, it is a must read. In my opinion a lot of these nesting issues aren't so bad when you add a lot more comments to the code, which all of these examples is lacking

    • @nuckm
      @nuckm Год назад +11

      Also if you deconstruct into a bunch of small methods, that makes it harder to understand in a different manner because it obscures the real functionality. "clearDownloads" doesn't mean anything at all, it's the code inside you need. Don't break up the code into many small functions especially if it's only gonna be used in that one place

    • @youcefnafa2267
      @youcefnafa2267 Год назад +1

      In addition to your 2nd point. I noticed putting checks upfront goes against the paradigm of try now fail later. Instead of checking whether a file exists, just try to read it and throw your exception (try-catch blocks). The nesting needed is just one level if the language allows multiple catch blocks per try block.

    • @youcefnafa2267
      @youcefnafa2267 Год назад +4

      @@nuckm RUclips recommended another video from the same channel, titled "don't write comments". Now I feel like I gotta watch it

  • @RaineAvina
    @RaineAvina 2 года назад +28

    This also gets into the idea of testability. If you have a lot of small functions like you do in your last example, it's easier to write a test case to verify each public API that you split out in isolation.

    • @peterbonnema8913
      @peterbonnema8913 2 года назад +2

      Wouldn't the extracted functions be private and therefore untestable?
      And no, you shouldn't then make them public instead just so you can test. That would be very bad.

    • @peterbonnema8913
      @peterbonnema8913 2 года назад +2

      @Jan Krynicky you misunderstood. I meant that extracting out functions doesn't mean you can test them separately because they are private.

  • @Necropheliac
    @Necropheliac 2 месяца назад +1

    For the most part I agree. If you’re going 3 or 4 deep you should be asking yourself if some of this should be deferred to another function.
    Too many conditions in a function can make code difficult to test because the test has to account for many conditions and that makes the tests themselves sort of brittle and too cumbersome to deal with over time.

  • @SrFrancia0
    @SrFrancia0 2 года назад +33

    YES! when multiple if statements are nested I feel like I need to keep it in mind it's a nightmare. I've always been a never nester without knowing. Great video!

  • @timecubed
    @timecubed Год назад +10

    This video is a really helpful one. I have recently started trying out rust as my main programming language and although it's basically all I've ever wanted, its syntax and how it's written can quickly turn any app into a big mess, and these techniques really helped in making my rust code more readable. Stuff like the extraction method help with fixing some of the messy syntax and hiding it away somewhere else so that your main function that does all the work looks cleaner and more concise. I will say though, writing code while making sure that it doesn't nest more than 4 layers deep is quite hard, and I usually go with a "make a messy function that does a bunch of stuff first, then denest it" type of approach. Great video!

  • @udadni
    @udadni Год назад +21

    I'm a new C# programmer doing hobby game design in Unity. I am so glad I got introduced to some of these ideas early in my programming journey, mainly inversion using the term "guard clauses". It's so nice now that I have a little more experience to see this elegant dive a little deeper into the topic. Thanks for the great material!

  • @carrolte1
    @carrolte1 11 месяцев назад

    ok, I clicked this cause I thought you were gonna write code and format it with 0 indentations and thought "That is stupid, lets watch". Then I saw you are changing the algorithm, not the formatting. This is a great mindset to have. thumbed up, and subscribed.

  • @craigsparton
    @craigsparton 2 года назад +9

    A fellow never nester here. The gatekeeping method is so much more elegant, and your points about how it shifts all the real code to the end and keeps it all together is exactly the reason I do it. I find it much easier to make sure I've validated everything necessary when all the "unhappy" conditions are all lined up before the "happy" code.

    • @DeGuerre
      @DeGuerre 2 года назад +1

      Even the nestiest of "nesters" agree that input validation belongs at the top of a procedure. I'm sure examples like 2:40 came from real (presumably novice) code, but to cast this as "never nest" advice is a bit of a red herring. The more interesting use case is algorithms and data structures which, as Niklaus Wirth pointed out, equals programs.
      Try "never nesting" code that perform B+-tree deletion or something like that.

    • @craigsparton
      @craigsparton 2 года назад

      @@DeGuerre No you're right, and I was using the term "never nester" a bit jovially. I agree that there is a place for most programming practices, even heavy nesting, and we must be careful following any advice that says "never" or "always" do something. While I think nesting should be limited as much as possible to improve code readability, in certain examples like the situation you mention it would actually improve readability compared to the alternative.

  • @wtcxdm
    @wtcxdm 2 года назад +93

    Thanks for the high quality video as always!
    A little suggestion though, instead of blurring other lines, how about highlighting the lines viewers should focus on? It will be easier for eyes on mobile.

    • @CodeAesthetic
      @CodeAesthetic  2 года назад +45

      Thanks for the feedback. I'll play around with some options for the next one and make sure it comes through well on mobile

    • @arturpendrag0n270
      @arturpendrag0n270 2 года назад +6

      @@CodeAesthetic Just blur + grayscale that way you will leave the code you need focus on colored while the rest would be discoloured

    • @reisaki18
      @reisaki18 2 года назад

      @@CodeAesthetic you can use this style. ruclips.net/video/6-mk6OpcUdM/видео.html

  • @macchiato_1881
    @macchiato_1881 2 года назад +15

    As always, follow coding paradigms with caution. Just because someone on the internet said don't do X thing, doesn't mean you should follow it all the time. There will always be edge cases to everything. While it is generally a good idea to keep nesting at a minimum, there maybe sometimes that you might want to nest a piece of code for conciseness.

  • @JasonJBrunet
    @JasonJBrunet Год назад +1

    I learned all my coding ways from the company I work for who hired me with zero experience. This video changed my life, and we are currently working towards implementing this on projects going forward.

  • @danny_the_K
    @danny_the_K Год назад +4

    Thank you for this explanation of never nesting. It help this beginner see some very bad habits I was creating. The exciting part for me was seeing you refactor via inversion, moving all the conditions and pre-qualifiers to the beginning of the code block and grouping the actual functional code after that… begin able to examine a block of code after putting down all the initial tests and rules will really help me a lot. I am always trying to do something way beyond my capabilities, so this should bring huge benefits to me. Thanks again.

  • @TimTom
    @TimTom 2 года назад +58

    I agree that indentation should be avoided when possible, and also that guard clauses are one good strategy to do that, but I think breaking your code into a ton a little functions makes it harder to follow what’s happening and makes it easier for bugs to slip in. John Carmack wrote a memo about this a while ago, look up “John Carmack on Inlined Code” to see a more thorough argument.
    Regardless, excellent video! Can’t wait to see more!

    • @cluelessdev3851
      @cluelessdev3851 2 года назад +12

      I totally agree, I found my self going up and down, up and down around some files because I had all these function calls... Not everything has to be a function, guard statements are often enough, and well designed code will rarely if ever go deeper than 3 levels w/o extracting into functions.

    • @coffeedude
      @coffeedude 2 года назад +14

      If functions are well named and tested there shouldn't be problems with understanding code that uses them, in fact they can make it quite easier

    • @cluelessdev3851
      @cluelessdev3851 2 года назад +9

      ​@@coffeedude You do have a point! Nonetheless at least in my line of work that's rarely the case (I seem to eat spaggetti every day) and well I sometimes have a "nag" to see how a function operates if that makes sense?

    • @brawldude2656
      @brawldude2656 Год назад +1

      @@coffeedudeI really love when I can tell what the code is doing in 10 seconds

    • @danny234555
      @danny234555 11 месяцев назад

      I think it's a bit important to note that the kind of nesting you're talking about is mostly visual, and you're completely fine nesting to infinity as long as each function is only visually 3 deep.

  • @neilmurphy7594
    @neilmurphy7594 2 года назад +4

    Thanks for posting, these are really great! I was a technical writer before I became a software engineer, and think about the aesthetic of code and cognitive complexity quite a lot.
    Other possible topics:
    • the declarative flow pattern you illustrate here (put every individual "thing your code needs to do" in it's own function, then compose in a main method at the bottom with a top-level try-catch),
    • phrase every boolean in positive terms (i.e. isLoaded vs. !isNotLoaded; every negative boolean in code as well as written/spoken word adds cognitive complexity because we have to mentally flip to understand),
    • factor out the individual parts of a compound condition into statements aliased to easy-to-read variables (if isUserAuthenticated && recentlyJoined)
    • writing code with the primary goal of minimizing the time-to-understanding of the next dev who has to read it

    • @vani9831
      @vani9831 Год назад +1

      It's very interesting you mentioned this!! I am a software engineer and I find myself so frustrated with the way people code and organise their code, that I am now the defacto documentation person in my team!! I am constantly writing pieces explaining the flow, thought process, context, memory concerns and so much more. All of this for the - COGNITIVE LOAD. All I wish for is the next person doing this after me to not have to spend years understanding the same thing. I find that Code organisation, comments, variable names, fonts, colors etc make a very big difference in how I subconsciously read code and affect speed

    • @vani9831
      @vani9831 Год назад +1

      Recently I was refactoring and cleaning up a single file of 13k lines and modularizing it. I work in C btw. I found myself telling the junior dev how to name functions.
      Subject-verb-object
      I.e. module_name-action-what_to_act_upon
      For example
      Custom_utils_generate_hash.
      This helped me create header files with almost tree like branching in names where I could easily read through it and find out what a module has to offer.

  • @comet9864
    @comet9864 10 месяцев назад +1

    I was expecting something far worse when I heard "never nester" but this is incredibly informative.

  • @_gheo
    @_gheo Год назад +46

    I'm extremely fascinated by the never nesting technique. I actually started using inversions and premature returns and I sure feel satisfied of my codes. There are always ways to improve since I'm a self taught, but damn, the elegance and readability sure feel great.

    • @timecubed
      @timecubed Год назад +1

      They really do. Especially in cases where you're using rust or something. Although rust is quite awesome, the syntax can get quite messy at times and using these techniques really do clean up code and makes all of my rust code quite concise and elegant and easy to read, especially the extraction one.

  • @sebikusik
    @sebikusik 2 года назад +215

    Now in my work I'm reviewing some code and excessive extraction is my number #1 obstacle. To verify how some simpliest things are calculated I need to constantly jump across different sections of the code, often having to look for them in various files. It results in having much more to remember in the code, because not only you still need to keep those additional conditions in mind, now there's another matter on whether there are no type conflicts, whether the functions work together, because it's pain in the ass to debug if every function works on it's own, but they don't work together when you run the whole thing.

    • @LizEllwood
      @LizEllwood 2 года назад +30

      Personally for me, I find the extraction to be significantly easier after everything is written. Sure, when starting out, you may end up 4 or 5 deep, but once you have it working, I think refactoring to avoid excessive nesting makes the most sense at least for me

    • @imblackmagic1209
      @imblackmagic1209 2 года назад +11

      I've seen some code with excessive extraction and poor naming, enough said i had to rewrite it all... i didnt even surpass nesting 3...

    • @madpuppet666
      @madpuppet666 2 года назад +36

      I'm not a fan of single use extraction, but also not a fan of deep nesting, so its a constant balancing act.

    • @madpuppet666
      @madpuppet666 2 года назад +6

      probably the main single use extraction I like is to represent proessing that only happens in specific states... ie. a finite state machine.

    • @TheEmolano
      @TheEmolano 2 года назад +8

      @@LizEllwood that's good thinking, it's the same as premature optimization, doing it will usually do more harm than good

  • @GenerallyGoodMusic
    @GenerallyGoodMusic 2 года назад +203

    I like this approach in moderation. When extraction goes overboard, it can get real annoying. Not a lot of functions are simple return statements. Trying to remember how 20 smaller functions work can be a lot harder than understanding the flow of a complicated function (if you document it well).
    I could possibly be traumatized by legacy code I'm working on right now...

    • @BanditTech
      @BanditTech 2 года назад +53

      this is one of the things that has me on the fence about this.
      Sometimes having everything in one function is very helpful.
      The metric I use to determine if I should refactor into another function is if we use it more than once.
      Or if the section of code can be replaced by a very well named function to make things clearer to read.

    • @-Jason-L
      @-Jason-L 2 года назад +5

      Separate intention from implementation.

    • @VeganSemihCyprus33
      @VeganSemihCyprus33 2 года назад

      Truth should be shared 👉 The Connections (2021) [short documentary] 👀

    • @cjbottaro
      @cjbottaro 2 года назад +10

      100% this. I might even say it's *worse* to spread the code across tons of other functions, methods, files, etc. At least if it's nested, it's all in one place. Then just use your code editor's code folding feature to make it easy to read.

    • @cmwhitworth
      @cmwhitworth 2 года назад +4

      That's what commenting is good for. The extraction is for readability and organization. You could argue that commenting nested code is the same, but it doesn't read the same.

  • @s.b.8121
    @s.b.8121 13 дней назад

    I clicked on this video half expecting something overly pedantic (still wanted to know though) and was pleasantly surprised by an actually very compelling argument for de-nesting my code (+ how to do so)! Nice video, I learned something with real applications :]

  • @fexofenadinaGenerica
    @fexofenadinaGenerica 2 года назад +26

    I'm glad I found this channel. It's so pleasing to see the code being organized. Keep up the great work!

  • @noxagonal
    @noxagonal 2 года назад +142

    I generally agree, after 3 or 5 indentation levels it gets harder to understand how deep you really are in the indentations, but I'm not really against nesting past 3 levels. I am against spreading the code around however, eg. "else" statements that are far apart so you have no idea what they're for at a glance.
    In fact I'm more likely to add an indentation or an immediately invoked lambda to contain relevant code in its own block. Mostly in situations where the block is relatively small, semi complicated but doesn't quite make sense to put it in its own function.

    • @cook_it
      @cook_it 2 года назад +1

      Back when I knew less I wrote some code with the else so nested and far from the if that I had to add comments just for knowing to which if the else belongs.
      With this video I could probably easily fix it but I'm afraid something will break so... my old code will just stay the way it is, at least until I get determined enough to do another larger update XD

    • @TubeTAG
      @TubeTAG 2 года назад +6

      Cohesion is important. Extraction only works when the thing you're extracting is a *cohesive* chunk of code.

    • @absolutewisp
      @absolutewisp 2 года назад +1

      @@cook_it That is how you know it's either time for guard clauses or a new function, or both

    • @cook_it
      @cook_it 2 года назад +2

      @@absolutewisp Inversion/guard functions would perfectly solve it and make it way easier to read.
      The problem is that it's part of my updater subroutine which checks if there's an update and starts the update sub if there is, which means if I mess _anything_ up I can't send out anymore automatic updates, which would require all users to manually upgrade to a hotfix version, which is just... no.
      So I will probably do it if I do a major refactoring of all modules, which won't be anytime soon as I don't get to work on that all that often and there are more important things to update first.

    • @evancombs5159
      @evancombs5159 2 года назад

      @@cook_it don't be afraid, just do it. It's a bad idea to let code rot. Just need to create some good tests to make sure any chance doesn't break anything.

  • @Fidooop
    @Fidooop 2 года назад +7

    Wow, you just opened my mind to the realization that I too have always been a never nester. I never thought of it this way, and I never had a disgust-o-meter for function depth, but I do extractions and inversions ALL the time to minimize the length of functions and to keep everything easy to read.

  • @lavenderghost2226
    @lavenderghost2226 Год назад +5

    Opposite condition to (top > bottom) is not < but

  • @Volatuhl
    @Volatuhl 2 года назад +8

    This is already an incredibly high quality channel, please keep it up!

  • @ImpossibleStudios-2023
    @ImpossibleStudios-2023 Год назад +6

    As a beginning programmer, I always hear my professors tell me to separate complex problems into several methods. this video is a visual representation of what they mean. thank you very much!

  • @ImranHaider
    @ImranHaider Год назад +30

    Moving the unhappy code to the beginning is not always a good idea because you're throwing off the branch predictor. By default, your CPU is more optimized to take a reverse jump before the condition is fully evaluated (useful for for-loops) and *not* take forward jumps before the condition is evaluated (useful to prioritize the first if-block). You can "solve" this problem by using __builtin_expect(your_condition, 0) , which will allow the compiler to reorder the generated assembly code such that the block is moved further down in the function. I use this technique sometimes when I find myself nesting too much but sometimes I find it cleaner to keep the "more likely" branch high above in the function.

    • @ChrisSchepman
      @ChrisSchepman Год назад +5

      This is clever but almost no one needs to worry about this. Premature optimization 99% of the time!

    • @ImranHaider
      @ImranHaider Год назад +14

      @@ChrisSchepman It's not really premature optimization until you've measured it and verified that the optimization isn't helpful. Modern CPUs rely heavily on pipelining and a missed branch prediction can be more than an order of magnitude slower.

    • @tomcutts9200
      @tomcutts9200 Год назад +9

      @@ImranHaider All code optimisation is premature if you don't have a particular reason to optimise that code yet.
      You might have slowest piece of crap code ever, but if it only runs occasionally optimisation is irrelevant. Or you might have an already very fast beauty which you've already mostly optimised with barely any room to squeeze more performance out it, but if it runs hundreds of thousands of times per second it's probably still a better candidate for optimisation than the really slow shit.

    • @ImranHaider
      @ImranHaider Год назад +5

      @@tomcutts9200 You shouldn't optimize your code based on how frequently it runs, you should optimize it based on whether it runs within the time you expect it to execute. For example, in a video game, you would optimize your rendering code so that it can finish by the time the next frame is about to be drawn on screen.
      Many developers do what you mentioned and they give very little priority to code paths that they think won't run as frequently. The application start up procedure usually falls in this category and this is why so many "professional" applications (like Microsoft word or Photoshop) take so long to boot up. Users of these applications actually care a lot about load times but developers don't prioritize it enough.
      All I was pointing out in my original comment is that you should be aware of how your platform (aka your hardware) is executing your code. This enables you to write code that works with your hardware instead of against it.

    • @tomcutts9200
      @tomcutts9200 Год назад +4

      @@ImranHaider I am a video game developer, and I have tools which tell me pretty much exactly how much of a frame's budget is spent in which function calls, so I don't need to guess what code is taking up all the time.
      If a significant chunk of time is spent in one place, that's the place to start looking for potential optimizations.
      I could try and find the bit of code which is doing it's specific thing the slowest, but if it's called once per frame it probably doesn't matter. Maybe it should take 1 ns but it takes 10ms, but who cares?
      There'll be some other code which should take 1ns, but it takes 1.1, but it executes 10000 times per frame. Even if I only shave off 0.1ns that's a much better choice for optimisation.
      You look at the thing that's taking up the largest % of your frame and you start there. And you prioritise the spikiest frames that take longer than average frames and see what can be done to optimise whatever is happening to cause the spike (and possibly see if you can flatten that spike by spreading it's work over multiple nearby frames).
      And yes, while application startup, and load times, are both important things that you don't want to get out of hand, they don't kill game sales nearly as quickly as framerates tanking and the game stuttering. Most customers would prioritise that you give them a stable fast game, over slightly annoying load times. People are prepared to wait a bit if the game is solid, but no matter how fast your game loads no-one will want to even start loading it up if the framerate is garbage.

  • @brianbarefootburns3521
    @brianbarefootburns3521 8 месяцев назад +4

    A former colleague of mine used to nest entire programs in an if (true) {} at the top of all his code. Someone spent a day while this colleague was on vacation trying to understand why one of these programs was indented one additional, unnecessary level in all places. When the problematic colleague returned from vacation, he explained that this pathological behavior was simply for debugging and as a “safety switch” he could set while programming. Our boss gently but firmly ordered him to discontinue this practice.

  • @Machtyn
    @Machtyn 2 года назад +13

    One of the things I learned from the Pragmatic Programmer is to write a function that does one thing well. And if it does that one thing well, you don't have to worry about it and can call it when needed. If your function is trying to do two things, that's pushing it, three things and you better start thinking about what you're doing and why. Sometimes you can't help it. But many times you can.

  • @camelCase60
    @camelCase60 2 года назад +61

    You’ve managed to articulate a code style I’ve stuck with for years far better than I can!
    Regarding your last example with the download queue, you could also point out that it’s much easier to unit test the de-nested code compared to the big block

    • @pierreturpin2901
      @pierreturpin2901 Год назад

      Actually, on the video sample, it doesn't change much the testing strategy.
      When testing, you want to target an unit which has a functional meaning, with scenario that makes sense. Generally, it is testing public actuators, controlled by public state, and asserted on public observable.
      For instance, with the download sample, one would really want that given some recoverable http error, then the execution is retried many times until a failure state.
      The handleHttpError method, or all other internal extracted methods are not testable as they don't have any particular functionality.

  • @JayMaverick
    @JayMaverick 2 года назад +149

    I'm an ex-content writer, now learning code. In the web writing world, we have headlines from H1 to H6 (and beyond), but it's generally considered sloppy and bad practice to go deeper than H3-subsections and H4-lists. If you find yourself building nested H4-subsections within your content, you need to revisit your structure.
    I see many parallels here!

    • @elissitdesign
      @elissitdesign 2 года назад +4

      Niiiice!

    • @adriangibbs
      @adriangibbs 2 года назад +2

      My brain works the same!

    • @kikefuentes5191
      @kikefuentes5191 2 года назад +3

      As a web programmer, I have to say: I think not allowing multi-line links in HTML is a crime. I know having to change a one-line link is easier, but I just want shorter code goddammit!! It feels bad to have well indented and well nested HTML look awful once you put a link that's like 170 character wide ;(

    • @charlesm.2604
      @charlesm.2604 2 года назад +1

      Because in both case it's about readability, less complexity means more straight-forward access to the information. Ultimately a deeply nested piece of code will work the same, it's just gonna be easier to read, maintain and extend.

    • @kiandronootto
      @kiandronootto 2 года назад

      I’m in the same boat. Ex content writer and I see the parallels

  • @NickCombs
    @NickCombs 10 месяцев назад +1

    Extraction is great, but like anything else it can become unwieldy if overused. Instead of loading the complexity into the imperative structure, you're moving it into the number of scopes and arguments passed into/through them.

  • @0xDevelopers
    @0xDevelopers Год назад +4

    Unhappy code first makes so much sense. It cleans up code and lets other developers understand easily! Love it

  • @carlolson932
    @carlolson932 2 года назад +14

    I think inversion can work to make a function more readable, but extraction almost always makes a function less readable. Scrolling between different functions is way more annoying and confusing than looking at another nested layer which is right there next to the rest of the code you're trying to understand.

    • @ChunkPlay
      @ChunkPlay Год назад +1

      Most of the IDEs nowadays allow you to split the screen, so you can literally have the same file twice in front of you, and just go to whatever second function you need. Works well for me

    • @skyethefox9899
      @skyethefox9899 Год назад +7

      If you name the functions properly you usually don't need to check the inner workings of every function call

  • @JasonWelch
    @JasonWelch 2 года назад +4

    This is how I've been coding for idk, 6+ years. I've preached earlier returns to dozens of programmers. Good stuff. I hope many watch this and it sticks like a thorn in their brain.

  • @notsharing5887
    @notsharing5887 8 месяцев назад +1

    At some point I became a never nester because once I took a two month break, returning to programming then spent like three days worth figuring out how everything worked again

  • @FarCough145
    @FarCough145 Год назад +14

    Sad clause before happy clause, that makes so much sense now that you say it out loud. I just finished a uni assignment (using java to program a really shit interpreter) and did this without realising because I was trying to avoid messy nests, but I had no idea what I was actually doing. I’m glad there’s a name for it and I can do it knowing it’s a good idea, unlike many of my “good ideas”.
    “Oh I should program my ENTIRE interpreter around arrays, right now it doesn’t matter that their size can’t be changed and it definitely won’t bite me in the arse later”
    2 days later: “oh shit I didn’t think about that specific case. Well I’m not rewriting every single method to take something other than an array so I guess it’s time to spend 2 hours “making the puzzle piece fit with a hammer”, as my mum described it.”

  • @marceloarrarte8535
    @marceloarrarte8535 Год назад +41

    Glad to know there is people like me out there. Also, it's wonderful that you didn't stick with the first trivial example and instead dug into a more complex and realistic problem to show the true potential of this kind of aproach to coding. Cheers!

    • @czernnobog5350
      @czernnobog5350 Год назад +6

      Too many functions is spaghetti code. Properly nested code is beautiful. Your team won't wait for you to refactor your code just to fit your own idea of "pretty code". If you can't handle and organize nested code properly, you are gonna be a NeverCoder pretty soon.

    • @nikoraasu6929
      @nikoraasu6929 Год назад +1

      @@czernnobog5350 if you can't create an optimized code then you're gonna be a nevercoder

  • @army9700
    @army9700 2 года назад +5

    In a year or two (even less maybe) when this guy blows up, these videos are going to be recommended as part of introductory CS courses in university the same way that 3Blue1Brown videos are for math courses at my university. Glad to be an early adopter!

  • @wueijun
    @wueijun Год назад +1

    I was taught this by my mentor in my first internship and honestly one of the most important foundations of my programming approach to date.

  • @luciusoflegend
    @luciusoflegend 2 года назад +16

    Before this video, I never thought about it. But seeing code de-nested, I agree. It's far more readable. I will most likely incorporate these strategies into my coding technique. Thanks!

  • @dune2themaker
    @dune2themaker 2 года назад +6

    I do this all the time , glad to see someone put it into words and make it so visual. Awesome work!

  • @georgehelyar
    @georgehelyar 2 года назад +8

    The important thing is to split code into logical blocks rather than to mindlessly follow a style guide or a linter.
    The % 2 example is an example of doing this wrong. Extracting there adds no value and makes the code harder to follow.

    • @sanderbos4243
      @sanderbos4243 2 года назад

      If the function was named filterEvenNumber() or filterEven() instead of filterNumber() it'd be slightly more useful

  • @TheRojo387
    @TheRojo387 4 месяца назад +1

    Denesting and functionisation only works if the same code will be used in multiple functions. If you HAVE to limit nesting, that's where the "inline" keyword comes in for the simpler functions.

  • @mia_bobia_
    @mia_bobia_ 2 года назад +5

    you've got some of the highest quality easily digestable programming videos out there dude! Keep it up ^-^

  • @sf-spark129
    @sf-spark129 Год назад +95

    I always compare coding to literature.
    As you grow more experienced and laureate, you will write less but deliver more.
    Given this, I always start writing code verbosely to meet all the requirements.
    Then, I trim down the fat by sticking to the core principle, being DRY. It's not ideal, but it works for me!

    • @musicdev
      @musicdev Год назад +2

      Completely agree. If I could write all my apps in one line of code I would. I’ve come to find that simple code tends to be the best code. Obviously not everything can be simple, but if it can be, it should be

    • @kevin_mitchell
      @kevin_mitchell Год назад

      Nice comparison.

    • @hematogen50g
      @hematogen50g Год назад +1

      Our programming gurus like to create long lambda expressions which looks sick unless you try to understand it. Also it is much harder to debug.

  • @lekicig
    @lekicig 2 года назад +8

    I wish this channel persists! The videos you post are so easy to process. Things that are important couldn't be better presented than you did.
    Good job!

  • @Deroge_1069
    @Deroge_1069 Месяц назад

    This style of coding is easily gonna save me hundreds of hours of confusion... thank u :)

  • @LucaDelloSterpaio
    @LucaDelloSterpaio Год назад +26

    Just here to say that the “inverted” (negated) condition of “top > bottom” at 2:21 is “top

    • @bodardr
      @bodardr 10 месяцев назад +1

      Do not, I repeat, never negate (!) numerical comparisons. This straight up harms readability.

  • @jeremieh5009
    @jeremieh5009 Год назад +5

    As a chronic nester this advice was very helpful! Hopefully I’ll be able to make my code clean as can be!

  • @sf2998
    @sf2998 Год назад +121

    Nesting isn't always bad or evil. Depending on your desired output, workflow & requirement, you may need to nest your code abit for the sake of clarity.

    • @sf2998
      @sf2998 Год назад +13

      the same goes with using multiple if...else and switch statements...😶

    • @Vespira21
      @Vespira21 Год назад +4

      Yes, you do have to create functions if it goes deep, to take care of some parts of the processing and prevent having all the visual spaghettis in front of our confused face

    • @hetuman
      @hetuman Год назад +3

      can you give example?

    • @nutelhere
      @nutelhere Год назад +6

      @@hetuman nested, although not if/else: a definition of a recursive data structure that represents many possible "pathes" (for example in a game) or shows relationship between sub-nodes (just like xml)

    • @hetuman
      @hetuman Год назад

      @@nutelhere Oh yeah! Good example!

  • @brian1204
    @brian1204 Год назад +1

    I’m beginning to appreciate this. I once held the belief that each function should have just one return/exit. I don’t even remember why; I think I read it somewhere/somewhen? It makes for some complex nesting and code paths!

  • @NeonFraction
    @NeonFraction Год назад +375

    I’m mostly a self-taught coder so videos like this are invaluable. Thank you so much! 😊

    • @GOTHICforLIFE1
      @GOTHICforLIFE1 Год назад +34

      You'd be surprised how little attention stuff like nesting, single responsibility functions, etc. are taught at university / college. You will be very lucky if you have a programmer that actually appreciates that as well as good logic and on top of that is your/a teacher.
      I've found that your best option is to find several sources of people that have a lot of experience and tailor to expert/intermediate audiences (even if you are not). That's where you start learning about design principles, abstraction, nesting, composition etc. I'm a python developer myself, and i can tell you that what i got prepared with from uni vs what i met when i started working is vastly different. Was lucky enough to find a channel called ArjanCodes which is exactly the type of channel i'm referring to when it comes to enhancing your coding levels. They help you pick up good habits early on and keep you on the right path of good practices

    • @ritchi465
      @ritchi465 Год назад

      @@GOTHICforLIFE1 I was about to point out the same things. Uni just gives you the basics of programming. Learning about coding best practices enhances your programmer level to another level.

    • @thunder____
      @thunder____ Год назад +1

      @@GOTHICforLIFE1 mCoding is another good channel focused on intermediate/advanced programmers (particularly Python and C++ devs), but I particularly want to mention Corey Schafer, especially as he just posted a new video after like a couple years off; I've found that Corey's channel does a great job of at least mentioning more advanced concepts while keeping the videos very accessible and beginner-oriented. I believe his videos are almost all about Python though, but for anyone learning Python, I highly recommend Corey Schafer's channel, and for anyone new to programming who's starting off with a language other than Python, I highly recommend switching to Python (at least while you're learning the basics of programming) and also Corey Schafer's channel.

    • @T1Oracle
      @T1Oracle Год назад

      I was self taught, but I also kept reading to make up for it. This was eons ago, so books are less popular now, but The Pragmatic Programmer and Code Complete have timeless wisdom. Then there's the "Gang of Four" Design Patterns book. After that I would suggest learning SOLID design principles.

    • @gladwinj3389
      @gladwinj3389 Год назад

      @@T1Oracle ty for that

  • @detaaditya6237
    @detaaditya6237 2 года назад +6

    I agree that we shouldn't cram nested statements in one place. But extraction kinda makes the code becomes more... jumpy? Like, it requires the reader to jump around the code in order to understand what's going on. What do you think about this?

    • @arvinlaya5781
      @arvinlaya5781 2 года назад

      Technically it is. But you can view it in a way that it makes the code easier to understand on a high level by turning huge complicated blocks of code into a single easy to understand function. It's like putting comments except you put the chunk of code out and leaving a label if you know what I mean.

    • @jaypaans3471
      @jaypaans3471 2 года назад

      I hear ya. I'd say you would be MOVING CODE

  • @qulien7123
    @qulien7123 2 года назад +5

    Another simple but handy feature I often use to remove an if/else statement is the *ternary* operator. Obviously this gets ugly and hard to read for more complicated statements, but for simple assignments based on a simple condition, it not only saves a level of indentation but also reduces several lines of code down to one.

    • @yash1152
      @yash1152 2 года назад

      yeah same, i love ternary operator when it works.
      what do u do when it has to do only one way selection? i.e. when there is no action for the "false" situation?

    • @qulien7123
      @qulien7123 2 года назад

      @@yash1152 Depends on the language. In PHP, there is now the `??` operator that can be used in such a case. `$foo = $lol ?? $bar`, which is basically `if (isset($lol)) { $foo = $bar }`, or `$foo = isset($lol) ? $bar : $foo`. If the language doesn't have such an operator, I usually just go with one-line, braceless if-statements. `if (lol) foo = bar`

    • @yash1152
      @yash1152 2 года назад +1

      > _"$foo = $lol ?? $bar"_
      > _"If the language doesn't have such an operator, I usually just go with one-line, braceless if-statements. `if (lol) foo = bar`"_
      @@qulien7123 c/++ does have the ternary operator, but it doesn't allow skipping the colon as far as i remember. one-liner is nice idea. i will use the brace-d version of it. thanks :)

  • @omarcrosby
    @omarcrosby 6 месяцев назад

    Well said! I've been doing this for years so I guess I'm a never nester too. :)
    Another thing to note is that by following these suggestions you also make code easier to test.

    • @felixg2062
      @felixg2062 2 месяца назад

      My first big project made me a never nester. It was really bad I didn’t understood oop and nested anything. But now I bring light to the dark and evil code

  • @reyisaacjr.8901
    @reyisaacjr.8901 2 года назад +4

    Wow, as a CS student, I love your videos. It's a breath of fresh air.

  • @jada90
    @jada90 Год назад +6

    Lol as soon as you defined it as never going more than 3 deep I'm like "yeah, every programmer knows that's a nightmare and avoids it whenever possible"

  • @dexio85
    @dexio85 2 года назад +4

    There are some reasons not to invert - technically the most likely path should be the one that if statement tests for. So writing the unlikely if (bottom

  • @gristlelollygag
    @gristlelollygag 11 месяцев назад +1

    The real refactoring in C or C++ should've been realizing you have a completely extraneous condition as well as another easily resolvable one
    ```
    int calculate(int bottom, int top)
    {
    int sum = 0;
    bottom += bottom%2; // Start from the first even number
    for(int i = bottom; i top, then we will likewise return 0, as the loop doesn't even begin...