I Promise You Will Have Bugs

Even when we were happily married, my wife and I used to marvel that any marriages manage to make it until “death do us part,” so varied and plentiful are the pitfalls. Likewise, I marvel that only 4% of the defects in a recent release of our software were related to JavaScript Promises.

By the way, she is now my ex-wife and Promise-related bugs continue to creep into my code base at work. Just this week, I was reviewing some code along the following lines. (Note that we are dealing with AngularJS $q-type promises, not ES6 Promises.)

function promiseToDoSomething(record) {
    return callMethodOnServer().then(
        function success() {
            return promiseOfHappiness;
        },
        function failure() {
            return promiseFromCleaningUpAfterFailure();
        });
}

The promiseToDoSomething() function returns an AngularJS $promise. A $promise has a then method that gets executed after the promise resolves to either success or failure. In fact, the code that will ultimately be executed is either the success function or the failure function in the snippet. Their respective return values become the return value of then, which in turn will be the return value of the outer function.

I can see your eyes are glassing over, so I’ll jump to the sad ending of this tale. If we land in the failure function, the promise returned from promiseFromCleaningUpAfterFailure() will become the return value of promiseToDoSomething(). If the cleanup was successful, the outer function will therefore seem to have succeeded.

This is a very easy mistake to make. Continuing the theme of this series on avoiding defects, how can we avoid Promise-related bugs?

In the case of the above code review, I asked the developer to rewrite the function from the ground up using Test-Driven Development. TDD was a major theme of my book, Reliable JavaScript, and the book had a whole chapter on using TDD to build Promises-oriented code, so I won’t cover all that here. Suffice it to say that if there had been a test to verify that promiseToDoSomething() returned a rejected promise in the event of failure, the bug would not have occurred.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.