تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Avoiding Else Nesting0:07

Several years ago I was in a talk by Raphael Dobbs and he was sharing the code Katas practice by his team. One of them was to avoid else. I've since taken this a lot farther, but avoiding else puts you on the path to avoiding nested code to improve code readability. I like to have as much of the code at the top level as possible. This is difficult because when using control structures, like if else, there's no way to avoid that inner level.

This is difficult because when using control structures, like if else, there's no way to avoid that inner level. However, we can avoid nesting beyond that. Let's jump into a code sample. What I wanna point out first is this empty block. I know this might look crazy, but I've seen this in a lot of code and it's not just new programmers. Sometimes it's easier to write the simple logic than it is to figure out what the inverse of this is.

Sometimes it's easier to write the simple logic than it is to figure out what the inverse of this is. We'll come back to addressing that specifically in a little bit. For now, I think we can all agree that this code is much more nested than it needs to be. In fact, it's up to three indentation levels deep. Now, again, some of this is unavoidable, but I think it could be refactored to be a single level to go through some of the strategies.

Set Class Refactor Setup1:19

but I think it could be refactored to be a single level to go through some of the strategies of breaking up nested code. Let's look at a partial implementation of a Set class. Now, a Set is an object that contains unique items and again, this class has a couple methods to implement that. Let's start at the top and go through each of them. Refactoring away from this nested code looking at isEmpty. We see a pretty common structure when it comes

Return Conditionals Directly1:41

Refactoring away from this nested code looking at is empty. We see a pretty common structure when it comes to this if else block, and that is returning a value in this case, a raw boolean value. Anytime you see code which matches the structure, you may immediately collapse it to return the conditional. After all, this conditional evaluates to a boolean value and in this case, that condition lines up exactly with what's being returned.

and in this case, that condition lines up exactly with what's being returned. So I'll just take it, we'll cut it out and we'll return paste. Moving on to add, we see one of those empty if blocks now based on the rest of the code. What this is really doing is in implicitly returning, we can make that explicit by adding a return statement. And as we've learned in dead code, now we know that if we ever get inside of this if block we're going

Introducing Guard Clauses2:34

And as we've learned in dead code, now we know that if we ever get inside of this if block we're going to return and therefore no code below it is gonna execute. That means we can actually avoid this else and we'll just format the code a little bit. Now what we've actually done here is create what's called a guard clause. I really like guard clauses and that's because as a human, we have context. When we're reading through something like this ad method,

because as a human, we have context. When we're reading through something like this add method, we know the inputs and the outputs. So having a guard clause that we can immediately come across allows us to stop reading once we've satisfied that context. In this case, if we're reading through add and we know item is null, as soon as we get here, we can stop. We don't have to continue reading the rest.

as we get here, we can stop. We don't have to continue reading the rest of this block of code. Now, the nested code that's left isn't a guard clause. It actually performs what I call the primary action. I prefer the primary action not to be nested. Again, when I come into this method, I like to be able to see what it does directly, and if it's within nested code, I have to dig around a bit to find it.

and if it's within nested code, I have to dig around a bit to find it. So what I'd really like to do is turn this into another guard clause. Doing so provides consistency within this method. That means my brain can be a little lazy as I'm reading. As a programmer, I can jump directly to the code path that matters for my context. In addition, by turning this into another guard clause, I can bring the primary action back to the top level.

In addition, by turning this into another guard clause, I can bring the primary action back to the top level. Now, there's all sorts of math available to figure out how to change or invert the logic. In the case of compound conditionals, you might wanna look at something called Morgan's law. In this case, we just have a single condition and we only need the inverse. So let's start to break out this code for what we want it to look like.

So let's start to break out this code for what we want it to look like. I wanna bring the primary action to the top level, and instead I wanna turn this into a guard clause by returning. But to do that, I need to invert the logic, but taking this step by step, I might wrap the inner condition and then negate it. This works. This is indeed the inverse, but again, the code is now a bit more complex.

This works. This is indeed the inverse, but again, the code is now a bit more complex. This is not what most programmers would be used to reading. Thinking about it mathematically, if I have one and I negate one, I have negative one, and if I negate negative one, I'm back to one. So we can do the same thing here by removing the negations and get back to a simpler condition. Now, in some cases, I would leave the code here. It's simple, explicit, easy to scan.

Now, in some cases, I would leave the code here. It's simple, explicit, easy to scan. That all makes the code infinitely more readable than its original version. But in this case, we could go a bit farther by collapsing these two guard clauses. They both contain simple single conditionals and collapsing them together draws out the exceptional states of the ad method. So to join the two, I'll make it a complex conditional.

states of the add method. So to join the two, I'll make it a complex conditional with the OR operator. In this case, we're now saying if item is null or this set already contains item, then return again for a human reading. This, I've now drawn out the two exceptional cases where an item would not be added to the set. If I don't fit one of those cases, then the item added. Alright, let's bring all this together.

Refactoring Contains Logic6:09

If I don't fit one of those cases, then the item added. Alright, let's bring all this together. By looking at contains, again, we see a double nested condition here, similar to the ad method, we can join these two conditionals, but this time, because of the nested inner structure, we need to join them using an and let's clean up that nested code and apply some formatting. Now it looks much like isEmpty.

and apply some formatting. Now it looks much like is empty. That is an if statement, which returns a raw bool. So instead of the if statement, we can actually take the conditional and return it directly. Now, because this is a compound condition, it feels a little more complex than it really is. We can streamline the code and therefore make it more readable by removing this first condition.

therefore make it more readable by removing this first condition. After all, if the set is empty, the item would not be found and therefore contains would return false. So in this specific case, we haven't changed its behavior, but I would be very mindful of making these changes, especially without deep knowledge of the code base or strong test suite. Now, there are other control structures which create nested code.

Other Nesting Structures7:29

Now, there are other control structures which create nested code. For example, a switch statement as we saw in the previous video, often refactoring this to a match statement or even rewriting it as an if statement can improve code readability. Similarly, loops have an inherent nested structure. If you have a code base, which contains a lot of loops, I would encourage you to read through

If you have a code base, which contains a lot of loops, I would encourage you to read through the array functions available in php. If you're using Laravel, refactoring to collections is also an option. Now there could be an entire course on those topics. For now, I've focused on the most fundamental control structure, the if statement, practicing how to remove or refactor. Those will definitely make your code more readable.

to remove or refactor. Those will definitely make your code more readable and level you up as a programmer.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟