Bad practice: using if instead of guard


You’re more of a video kind of person? I’ve got you covered! Here’s a video with the same content than this article 🍿


This code seems quite reasonable, doesn’t it?

We are testing if the result of an asynchronous call has been successful, and if it hasn’t we then throw an error.

However, there’s something a little bit annoying with this code: the normal path of our code, the path where there’s no error, has gained one level of indentation 😟

For now that’s not too much of an issue.

But let’s imagine that we need to perform a second asynchronous call, with a corresponding error should it fail:

And then a third asynchronous call:

With every new call, the main path of our code gains a new level of indentation, and it’s starting to hurt its readability 😞

Even worse, as the code grows, it’s also becoming increasingly harder to correctly match each else clause with its corresponding condition.

The good news is that Swift has the perfect syntax to solve both of these issues!

When dealing with conditions that trigger an early return, it’s better to replace if statements with guard statements:

The code still does the exact same thing, but now the normal path has become much easier to follow and it has also become much simpler to match each error with its associated condition:

That’s all for this article: I hope it will help you avoid this tricky pitfall in the future!

Here’s the code if you want to experiment with it:

guard let user = await fetchUser() else {
    throw UserError.noUser
}

guard let address = await fetchAddress(of: user) else {
    throw UserError.noAddress
}

guard let paymentMethod = await fetchPaymentMethod(of: user) else {
    throw UserError.noPaymentMethod
}

// do something
Previous
Previous

How risky is it to use [unowned self]? 🤔

Next
Next

I can teach you Combine in just 4 hours 😌