misiel.

engineer ∙ gamer ∙ creator

Published on

Pyramid of Doom

Authors

What is the Pyramid Of Doom?

func pyramidOfDoom() {
    if (user != null) {
        // do something
        if (user.name != null) {
            // do something
            if (user.status != null) {
                // if...
                    //if...
                        //if...
                            //if... you get the gist
            }
        }
    }
}

Wikipedia defines it as: a common problem that arises when a program uses many levels of nested indentation to control access to a function.

I ran into this problem recently at work when I was creating a helper function for a larger function, and saw that the code within the function created this nested visual pattern. I thought nothing of it since the code worked (junior dev mistake), but something just felt off. Why was the objective of my function nested within 3+ if statements?

A senior dev helped me realize the error of my ways when he pointed out the "Pyramid of Doom" concept to me. Through some simple guard clauses, I was able to declutter the visual mess and make my code look cleaner and more visually appealing, also just logically easier to read since a future reader wouldn't have to parse X amount of if-statements to see what the objective of the function is.

So what's the solution to this?

Well it's dependent on the language you're using. Being a previous Android dev using Kotlin, I would take the above code example and rewrite it like this:

fun pyramidOfDoom() {
    if (user == null) return
    // do stuff
}

This if (user == null) return line is known as a guard clause. Instead of nesting logic within a block of code that begins with checking if the user is NOT null, we could just end our code early if the user IS null.

(This is a simple example without going too deep into Kotlin's "?." operator and other ways of null safety.)

But Swift also has it's own ways of null checking...

'If let'

func pyramidOfDoom(){
    if let userName = user.name {
        print("The user's name is \(userName)")
    }
}

Through the usage of if let, we're able to check if user.name has a value and assign that value to a variable. Within the scope of the if let block, we know the value is not null and able to use it however way we want.

'Guard'

func pyramidOfDoom(){
    guard let userName = user.name else { return }

    print("The user's name is \(userName)")
}

guard is another way of null safety in Swift and allows us to combat the "Pyramid of Doom". The difference between this and if let is we now have a greater scope to use our non-null value. With if let, the value is only non-null within the scope of the block. With guard, if the value is not null then we can use it throughout the whole function scope.


Thanks for reading!