Assume errors will happen at any point

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the exceptions category.

Last Updated: 2021-05-16

I had the following code as part of a tax calculator.

  calculateWithBMF(userInput)
    // Filter to just the solidarity_tax
    .then(results => ({ solidarity_tax: results.solidarity_tax }))
    .then(addMonthlyResults)
    .then(localizeValues)
    .then(displayResultsOnPage)
    .catch(displayErrorOnPage)

Overall what this code did was: - hide the calculator inputs - make a request to an external API - display the results on page

My catch function, displayErrorOnPage, showed the error text. But it did not hide the input fields (even though we wanted them hidden when errors showed).

The issue was that I had only tested the error flow by creating issues in displayResultsOnPage. But the first line in this function's job was to hide the input fields. So in all the cases I tested the error condition, I had already hidden these input fields. But, in reality, an error could have (and in fact, did) occur earlier in the chain - e.g. right at the start in calculateWithBMF(). But I had not foreseen this. Therefore by catch clause did not do enough.

Lesson

Assume errors will happen at the most inconvenient times.

Remember that your catch or rescue clauses are responsible for returning the page to its ideal state, making no assumptions about what might have happened before in the chain.

Be especially careful when your catch clause is responsible for a chain of many functions - go through each individually and ask what state needs to be undone.