Escape Nesting Hell - Do This Instead

  Рет қаралды 267,709

James Makes Games

James Makes Games

Күн бұрын

Пікірлер: 506
@codichor6036
@codichor6036 2 жыл бұрын
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 жыл бұрын
Definitely! It even helps you recognise opportunities to refactor that you might not have spotted if your code was nested
@powerpc6037
@powerpc6037 2 жыл бұрын
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 жыл бұрын
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 жыл бұрын
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 жыл бұрын
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.
@Ishanatmuz
@Ishanatmuz 2 жыл бұрын
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 жыл бұрын
Same here man. Never knew the name
@phitc4242
@phitc4242 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 жыл бұрын
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 жыл бұрын
Me thinking I was going to learn something new (:
@Alche_mist
@Alche_mist 2 жыл бұрын
I knew it as "Early returns". It's quite standard approach in Python for example.
@cappydev
@cappydev 2 жыл бұрын
Beginner programmers, take notes! Readability and structure is king in systems
@dr_birb
@dr_birb 2 жыл бұрын
Maintainability and performance*
@cappydev
@cappydev 2 жыл бұрын
@@dr_birb Of course, it should be structured for maintainability and performance
@mortenbork6249
@mortenbork6249 2 жыл бұрын
@@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 жыл бұрын
@@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 жыл бұрын
@@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.
@dorky5256
@dorky5256 2 жыл бұрын
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 жыл бұрын
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 жыл бұрын
@@ChrisD__ Not any language, but pretty much any imperative one
@ChrisD__
@ChrisD__ 2 жыл бұрын
@@ultimatedude5686 Shhhh, we don't talk about functional programming, we're game developers! It scares us.
@tonynussbaum
@tonynussbaum 2 жыл бұрын
I dont know. I think we need a few more videos on how to make a square move and jump.
@spiralingspiral72
@spiralingspiral72 2 жыл бұрын
YandereDev HATES this man for using these simple tips !!!
@Ryöken17
@Ryöken17 5 ай бұрын
XD that was the early project
@marzzbar
@marzzbar 2 жыл бұрын
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.
@lorderu1
@lorderu1 2 жыл бұрын
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!
@LazerMarsupial
@LazerMarsupial 2 жыл бұрын
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 жыл бұрын
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"
@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!
@Mr.Not_Sure
@Mr.Not_Sure 2 жыл бұрын
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 жыл бұрын
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 жыл бұрын
@@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 жыл бұрын
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.
@lyons5609
@lyons5609 2 жыл бұрын
This was a game changer for me when I first started writing code like this.
@R.B.
@R.B. 2 жыл бұрын
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 жыл бұрын
@@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.
@volfdoesit
@volfdoesit 2 жыл бұрын
@@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 жыл бұрын
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!
@FedericoSpada13
@FedericoSpada13 2 жыл бұрын
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 жыл бұрын
@@trancejockey yes, you are right about the flag, but I think that it depends from case to case.
@Lee14G
@Lee14G 2 жыл бұрын
This is amazing. Guard clauses! I will be using them from now on. Thank you.
@pchris
@pchris 2 жыл бұрын
It's always nice finding out there's a name for stuff I've been doing for years
@chosencode5881
@chosencode5881 2 жыл бұрын
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
@MyGameDevPal
@MyGameDevPal 2 жыл бұрын
Nice thumbnails James! Also I love the way you cut out the empty space, only including relevant clips, most tutorials don’t do that :)
@isaackay5887
@isaackay5887 2 жыл бұрын
This video: *_Yandere Simulator dev:_* * nervously sweats and scrolls past *
@Brahvim
@Brahvim 2 жыл бұрын
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!~
@gingerbeargames
@gingerbeargames 2 жыл бұрын
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.
@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
@SolironBrightwoode
@SolironBrightwoode 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.
@CodingWithLewis
@CodingWithLewis 2 жыл бұрын
This is helpful in more than just Unity. Amazing video.
@JamesMakesGamesYT
@JamesMakesGamesYT 2 жыл бұрын
Glad it was helpful!
@roellemaire1979
@roellemaire1979 2 жыл бұрын
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 жыл бұрын
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 жыл бұрын
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.
@FunkyAnimations
@FunkyAnimations 2 жыл бұрын
More tutorials like these are NEEDED on KZbin thank you!! I've always looked for things like this and having a video going over it is incredibly helpful
@carlosmspk
@carlosmspk 2 жыл бұрын
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 жыл бұрын
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 жыл бұрын
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 жыл бұрын
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.
@mikena8519
@mikena8519 2 жыл бұрын
yes. also use this technique with principles of single function return (SFR) by incorporating with do-while(0) idiom. Many times also reducing the cyclic complexity of pre and postambles that are common.
@albertbatfinder5240
@albertbatfinder5240 2 жыл бұрын
I do this every now and again, and hate myself for doing it every time! You just co-opt a block structure when there is no loop, never was a loop, and never will be a loop. But yeah, I do it occasionally because I love SFR. It might cause the maintenance programmer a few minutes head-scratching if they wonder whether the code is a fossil of an extinct loop,. Maybe previous programmers removed the necessity to loop, without having the courage to dismantle the scaffolding of the loop. A judicious comment Do-while() /* Allow early exits */ may be appreciated by future generations. Mind you, I’m old enough to remember when you could goto a label near the end of the function without having people slap their foreheads in despair and disgust. It’s all about which coding principles are more important, and by more important, I mean more maintainable.
@zf4hp24
@zf4hp24 6 ай бұрын
@@albertbatfinder5240 Single return was encouraged early on due to higher level languages needing formal and rigid prolog and epilog handling of the stack, register saving and restoration and exception block management prior to issuing the simple "ret" instruction. Having multiple returns usually resulted in branch instructions to some common exit point at the bottom of the function. So no real gain or change there. The problem with multiple returns is unwinding any cummulative initializations or state changes to the larger program requires multiple "gotos" to a bunch of "cleanup" labels, each with their own block of "undo" code. So, if you open a file handle and then decide to eject, you need to branch around your good code to, say, a "CloseHandle" label and execute the file close. 3 or 4 of those "undo" blocks and it starts to look like its own mess. Is there any performance hit either way? Probably not. As a C/C++ systems programmer, I'm a follower of Dykstra. I haven't used a "goto" in 20 years. And then I think it was only once. I felt so dirty afterward. ;^)
@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.
@javasbot5197
@javasbot5197 2 жыл бұрын
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.
@jackdavenport5011
@jackdavenport5011 2 жыл бұрын
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!
@JACKHARRINGTON
@JACKHARRINGTON 2 жыл бұрын
This is about the first practical thing that I’ve learned about coding.
@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.
@SelaMalka
@SelaMalka 2 жыл бұрын
Brilliant, please make more videos man, you're explaining so well!
@JamesMakesGamesYT
@JamesMakesGamesYT 2 жыл бұрын
Thanks! Have a few more videos in mind, but they might be a bit delayed
@jeroenvanwees3250
@jeroenvanwees3250 2 жыл бұрын
This is great! I have used guards clauses before, but not consciously. From now on I will.
@EnricoDias
@EnricoDias Жыл бұрын
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 10 ай бұрын
This is interesting. The question I have around this would be how is each condition class getting the data to do the checks?
@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.
@pourmydrank
@pourmydrank 2 жыл бұрын
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 жыл бұрын
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.
@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
@Exilum
@Exilum 2 жыл бұрын
It's unlikely I'd use guard clauses for this specific example (at least not in this way), but I do like using it in methods for errors, obvious cases in which you don't need to run what's behind, etc. Makes it more easy to separate things.
@unarei
@unarei 2 жыл бұрын
This seems like a pretty nice use case for them for me - you're attacking only if a set of preconditions are met. I probably wouldn't do it for the mousedown but for all the rest it makes sense
@Exilum
@Exilum 2 жыл бұрын
@@unarei If you have separate methods for each input it makes sense. Because you tend to return, it can't work if you have more than one utility per method.
@unarei
@unarei 2 жыл бұрын
@@Exilum Yeah. I guess if you don't want to split it out, you can put it into an if-else chain instead of whatever mess the original code was in this video
@chimz8057
@chimz8057 2 жыл бұрын
Ah, short videos with no time wasted. Subscribing for that simple reason
@DarkryeXII
@DarkryeXII 2 жыл бұрын
Been doing it for years, never knew it's an actual thing lol Great video
@lucasfarias1148
@lucasfarias1148 2 жыл бұрын
Simple, clear, straight to the point. I really like it, keep it up!
@XDubio
@XDubio 2 жыл бұрын
I have to maintain code with a lot of these nested condition structure. Thanks for making the world a better place!
@wa1gon
@wa1gon Жыл бұрын
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.
@DanieleNiero
@DanieleNiero 2 жыл бұрын
Did people forgot operators such *or,* *and,* etc? They are there so you can avoid these types of if-nesting.
@yidscq7990
@yidscq7990 2 жыл бұрын
Your voice is so cool and your content is actually useful.
@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.
@juanpuppinmonteiro
@juanpuppinmonteiro 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.
@JamesMakesGamesYT
@JamesMakesGamesYT 2 жыл бұрын
Glad the video helped!
@SanderDecleer
@SanderDecleer 2 жыл бұрын
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 жыл бұрын
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 жыл бұрын
@@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 жыл бұрын
@@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.
@vietanhnguyen1415
@vietanhnguyen1415 2 жыл бұрын
Short Video but make a huge impact on my knowledge. Sir, you are a lifesaver!!!
@CubesUnpacking
@CubesUnpacking 2 жыл бұрын
I'm trying to develop a game, making it first time, so your advices very useful, thank you!
@pliniomourao
@pliniomourao 2 жыл бұрын
It is always good to have a reminder of good practices and patterns. thank you for sharing!
@GUMMY_MKII
@GUMMY_MKII 2 жыл бұрын
// Really useful, clean and optimized! // I love short tutorials like this!
@trashcaster
@trashcaster 2 жыл бұрын
A commented comment? Clever
@zendakk
@zendakk 2 жыл бұрын
-- Agreed, also applicable to e.g. Lua { and even good ol' Pascal, } # anywhere, really.
@Dreadnaut2560
@Dreadnaut2560 2 жыл бұрын
@@zendakk
@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!
@JayadevHaddadi
@JayadevHaddadi 2 жыл бұрын
I have been using this for ages and I love it. It is the first time i know what it is called!! Guard clause !!!:))) 👍😊❤️
@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!
@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
@vinodakula3824
@vinodakula3824 2 жыл бұрын
Awesome video. So informative about writing beautiful and maintainable code. Thanks. Please keep these coming.
@TMPfernando
@TMPfernando 2 жыл бұрын
I never thought about using return this way... nice trick.
@mehmetb8470
@mehmetb8470 2 жыл бұрын
Thanks from Turkey. I subscribed. I will look forward to see more of this kind of content.
@jackdog06
@jackdog06 2 жыл бұрын
oh wow, hadn't even considered that before. Looks so much nicer. genuinely a life saver.
@FabiulousGames
@FabiulousGames 2 жыл бұрын
Great vid, I recently started using Guard Clauses and I can confirm that it has improved my workflow a ton
@gordonzar992
@gordonzar992 2 жыл бұрын
How long have you been developing games again?
@flootypie
@flootypie Жыл бұрын
It's interesting how things change. When I went through Uni (many many years ago) we were taught that a method should only ever have one exit point, and doing otherwise was absolutely forbidden. Glad to see more flexibility in use these days, although I can see how having multiple exit points could also cause problems...but I agree it's an improvement.
@JamesMakesGamesYT
@JamesMakesGamesYT Жыл бұрын
That’s a good point, there’s a lot of changes as new technologies and methodologies emerge. My understanding of the “only one exit point” rule is that if you have a big method it can be confusing if you’re returning “7” on the first line and “13” on the 30th line. If you try to keep your methods small then the guard clauses can really make your code a lot tidier.
@flootypie
@flootypie Жыл бұрын
@@JamesMakesGamesYT Yes, I've certainly come to agree. My favourite "new discovery" is writing self-evident code with as few comments as possible. The reduction of the old pressures of size and efficiency over everything else allow many convenient freedoms. Rediscovering coding after a 30 year break is very interesting.
@rohanphaff2640
@rohanphaff2640 2 жыл бұрын
Much love!!! I really needed this one to clean my code up :D
@sundarakrishnann8242
@sundarakrishnann8242 2 жыл бұрын
a very nice, short and informative video! You explained so well in such a small amount of time! Thanks
@ProjectPhysX
@ProjectPhysX 2 жыл бұрын
I use these all the time in OpenCL. Didn't know they are called guard clause though. Good to know!
@danser_theplayer01
@danser_theplayer01 Жыл бұрын
I do this a lot with a few simple guards like if ANY of these trigger then exit the function instead of doing what you want. But I don't know how you can use them with finer detail instead of basically making a giant OR guard.
@Vaaaaadim
@Vaaaaadim 2 жыл бұрын
I am not a game programmer, but I've certainly used this pattern before, didn't know they were called guard clauses. The main places I've used it is in loops in combination with the "continue" statement.
@Povilaz
@Povilaz 2 жыл бұрын
When I began programing _this_ is how I used to write my code, but over the years I slowly changed into doing the layered method. Idk why that's interesting.
@torikenyon
@torikenyon Жыл бұрын
Remember to EQ your voice! I was watching this on my TV and it triggered the subwoofers to shake the floor due to unneeded sub-bass frequency information that’s not actually part of the sound of your voice. A high pass filter around 100 Hz should do the trick
@JamesMakesGamesYT
@JamesMakesGamesYT Жыл бұрын
Thanks for the tip! Audio is something I've tried to get better at with each video
@marcelocosta9620
@marcelocosta9620 2 жыл бұрын
Wow! This opened my mind now! Thanks for the tip.
@mattsponholz8350
@mattsponholz8350 2 жыл бұрын
Early going I used to cringe at this technique but it's honestly a life saver; especially, if you bring someone else on the project.
@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 жыл бұрын
Thanks for the kind words! Trying to create more of these types of videos in the future
@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.
@nickygdev
@nickygdev 2 жыл бұрын
Love guard clauses. One of Riders best features is pointing them out
@netrogamedev3257
@netrogamedev3257 2 жыл бұрын
thanks james! this is gold for me as a self taught programmer!
@megascan
@megascan 2 жыл бұрын
when you unintentionally already operate like this since you found it neat
@심심이17277
@심심이17277 2 жыл бұрын
Unity 관련 영상이지만 엄청 유용하게 활용할 수 있겠네요. 감사합니다!
@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
@Konitama
@Konitama 2 жыл бұрын
Feel like this will only work if the method doesn't have other stuff going on in it as well... Otherwise all these returns are going to cause a lot more confusion when you're trying to do something else but it never executes the code because some other thing way up the list is causing the whole method to end prematurely.
@Schnorzel1337
@Schnorzel1337 2 жыл бұрын
Well if one function does more than one thing, you should replace it my multiple functions anyway.
@Frank_G_Finster
@Frank_G_Finster 2 жыл бұрын
Thank you for the tip! It really makes life easier as a newbie coder.
@tjdewolff5104
@tjdewolff5104 Жыл бұрын
For the very same reasons you mention, like "readability" and " maintainability", I convert these multiple "return" functions into (apply drumroll here...) yes, NESTED(!) code! For some 4 decades now. In the process of conversion I discovered many an error like memory leaks. Applying multiple return-clauses in a function tend to obscure these clauses more often then not, eliminating readability. A return-clause should only be applied as the final clause in a function and the only when a value is to be returned. That value, by the way I explicitly demand to be contained in a variable, which is declared in the very first line of the function and is set to a recognised error value. This line is to be followed with a blank line and that sets the returnvariable apart. Literaly. What's more, nesting code brings you the benefitsof "just in time" declaration of variables. Think in terms of congruency of lifetime and scope. This you will NEVER fully achieve in this video. My 2 cents. Tjitte I work in 'C' only.
@dhrubasaha08
@dhrubasaha08 2 жыл бұрын
Hey, I'm newbie at this...but I have a question why do you use only if instead of else if and else after 1st if ?
@JamesMakesGamesYT
@JamesMakesGamesYT 2 жыл бұрын
Hey, the reason we only use an if instead of else if is because of the "return;" within each if statement. If the condition is true, we return from the statement so no further code is executed. Hope this cleared things up!
@dhrubasaha08
@dhrubasaha08 2 жыл бұрын
@@JamesMakesGamesYT thank you so much 💖
@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! 👍
@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.)
@Ryöken17
@Ryöken17 5 ай бұрын
It's cool in a way, but there is a priority, can't you have an if and a print depending on wich one triggers ?
@sebimed5917
@sebimed5917 2 жыл бұрын
Okay, but what if my update method needs to check more than just the attack action, like jumping, rolling, etc. It can't just return if one of the 10 possible buttons isn't pressed so how would you handle that?
@JamesMakesGamesYT
@JamesMakesGamesYT 2 жыл бұрын
You could extract the guard clauses out to a method that returns a bool called "CanJump", "CanRoll" etc. Instead of a return in the guard clauses you would have a return false and then a return true at the bottom of the "CanJump" method like this: void Update() { if (IsJumpButtonPressed && CanJump()) { Jump(); } } private bool CanJump() { if (isJumping) { hintTextUi.SetText("You are already jumping"); return false; } if (!HasStamina()) { hintTextUi.SetText("You have no stamina"); return false; } return true; } Hope this cleared it up
@sebimed5917
@sebimed5917 2 жыл бұрын
@@JamesMakesGamesYT I see, that would actually be a good way to make my player controller script more readable. Thanks for the answer, much appreciated 👍
@jackoberto01
@jackoberto01 2 жыл бұрын
@@JamesMakesGamesYT Alternatively you could extract a method like void AttackLogic(), void JumpLogic(), etc with all the input actions and in there add the guard clauses I try to almost never put conditions in Unity Event functions like Start and Update because you know you might need to change them later
@tycho25
@tycho25 2 жыл бұрын
I was just wondering about this. Nice to know.
@atajuan
@atajuan 2 жыл бұрын
I love these kind of stuff. Thanks for sharing.
@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).
@SHOOTINGDNA
@SHOOTINGDNA 2 жыл бұрын
Do you know if you use rider ide it suggest such good practices. By just two key press you can convert if conditions to guard clauses.
@Furki4_4
@Furki4_4 2 жыл бұрын
I'm just a beginner at coding and suffering from if-else statement's jumble. I'll try it and hope that it'll help me.
@Known_as_The_Ghost
@Known_as_The_Ghost 2 жыл бұрын
I want to learn Unity. Whenever I decide to do this, this will help me quite a bit. :)
@JamesMakesGamesYT
@JamesMakesGamesYT 2 жыл бұрын
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
@Known_as_The_Ghost
@Known_as_The_Ghost 2 жыл бұрын
@@JamesMakesGamesYT Thank You, sir. You're quite helpful; I genuinely appreciate it!
@marcelbricman
@marcelbricman 2 жыл бұрын
in addition i like: write return statements on same line as clause without brackets, use throw in the same fashion
@gabrielaugusto1039
@gabrielaugusto1039 2 жыл бұрын
Guard clauses are really helpful, a thing that all programmers should know, and it was well explained, very good
@LeonardoHernandezpages
@LeonardoHernandezpages 2 жыл бұрын
What about workflow, when you need condition A absolutly to happen in order to execute condition B. And so on so forth
@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!
Why You Shouldn't Nest Your Code
8:30
CodeAesthetic
Рет қаралды 2,8 МЛН
Better Coding in Unity With Just a Few Lines of Code
15:27
Firemind
Рет қаралды 318 М.
Война Семей - ВСЕ СЕРИИ, 1 сезон (серии 1-20)
7:40:31
Семейные Сериалы
Рет қаралды 1,6 МЛН
Ozoda - Alamlar (Official Video 2023)
6:22
Ozoda Official
Рет қаралды 10 МЛН
Your Game Needs TWO Names (Here's Why)
2:22
James Makes Games
Рет қаралды 9 М.
5 Signs of an Inexperienced Self-Taught Developer (and how to fix)
8:40
The Dome Paradox: A Loophole in Newton's Laws
22:59
Up and Atom
Рет қаралды 1 МЛН
Using Interfaces in Unity Effectively | Unity Clean Code
4:23
James Makes Games
Рет қаралды 63 М.
Nesting "If Statements" Is Bad. Do This Instead.
1:48
Flutter Mapp
Рет қаралды 1,4 МЛН
Why I Don't Use Else When Programming
10:18
Web Dev Simplified
Рет қаралды 1,2 МЛН
Naming Things in Code
7:25
CodeAesthetic
Рет қаралды 2,3 МЛН
The Power of Scriptable Objects as Middle-Men
17:41
samyam
Рет қаралды 131 М.
Pause in Unity WITHOUT Timescale
2:01
James Makes Games
Рет қаралды 121 М.
Giving Personality to Procedural Animations using Math
15:30
t3ssel8r
Рет қаралды 2,6 МЛН
Война Семей - ВСЕ СЕРИИ, 1 сезон (серии 1-20)
7:40:31
Семейные Сериалы
Рет қаралды 1,6 МЛН