Avoiding Else Statements0:00
The next rule of thumb on our list is to never use the else keyword. Let me give you an example. Imagine that we have some method to create a post. And let's use the Laravel for approach. So maybe you begin by grabbing some input. And then, well, we need to validate the form data, so I guess we're just doing it right here in the controller. Hmm. All right, we do validate or make. We pass in our input, and we will just insert the rules right here.
All right, we do validate or make. We pass in our input, and we will just insert the rules right here. So now we can get into some of the conditionals here. For example, for our demo, imagine that your company has some rule that says we only work on Friday, and we believe in this so much that we won't even allow you to post to the company blog if it's on Friday. All right, so a little silly, but just go along. Well, maybe you have something like this. If the date is not Friday, then we can move on to validating the post or the form. All right, so we can say if validation passes, then we can go ahead and create the post,
If the date is not Friday, then we can move on to validating the post or the form. All right, so we can say if validation passes, then we can go ahead and create the post, post_create, and pass in our input, and then finally maybe redirect to the home page. However, what if validation did not pass? Well, now you have this else keyword. And in that case, maybe you redirect back. You want to flash the input, and then you also want to send through the validation errors. All right, that looks good. And finally, why don't we do one last? Otherwise, if the date is Friday, then we will throw an exception.
And finally, why don't we do one last? Otherwise, if the date is Friday, then we will throw an exception. We do not work on Fridays. All right, so believe it or not, maybe excluding this Friday check here, this represents common code that I see in the wild all the time. So let's see how we might improve it. Because notice that already, a simple method really, we have all of these different branches here that we have to take in every time we read the method. We can do better. So if we want to remove the else here, we'll notice within this check,
Using Early Returns2:02
We can do better. So if we want to remove the else here, we'll notice within this check, if the validation passes, we return immediately. So in those situations where you return within one conditional, usually that means the else is redundant. So I can remove that completely, like so. And everything will still work just like it did before. But next, and this sort of comes down to personal preference, I prefer a more defensive programming approach. So in this example, I would actually check to see if validation failed first.
I prefer a more defensive programming approach. So in this example, I would actually check to see if validation failed first. So that means I would move this up and then return these to the bottom, like so. And then finally, we would check to see if the validation failed. That way, my happy path, so to speak, is always at the bottom. So now, if validation failed, go back and display the errors. Otherwise, we can move forward, create the post, do whatever, and then redirect home. But we can still do more here. Now, what if we applied this same defensive approach to the top-level condition up here? If the date is not Friday, then proceed with creating the post.
Now, what if we applied this same defensive approach to the top-level condition up here? If the date is not Friday, then proceed with creating the post. However, couldn't we also write this like so? If the date equals Friday, then we need to throw an exception. So we could take this right here, paste it up, and now we can unindent this and remove this section entirely. So just a couple tweaks here, but we've removed two else conditionals and we've decreased the indentation, which is nearly always an indication that you're on the right track. But really, we could do more here.
Extracting Logic to Filters3:42
which is nearly always an indication that you're on the right track. But really, we could do more here. If you think about it, if we want to protect our developers from doing any work on Friday, presumably, well, I don't want to repeat this everywhere. So it stands to reason that this should be within its own filter that we could execute before the request. And if you're using Laravel, just research Laravel filters and you'll figure out how easy this is to do. That means we could remove that section entirely.
Moving Validation to Services4:10
and you'll figure out how easy this is to do. That means we could remove that section entirely because it will now live within its own filter that we could apply to any route that we want. Next, we come up to the validation. Now, in Laravel 5, we have a nice and easy way to handle this using form request objects. But assuming you're using Laravel 4, well, it's a shame that we have to do all of this validation within what appears to be a controller method.
well, it's a shame that we have to do all of this validation within what appears to be a controller method. Would it be better if we could instead use dependency injection to reference some kind of validation service? With that approach, we would just say this, validator, validate the input. So now, this dedicated class will be responsible for initializing the validator, comparing it against some required input, etc. So that means we could remove this, all of this, like so.
some required input, etc. So that means we could remove this, all of this, like so. And presumably, if validation failed, an exception would be thrown, at which point you could either catch it right here or you could use a dedicated error handler, so to speak, if you're using Laravel. And once again, just refer to the docs if you want to know how to do that. So let's review a second example.
Replacing Conditionals with Polymorphism5:25
if you want to know how to do that. So let's review a second example. Imagine that you have some kind of signup function or method. And this will accept a subscription type. Now, we often have these situations where we need to check what a variable equals in order to determine how to proceed. So, for example, imagine that you're signing up for a subscription site like Laracasts. And we need to figure out, do you want the monthly subscription?
a subscription site like Laracast's. And we need to figure out, do you want the monthly subscription or do you want the forever subscription? Well, it's true you could do something like this. Maybe subscription is just a string, a primitive. Well, you could say, if the subscription type that they selected from a form is set to monthly, then we want to create a monthly subscription. I'm sure you've done similar things to this. Otherwise, else, if the subscription is equal to forever,
I'm sure you've done similar things to this. Otherwise, else, if the subscription is equal to forever, well, in that case, we need to create a forever subscription. And once again, we are assuming that the logic for creating both of these is distinct enough that they need to have their own separate methods. Now, what we see here is almost always a code smell. Think about when you have a different subscription type, a yearly. Well, if that has its own logic too, you would have to add another conditional here.
Well, if that has its own logic too, you would have to add another conditional here. And very quickly, it breaks down. But still, you may find yourself thinking, well, there's no other way to get around this. I need to check this type of subscription in order to determine how to proceed. So what might be another option here? Well, what if rather than just using a string, we actually had a subscription interface?
Well, what if rather than just using a string, we actually had a subscription interface? What would that do for us? Well, it would allow us to leverage polymorphism. Think about it. SignUp here doesn't really need to be responsible for determining what kind of subscription we want. It just needs to know that we can create a subscription. And that's exactly what polymorphism allows for. We can call these methods on objects.
And that's exactly what polymorphism allows for. We can call these methods on objects without actually knowing how they behave. So let's see what that might look like. Subscription will be an interface here. That way, we could have multiple types of subscriptions. If we've decided that a monthly and a forever subscription are distinct representations in our application, then it makes sense for them to be their own objects. A MonthlySubscription class and a ForeverSubscription class.
then it makes sense for them to be their own objects. A MonthlySubscription class and a ForeverSubscription class. Now, we would be able to remove all of this entirely and replace it with SubscriptionCreate. Now, what's cool about this is, in some contexts, the subscription object will be our MonthlySubscription class. So that means when you call create on it, that will do what is needed to create a monthly subscription. However, in other situations, it will be our ForeverSubscription class.
However, in other situations, it will be our ForeverSubscription class. And when we call create on that object, it will behave a little differently. And that's what polymorphism allows for. Now, finally, it's probably true that at some point upstairs, you will need to do some check to figure out what kind of object to create. But you could always extract that to some kind of factory method. So whatever you want to call that,
But you could always extract that to some kind of factory method. So whatever you want to call that, you would pass in your subscription type. So we can say if the type equals forever, then we will return a new ForeverSubscription. Otherwise, we don't have to use an else here because we returned early. So that means I can just return and default to the MonthlySubscription. So now, and remember, in real life,
to the MonthlySubscription. So now, and remember, in real life, these would be methods on their respective classes. But anyhow, somewhere in your code, you would figure out the subscription type. Maybe it's called getSubscriptionType, and we'll just update that. Now you have your object, so you can sign up the user and pass through the subscription that they chose.
Recapping Else-Free Techniques9:23
so you can sign up the user and pass through the subscription that they chose. That way, in some cases, we are doing setup for a monthly, and in other cases, we're doing setup for a forever subscription. So now, we're starting to see a few different ways to get rid of these else statements. One is to use defensive programming and early returns. So you do a quick check to see if something meets your criteria, and if it doesn't, you return early. That way, you can remove the else keyword below.
and if it doesn't, you return early. That way, you can remove the else keyword below. Another option would be to throw an exception, if that makes sense. And in the case of the validator example before, it absolutely does. So once again, that allows us to remove the else keyword. And then thirdly, like we demonstrated in this example, we can leverage polymorphism to further clean up our code. And this will be especially evident
we can leverage polymorphism to further clean up our code. And this will be especially evident in those situations where maybe you even have a switch, where you're trying to check something. If it's X, then do this. If it's Y, then do that. Or if it's Z, then do this. Whenever you find yourself writing that within your methods, ask yourself if you could instead leverage polymorphism. All right, that'll do it for this episode.
ask yourself if you could instead leverage polymorphism. All right, that'll do it for this episode.
