It is very common to be in the situation where your app needs to take some action, but only if multiple conditions are met. For example, suppose you have a function that is supposed to process a blog post. To post in the blog, you have to be logged in, to be an admin, and to have non-blank content. The first instinct would be to write something like this:

function postArticle(title,content) {
    if(content !== "" && title !== "" && !isSpam(content) && isAdmin() && isLoggedIn()) {
        publishArticle(title,content);
    }
    else {
        error("there was some kind of error");
    }
}

The problem with this construction is that there is no way to know why this function is failing, and subsequently there is no way to handle the error cleanup if necessary. It is possible to put in further checks inside, leading to something similar to this:

function postArticle(title,content) {
    if(content !== "" && title !== "" && !isSpam(content) && isAdmin() && isLoggedIn()) {
        publishArticle(title,content);
    }
    else {
        if(content == "") {
            error("content is empty");
        }
        else if(title == "") {
            error("title is empty");
        }
        // rest of checks go here
    }
}

Even with only two levels of nested if statements, this construction is getting harder to understand, follow along, and modify. If there are any kind of compound checks or recovery, it makes modification difficult since there are many possible interactions possible.

Below, I present a better way to handle these kinds of situations, where no more than one level of if statement is required.

function postArticle(title,content) {
    if(!isLoggedIn()) {
        error("You cannot post if you are not logged in");
    }
    else if(!isAdmin()) {
        error("Only admins can post articles");
    }
    else if(content == "") {
        error("Content cannot be blank");
    }
    else if(title == "") {
        error("Title cannot be blank");
    }
    else if(isSpam(content)) {
        error("Content is marked as spam");
    }
    else {
        publishArticle(title,content);
    }
}

The idea is that the normal flow checks for errors first, and only once all the checks have passed, the final else statement is reached and the action is performed. Each if or else if only checks one condition, and the conditions are ordered is such a way that the later checks depend on the first checks to pass. For example, being an admin is not possible if you are not logged in first, therefore the check to see if the user is admin is placed below the check to see if the user is logged in.

Similarly, it’s a good idea to perform cheap checks before expensive ones. It is easier to check if the content is blank than to take it through the spam filter, that’s why the blank check is performed first.

Finally, the else statement is reached when all the checks have passed.

The reason why we used this structure is that there is only one way to succeed, but multiple ways to fail. Therefore, we can handle each failure separately, and only handle the success at the very end.