When Things Go Wrong in Software
In software, as in life, things go ‘wrong’.
In software, as in life, how one reacts to bad situations is the only thing under our control.
How does one handle the ‘bad things’ in the domain of software?
Below is a crystallization of decades of software development experience for how to deal with ‘bad and unexpected things’ in the realm of code.
I’ll leave the life part for another article, but feel free to make analogies from what I write below. :)
Just Give Up
A common pattern is to simply not deal with problems.
This is the ‘Exception Pattern’.
There are times when there is simply nothing that can be done, and the best one can do is fail as gracefully as possible.
This pattern works up to a point but is obviously not ideal. Think of it as the default solution. What will happen if nothing is done. Leaving someone ‘higher up’ to deal with picking up the pieces.
Leave No Room for Error
One can adopt Functional Programming patterns.
The two main patterns one can adopt from FP are ‘immutability’, and writing ‘side effect free’ functions.
In a way these are both the same thing, one locks down data and the other locks down execution.
A handy way of thinking about this is that one removes the time component. Hence, one is protected from the future as long as 1+1=2 continues to hold, or more correctly, that one’s concepts of these things hold (1+1 doesn’t always equal 2 under all circumstances).
Acknowledge Reality
There is a sort of middle-ground between giving up (Exceptions), and limiting oneself to computational domains that can’t contain problems (pure FP).
One can produce results that aren’t entirely good, and indeed have a mix of good and bad.
One can elevate the Error
to a first class citizen.
This is quite helpful when dealing with the ‘real world’ where things are messy and bad things are expected to happen from time to time.
What this means in practice is that instead of always returning a valid result inside a function, one returns a combination of valid-or-errorful result.
TypeScript ‘Errorful’ result example:
function foo(input:string): string | Error {
if(input.length > 8) {
return new Error("Too many characters")
}
return `${input} was a triumph`
}
Note that one can also semi-achieve this with simple try-catch blocks, but this can get really messy really quick as the error processing becomes more complex.
I will argue that treating errors as legitimate values gives one better tools for handling errors in many circumstances.
This is more than merely a style-preference.
In languages such as TypeScript where the Exceptions are not part of the call-signature (as they are in say Java) this can allow one more visibility into what the errors are likely to be, and therefore have strategies for dealing with them (for example, one can sub-class errors, and/or have a generic error that can be parameterized).
Summary
There is no single ‘best way’ to deal with unexpected/bad situations, but one can prepare and adopt better and better strategies for handling those situations.
Or more succinctly:
💩 happens, expecting the worst, and preparing for how to deal with it, often leads to better results. :)
Originally published at https://github.com/matthewjosephtaylor.