Clean Code: Nesting

2023-04-16

When writing complex logic we often find ourselves in a situation like this:

export function handleSomething(prop) {
    if (prop.something) {
        prop.something.forEach((val) => {

        })
    } else {
        return false
    }
}

The more we nest the code the cognitive complexity increases and it becomes harded to understand all cases that it covers. We should always strive for simplicity and clean code. One of that ways to achieve that is to avoid over nesting. As a general rule avoid more than 3 nested block of codes, but strive for 1 or 2.

When faced with situation like above there are two strategies that we can used to simplify the code:

  • Inversion
  • Extraction

When designing a function we have one main cases that we want to cover, but then we discover some edge cases that we want to guard against, most notable is NPE. So we might have something like this

export function handleSomething(prop) {
    if (prop.something !== null) {
        prop.something.forEach((val) => {

        })
    } else {
        return false
    }
}

Just by inverting this check we can do an early return and we get with main case without indentation.

export function handleSomething(prop) {
    if (!prop.something) {
        return false;
    }
    prop.something.forEach((val) => {

    })
}

With this we got something that is called guard statement. We are guarding against undesired NPE. In case that we are throwing an execption from guard statements we got ourselves a validation.

export function handleSomething(prop) {
    if (!prop.something) {
        throw Exception("Something is not right")
    }
    prop.something.forEach((val) => {

    })
}