Escape Nesting Hell - Do This Instead

Поделиться
HTML-код
  • Опубликовано: 27 янв 2022
  • Learn how to improve your if statements in Unity to make them cleaner, more readable and easier to maintain using guard clauses.
    SUBSCRIBE
    Subscribe for more game dev tips and tutorials: bit.ly/3edJUA5

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

  • @codichor6036
    @codichor6036 2 года назад +869

    Being able to make your code look like a flat list of instructions vs some kind of pyramid shape is really overlooked but it's a total lifesaver when you're hunting bugs.

    • @JamesMakesGamesYT
      @JamesMakesGamesYT  2 года назад +50

      Definitely! It even helps you recognise opportunities to refactor that you might not have spotted if your code was nested

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

      It doesn't just look cleaner and easier to find bugs, it's also easier to add extra conditions afterwards without messing with the entire indentation tree and shifting every other condition an extra tab to the right.

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

      ​@@JamesMakesGamesYT i refactored your statement... 🙃
      You should really consider getting rid of redundant accolades...
      (see my contribution somewhere in this comment section.)

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

      @@powerpc6037 also you can make lines of code longer

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

      Its not overlooked by people who hire you tho (:
      Its overlooked by rookie devs who just started coding and it really slows down their learning by a lot

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

    I've always heard this referred to as an "early exit". It is one of the easiest ways to greatly improve readability.

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

      Yeah, I also use it on daily basis and call it "guardians" because they guard the rest of code where you can't pass e.g. undefined value or unresolved task. It really makes it easier to read and manage the logic.

  • @cappydev
    @cappydev 2 года назад +387

    Beginner programmers, take notes! Readability and structure is king in systems

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

      Maintainability and performance*

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

      @@dr_birb Of course, it should be structured for maintainability and performance

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

      @@dr_birb code is for people.
      Your CPU reads only 1 and 0.
      Humans read code. Code is for humans.
      Make your code readable to other humans is the first priority of your code.
      If no one can follow your code.
      You will eventually not be able to follow your code.
      Coders must write readable code. It is the top tier metric. Anything can be fixed that can be understood.
      Something that cant be understood can't be fixed.
      And code always changes.
      It's in the name. "Software"
      If code never changed. We would just be making hardware.

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

      @@mortenbork6249 holy fuck learn to write like a human.
      Also no. Code isn't for humans, code is for computer. Humans are paid to read and write the code, even if it isn't easy/simple.
      Maintainability and performance was is and will be the most important thing in projects that are constantly evolving.
      Sure, most of the time writing clean and readable and minimalistic (simple) code is also good performance wise and is scalable, but that's not always the case, and that's why it's not the king.

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

      @@dr_birb Actually, code is for humans, it just is also for a computer. Most code we write is in a higher-level language that is interpreted through multiple steps into machine language. HLL is literally designed to be easier to write for humans. If humans can't understand the code easily, it makes it very difficult to maintain the code and even make it efficient in the first place. Code acts as a bridge between human ideas and a computer's execution cycle.

  • @Ishanatmuz
    @Ishanatmuz 2 года назад +238

    I have been using this approach for 5 years now. Everywhere from servers to frontend to Unity.
    Never knew it was called guard clause.

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

      Same here man. Never knew the name

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

      I found out about the name once I googled for if it makes any difference or if it was bad practice (I was wondering if the code would get larger when compiled, speed performances, etc...)
      but now I do it all the time...

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

      Web dev here, I've seen this approach under the name "Early return pattern". Funny to see how good practices propagate even with different names.

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

      Me thinking I was going to learn something new (:

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

      I knew it as "Early returns". It's quite standard approach in Python for example.

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

    YandereDev HATES this man for using these simple tips !!!

  • @dorky5256
    @dorky5256 2 года назад +42

    That is actual genius. I've had so many cases where this was a real problem having so many stacking if statements. Great tip

  • @elriano1
    @elriano1 2 года назад +76

    These are exactly the sort of Unity videos I have been searching for, concise, informative and actually applicable. Please continue to make more!

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

      Start looking for general programming videos and not Unity videos. This video applies to any language.

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

      @@ChrisD__ Not any language, but pretty much any imperative one

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

      @@ultimatedude5686 Shhhh, we don't talk about functional programming, we're game developers! It scares us.

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

      I dont know. I think we need a few more videos on how to make a square move and jump.

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

    Concise yet informative! Love seeing videos that don't unnecessarily bloat simple concepts.
    For those looking for more videos of this nature (code structure and design), search for that and leave out things like Unity and C#. It's general programming advice you're looking for. Which is the same whether you're making a game, website, api... You get it.

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

    Been programming for a few years now, always had an instinct to take advantage of the empty else but I never thought of this. Thank you so much

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

    I have no words.. as soon as I realised what you were doing my mind was blown and my code will be changed for the better forever. Thank you!

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

    This is amazing. Guard clauses! I will be using them from now on. Thank you.

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

    a very nice, short and informative video! You explained so well in such a small amount of time! Thanks

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

    I've beem programming for 10 years, not games, but this is a really good way to explain this.
    The way I visualise it is like a freeway, with exits. Most traffic goes along the freeway, but if there are certain conditions, they will exit with certain actions as per the criteria.

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

    It is always good to have a reminder of good practices and patterns.
    thank you for sharing!

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

    I wish someone showed me this when I was starting out. This make both code easier to read but also so much easier to teach and understand.
    You should make a bunch more of these and in the same 'snack' sized way..
    Thanks man, this is an eyeopener.

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

      Glad the video was helpful!

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

      i started coding on roblox and so im used to return being to give the output of a function, but after learning that it was to return back to teh top of a method i just though "jesus christ im an idiot how did i not know that before"

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

    I remember going from always doing your first example, to learning about the second. I always love these moments

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

    I've used them but without knowing how effective they can be and your video shows it! I'll use them more!

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

    This was a game changer for me when I first started writing code like this.

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

    This has helped me quite a ton! Thank you so much!

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

    Awesome video. So informative about writing beautiful and maintainable code. Thanks. Please keep these coming.

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

    this is the kind of thing that make sense, but didn't think about until now. Thank you very much. Not a solve all for everything, but i feel like i can do great work with it.

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

    More tutorials like these are NEEDED on RUclips thank you!! I've always looked for things like this and having a video going over it is incredibly helpful

  • @tyt-no-udee-nick
    @tyt-no-udee-nick 2 года назад

    This approach works perfectly in almost any language and technology. I'm used to be a React-developer and my code became much clearly when I started to use guad clauses

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

    Simple, clear, straight to the point. I really like it, keep it up!

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

    Brilliant, please make more videos man, you're explaining so well!

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

      Thanks! Have a few more videos in mind, but they might be a bit delayed

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

    I have used this concept before, but I neither thought I could make my code clean with it, nor did I know it's name. Thanks!~

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

    Wow! This opened my mind now! Thanks for the tip.

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

    I am not a programmer at all, but I am amazed that I was even able to understand the issue and the elegant solution offered offered to resolve it! Crazy!

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

    I'm trying to develop a game, making it first time, so your advices very useful, thank you!

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

    Thank you for the tip! It really makes life easier as a newbie coder.

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

    Short Video but make a huge impact on my knowledge.
    Sir, you are a lifesaver!!!

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

    Much love!!! I really needed this one to clean my code up :D

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

    Great video! We use the exact same method in games company I work for. We are actively reviewing on clean code approaches like this. Good you point this out! 👍

  • @Mr.Not_Sure
    @Mr.Not_Sure 2 года назад +40

    I usually oppose to use guard clauses. It can give you headaches when they're hidden somewhere in the middle of a method. The only acceptable case is when guard clause is RIGHT at the beginning of the method so it clearly visible, and it is for error-checking.

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

      While I agree that the best place for guard clauses is normally at the start of a method, I want to address what you said about visibility... If your methods are long enough that it's hard to spot something like that in the middle of them, they are probably way longer than they should be to keep code optimally readable/maintainable/extendable. Imo a method/function should normally have just one responsibility, if they need other stuff to be done they should delegate that responsibility to helper methods. In my experience if you consistently follow this your methods do not need to get long enough that visibility of guard clauses are an issue. SRP and the other SOLID principles are widely agreed upon for good reasons.

    • @Mr.Not_Sure
      @Mr.Not_Sure 2 года назад +1

      @@JonasBergling I completely agree with what you said. Have to say it's just my personal story of one of my colleagues whose code was really terrible. It made me oppose even to completely valid language features like default values! And yes, I'm talking about one specific project, not in general. Your mileage may vary.

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

      As with all tools the utility comes from the user.

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

      I agree, we should be careful to avoid the creation of "hidden" behaviors when using guard clauses, like you said. For that, I think we must put some effort to respect the Single Responsibility Principle, in this way our code tends to be more readable.

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

    Thank you, it will help me a lot! In a kind of way, it's a very obvious solution, but it's one of those that I've never thought about.

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

    Suppose you want to add some code at the end of everything, common to all cases (for example a special check that is always legit): now you have to rewrite everything as it was before... This reasoning can be done for completed functions that you already know what they do and so you can see that the code can be optimized. Not all functions are so straightforward!

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

      Sorry if I'm misunderstanding you, but if you had to add something like this that would always trigger, you would just place it before your guard clauses are reached.

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

      @@trancejockey Maybe it's something that must be done after you "attacked", if you was eligible to do it. If you can't attack, anyway I do something. Maybe a winning condition that is reached anyway (bleading effects):
      if CanAttack() then Attack();
      UpdateLife();
      if Has0LP() then PlayerWon();

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

      @@FedericoSpada13 If it was something that had to happen at the end of the method (eg bleeding effects as you said), I would change the output of the guard clauses (setting a flag to false instead of returning for example), or extract the guard clauses into a separate function as in your example, which can trigger / skip the attack. My point being, we should always use guard clauses, and not return to using nested ifs as you said in your first comment.

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

      @@trancejockey yes, you are right about the flag, but I think that it depends from case to case.

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

    oh wow, hadn't even considered that before. Looks so much nicer. genuinely a life saver.

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

    This is great! I have used guards clauses before, but not consciously. From now on I will.

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

    Thanks from Turkey. I subscribed. I will look forward to see more of this kind of content.

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

    i have learned this from a programming tips video 2 years ago with my colleagues, we still refer it as the most impactful tips for our career lol

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

    Guard clauses are really helpful, a thing that all programmers should know, and it was well explained, very good

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

    It's always nice finding out there's a name for stuff I've been doing for years

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

    Obviously as a programmer you know these things are possible but you rarely ever think of it, good video and thanks for the tip!

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

      Glad it was helpful!

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

      That is true specially when participating in a gamejam or have a deadline... unless this is a habit, you won't remember this good practice.

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

    I strongly believe you have the best tutorials i ve seen so far. This is a pattern people should use more in their codes . Cannot count the times i ve opened my old game jams and seen 10 if statements in a row.

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

      Thanks for the kind words! Trying to create more of these types of videos in the future

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

    I love these kind of stuff. Thanks for sharing.

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

    Talk about a helpful tip for programming in general! I remember some old projects in Visual Basic where I often needed to populate elements on a form with values pulled from an array, but doing so (necessarily) triggers the elements' defined "changed" event (which in this case updates said array with those values). As the versions of that language (VB2, 4, and 6) did not support programmatically adding/removing event handlers, my hack was: prior to populating the form elements, I set a global form variable (I called it "SkipEvents") to indicate there is an automated process running, and each "change" event routine likely to be triggered during that process would immediately check this variable first and if set, it would do nothing but return. (Not too different from using a *try...catch* block when you're running a routine that could reasonably experience errors.)

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

    That's awesome. Such a neat demonstration. Made total sense. I'm going to go try it out right know! Cheers buddy.

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

    Wow....So simple yet so effective!
    Nice, thanks!

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

    // Really useful, clean and optimized!
    // I love short tutorials like this!

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

      A commented comment? Clever

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

      -- Agreed, also applicable to e.g. Lua
      { and even good ol' Pascal, }
      # anywhere, really.

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

      @@zendakk

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

    thanks james! this is gold for me as a self taught programmer!

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

    This is a great video. Saving this one. Thanks.

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

    ive been doing this subcontiously for a while thinking it is bad practice bcs a lot of callbacks and stuff that make the overall code and executable larger, i was constantly trying to stop but while writing i just did it over and over, its nice to see that ive actually been doing good

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

    I have to maintain code with a lot of these nested condition structure. Thanks for making the world a better place!

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

    Code readability is something that separates junior from more experienced coders. This is one tool to make code easier to read and maintain.
    My only further suggestion in this example would be to group all your guard clauses into a single method. Then the intent of the code would be even clearer:
    if(!ValidateAttack()) return;
    Attack();
    If I'm glancing at your code I'm not concerned with why the attack should not be valid, only with that it could be invalid.
    Great tutorial!

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

      That's a great idea for further refactoring of the code! I like how even something as simple as guard clauses can open your eyes to further improvements that you wouldn't have spotted before

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

      @@JamesMakesGamesYT Iterative refactoring is a gift that keeps on giving

    • @a-minus-b-equals-a
      @a-minus-b-equals-a 2 года назад +1

      @@SanderDecleer Given that we're in the context of Update(), I'd argue that 'if(ValidateAttack()) { Attack(); }' would allow better extensibility. Said that, I'd probably extract it to its own AttackIfValid() method, where using ValidateAttack() as guard clause makes more sense.

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

      @@a-minus-b-equals-a once more than just attacking is used in the update I fully agree with you. I personally would make a method like HandleAttack() or something, this could be placed in the update together with HandleMovement, HandleInteraction...
      I guess this comes down to preference and convention within your team, the main goal of having more readable code has been achieved. Refactoring between my preference, yours, or most sane others would be trivial.

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

    I have been using this for ages and I love it. It is the first time i know what it is called!! Guard clause !!!:))) 👍😊❤️

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

    Good piece of tutorial. Thank you very much and keep it up.

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

    I was just wondering about this. Nice to know.

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

    I always use guard clauses in my code. It just makes more sense to me to bail out early than to nest all my code inside of conditionals.
    Obviously there’s a time and a place for them but this is a perfect example!

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

    This is helpful in more than just Unity. Amazing video.

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

    Your voice is so cool and your content is actually useful.

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

    Been doing it for years, never knew it's an actual thing lol
    Great video

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

    It is possible to add one more step, it adds all the conditions in an array and applies the "All" (or "every" in javascript) method.
    This even giving you the possibility to add conditions from other places.

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

    I never thought about using return this way... nice trick.

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

    Thanks for sharing this great technique!

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

    Nice thumbnails James! Also I love the way you cut out the empty space, only including relevant clips, most tutorials don’t do that :)

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

    Although I've never knew what it was called I have been using guard clauses. It made logical sense, in order to speed up execution (especially on an update/tick method) you want to return as soon as possible. I understand what you were trying to teach in this video (and I'm sure it's not the point but just something I noticed) you only only have it check for one button which makes sense for the purpose of this video but in the case of checking for multiple controls, a switch statement would be better and then set the default condition of the switch statement have the return as you don't want more if statements in your code as if statements are slower to run(especially if you are checking for control inputs) for every key when you can have a switch statement to handle all input. Maybe even a general boolean for if a key has been pressed then just return if that bool is false. Like I said, I know that's not the point of this video but just thought I'd share an example for handling controls. Cheers!

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

    In Swift, ‘guard’ is actually a language keyword. It takes a set of conditions and it requires to break out of the block (e.g. return from the method).
    imho that’s a very nice feature, it makes the core even easier to understand.

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

    That is a good start. I would also add that all the if should be extracted to a guard method that returns a tuple (bool isAttackable, string message) = CanAttack(..); Methods must only do one thing. This one is doing two: 1. checking to see if you can attack, then if you can then attack. This makes the code much more testable.

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

    This is about the first practical thing that I’ve learned about coding.

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

    Super Helpful Video. Thanks For Making It.

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

    Worth noting this technique applies to all areas of software engineering, not just game dev. I employ this same method all the time in backend web development, and I call it out whenever I see someone doing it wrong in pull requests.

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

    Ah, short videos with no time wasted. Subscribing for that simple reason

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

    When I was in University the teachers always said to avoid (just dont do it) having multiple return statements in a function, especially if the function has no return value. It is (was maybe) considered bad programming

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

      Good or bad is always situational when you think about it. Do whatever fits your needs in practise. In this example, 'return' just act as nothing but 'terminate here' so it is okay in this situatuation.

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

      It is really good in this tutorial to show how the simple inversion of the logic completely untangled the flow, but I agree in practice you want to avoid bloating a source file to twice the required line/character amount. Just use else ifs and put the attack in the final else and we can remove half the lines of code in that example.

  • @monkeyrobotsinc.9875
    @monkeyrobotsinc.9875 Год назад +1

    really great advice. thank you.

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

    Awesome. I've never thought of this before.

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

    I do try to keep my if statements separate but I've only used guard clauses without knowing they have a name and only a couple times. I'm about to refactor several scripts so this video will come in handy!

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

    Love it, not just unity, it applies to programming in general. Would love it if you give more tips on c# and unity

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

      Didn't you read the videos title? This only works in unity, and you can't even do it in regular c#, much less any other language with if-statements. Clearly.

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

    I have heard of something like a clause that can clean up code I didn't know exactly what they were talking about back in the day but now I just started to learn Unity & C++ I kinda understand what is happening

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

    That is pure logic. We are so conditioned (pun intended) to check what IS that we do that even when it's more logical to check what IS NOT. Excellent video man.

  • @R.B.
    @R.B. 2 года назад +54

    The cautionary note here is that a function shouldn't have multiple returns if it can be avoided. Enter at one point, exit at another. What if there are multiple conditions which must be met for an action? Something which can help is a local boolean flag which can set a condition. In this example you are only writing one thing based on the state, but it might be better to have multiple conditions reported. Having a boolean shouldAttack initially set to true and then setting it to false and falling through the guard instead of returning, you can check all those other conditions as well. Then for the final attack call, put a guard which checks should attack. In this way you've decoupled that logic again but you don't have a bunch of checks which can all drop out of the method. A true guard check is one which is looking for conditions which might break the function, is the parameter passed into the function null, sort of thing. Short and not complicated logic. As a personal style choice, this is the only time I use an if statement on one line and only then if it is very well understood why. Anything more complicated like your example, I'd rather use the flag because it further breaks it up into guard, condition, and (conditional) action.

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

      @Ryan Beesley Care to show an example?
      Will be easier for us to understand what you mean.

    • @digdug1431
      @digdug1431 2 года назад +37

      @@Ishanatmuz What Ryan suggested is this:
      private void Update()
      {
      bool shouldAttack = true;
      if (!Input.GetMouseButtonDown(0))
      {
      shouldAttack = false;
      }
      if (IsSprinting())
      {
      shouldAttack = false;
      }
      if (IsBlocking())
      {
      shouldAttack = false;
      }
      if (IsJumping())
      {
      shouldAttack = false;
      }
      if (shouldAttack)
      {
      Attack();
      }
      }
      In this small case there isn't really any difference, but the main advantage of this code is that it is easier to find bugs because all branches pass through the final if statement, allowing you to place a breakpoint there and see what state the code is in right before it exits.

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

      @@digdug1431thx mate. I think this might be better approach becouse it doesn't contain those returns which are messing with whole update function if you want to have more than one action.

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

      @@digdug1431 Thanks for the explanation

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

      Guard clauses rely on multiple return statements and that is not bad. It makes alot of sense to return a function right after a condition is met, since you then KNOW what will happen. If you dont return, somewhere else in the code you can mess up the flags making the code hard to debug. Returning is good!

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

    Really nice hint mate!

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

    I was stunned for a moment, why didn't I think of that.. my codes were spaghetti..
    And thanks for making it quick!

  • @EnricoDias
    @EnricoDias 9 месяцев назад +1

    Better yet, use chain of responsability. A list of classes implementing the same interface, each one checking for a specific condition. The method walks the list of classes before performing the action and returns early if any of them fail. That way you just need to add a new entry to the class list when adding a new restriction, leaving the original method untouched.

    • @pmoneyish6869
      @pmoneyish6869 4 месяца назад

      This is interesting. The question I have around this would be how is each condition class getting the data to do the checks?

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

    short and well explain, thanks for the advice

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

    Wow! In 2 mins I learned how to use if statements correct (Thats good that i don't have situations like that).

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

    I didn't know i needed this

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

    This is a good way! :)
    IMHO you could improve it with case-switch: removing all those 'if' and using a single 'return' a the end.

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

    Wow its so simple , but i never thought of it.

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

    What is good about this is that it doesn't just apply to unity. Readability is so important even when it's just a solo project, the larger a project gets the more time it takes to debug and i'm willing to bet that very few people actually enjoy debugging.

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

    Wow, I need more of this.

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

    I use godot, but the way you coded this made me improve my movement code!

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

    I always use guard clauses. Excellent!

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

    Thankyou. This will come in handy...

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

    Unity 관련 영상이지만 엄청 유용하게 활용할 수 있겠네요. 감사합니다!

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

    Love guard clauses. One of Riders best features is pointing them out

  • @carlosmspk
    @carlosmspk 2 года назад +57

    Just want to point out you're unlikely to implement guard clauses when scanning for inputs. If you also want to monitor for another button press, the code shown here doesn't work. You'd have to go back to the original if, and switch the guard clauses with "if-else"s without returns.
    Guard clauses are better for "errors", be it checking for actual errors like null pointers, be it for checking for invalid actions (like the IsSprinting(), etc., in the video).

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

      In use case you mentioned, it certainly does not matter the way you write, and every way works for non-combining presses (mind I'm not writing in any particular language here, its an amalgamation of C++, C# and Java, and not using Unity API at all):
      if (button == A) { buttonA_action(); return; }
      if (button == B) { buttonB_action(); return; }
      buttonDefault_action();
      if (button == A) buttonA_action();
      else if (button == B) buttonB_action();
      else buttonDefault_action();
      switch (button) {
      case A: buttonA_action(); break;
      case B: buttonB_action(); break;
      default: buttonDefault_action(); break;
      }
      For multiple presses you can also write differently:
      if (buttons.pressed(A)) {
      if (buttons.pressed(B)) {
      buttonAB_action();
      } else if (buttons.pressed(C)) {
      buttonAC_action();
      } else {
      buttonADefault_action();
      }
      }
      In the return way it will look like this:
      if (buttons.pressed(A) && buttons.pressed(B)) { buttonAB_action(); return; }
      if (buttons.pressed(A) && buttons.pressed(C)) { buttonAC_action(); return; }
      if (buttons.pressed(A)) { buttonADefault_action(); return; }
      // or buttons.pressed(A) && !buttons.pressed(B) && !buttons.pressed(C)
      So how come anyone would ever think of the code below as reasonable at all? It repeats the same clauses and looks like a mess by those very long expressions. The reason is the same as in the video: we are separating the logic from the actions, in a slightly different way: before each action there is a description on where this action would occur. We can bring out each guard into own method, which would make the code describe itself:
      public bool actionABReady(buttons) => buttons.pressed(A) && buttons.pressed(B);
      public bool actionACReady(buttons) => buttons.pressed(A) && buttons.pressed(C);
      public bool actionADefaultReady(buttons) => buttons.pressed(A);
      if (actionABReady(buttons)) { buttonAB_action(); return; }
      if (actionACReady(buttons)) { buttonAC_action(); return; }
      if (actionADefaultReady(buttons)) { buttonADefault_action(); return; }
      This means before each action there's a description of when this action would occur, completely separate from all the other actions (and probably the "return;" might be not be appropriate unless you are trying to write something like "do only one action per logic call", but without them it would rather be difficult to call it "guards" despite doing the same sort of refactoring as the video is trying to direct you to)

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

      A more practical example: imagine a top-view 2D game. You move on keyboard arrows (speed = 1, diagonal vector being longer is ignored for this example), and their movement can be combined.
      Here is a structural if-else code (again, syntax does not make sense):
      if (up) {
      if (left) move = (-1, 1)
      else if (right) move = (1, 1)
      else move = (0, 1)
      } else if (down) {
      if (left) move = (-1, -1)
      else if (right) move = (1, -1)
      else move = (0, -1)
      } else {
      if (left) move = (-1, 0)
      else if (right) move = (1, 0)
      else move = (0, 0)
      }
      Here is a guard-like code:
      move = (0, 0)
      if (up) move.y += 1;
      if (down) move.y -= 1;
      if (left) move.x -= 1;
      if (right) move.x += 1;
      // and that's it
      Now tell me which code do you prefer. You may tell me "I would never even think of writing the code the first way!", but I did write it like that when I was learning, and that's exactly the purpose of the video - to teach beginners on how to write more readable, more humane code, to make it less like mathematical robotic combinatorics and more like realistic causal chains, where it is clear what action each piece of code does.

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

      No, this is not necessary. In most programming languages, you could simply define several buttons as
      handled = handle_arrow_up() or handle_arrow_down() or handle_arrow_left() or handle_arrow_right()
      then let each of those function handle their own button and let each return a boolean indicating whether the function ultimately invoked the handler.
      If the buttons require overlapping guard clauses, they can either be placed before the button handler,
      or moved to a function, depending on what's most efficient.
      If you have many buttons to handle, you might be better off calling a function from a lookup table rather than use if/else logic.

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

      Note that when I said "You'd have to go back to the original if, and switch the guard clauses with "if-else"s without returns" I didn't mean there wasn't a better way to do it, I just meant you couldn't get away with the if(...){...return} guard clause. Of course you can always extract methods, and create handlers, but that's not really about what this video is about which, despite the title, is guard clauses.
      You could, however, argue that you can always implement these same guard clauses in each button handler.

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

      @@carlosmspk Advocates of guard-clauses frequently also advocate for separating out code to functions even if the code is used only once, for semantic clarity. Even if the guard-clauses doesn't work in a specific instance, other techniques can be used to reduce the indentation and improve readability.
      Guard-clauses are part of a technique that works great for almost anything.

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

    I want to learn Unity.
    Whenever I decide to do this, this will help me quite a bit. :)

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

      Thanks, I'm glad the video helped!
      Now is a really good time to learn Unity, there's a lot of great resources online to learn for free.
      Unity have example games that you can download and add your own mechanics to, like a Mario kart clone and a FPS

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

      @@JamesMakesGamesYT
      Thank You, sir.
      You're quite helpful;
      I genuinely appreciate it!

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

    We need more videos like this

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

    Great work ! This kind of tips are very useful for improving our dev skills there is other content like this one ? and can you suggest me other creators like this ? :)
    You won a new subscriber !

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

    Wow, i have been using this but didn't know the term ❤️