Resilience

Resilience is about avoiding failure. Where stability mostly concerns itself with expected inputs, resilience concerns itself with what happens when your code is exposed to unexpected or nonroutine inputs. Resilience in software systems is also known as fault tolerance and is sometimes spoken about in terms of redundancies or contingencies. Fundamentally, these are all in service of the same goal—to minimize the effects of failure.

For critical systems, where lives depend on ongoing functionality, various contingencies are often built into the system. If a failure or fault arises, the system can isolate and tolerate that failure by utilizing its contingencies.

NASA, when building flight control systems for the Space Shuttle, built resilience into the system by having a set of synchronized redundant machines. If one failed, due to an unforeseen circumstance or a bug, then another would take over. Back on earth, we build contingency into our hospitals, with backup power generators that'll activate immediately if the electricity grid is down. Similarly, some urban transport networks benefit from contingencies in the form of replacement bus services in the case of trains not operating. 

These large and complex systems may seem light years away from the world of JavaScript. But often, without realizing it, we are also routinely thinking about and implementing resilience into our code bases. One way we do this is via graceful degradation. When we write JavaScript for a browser environment, we have some key expectations:

  • That the JavaScript will be correctly delivered via HTTP
  • That the version of JavaScript is supported by the browser
  • That JavaScript is not blocked by an ad-blocker or another add-on
  • That the browser has not generally disabled JavaScript

If any of these conditions do not hold up, then the user might be faced with an entirely unusable website or web application. The way to alleviate these concerns is to build with graceful degradation in mind. Graceful degradation involves aspects of your application degrading to a state in which they can still be used, remaining useful to the user even in the face of unexpected failures.

Graceful degradation is often illustrated with a simple escalator:

[Photo via Unsplash, taken by Teemu Laukkarinen]

An escalator, when functioning correctly, will convey people via a set of moving metallic steps driven by a powerful gear system and motor. If the system fails for whatever reason, then the escalator remains static, acting as a regular flight of stairs. So, the escalators can be said to be resilient because, even when unexpected failures occur, they remain usable. Users can still convey themselves up and down the escalators, though, perhaps the journey will take longer.

When writing JavaScript, we can build resilience into our code by detecting features we are relying upon and only employing them if they are available. For example, I might wish to play MP3 audio to a user. To accomplish this, I will make use of the HTML5 Audio element. Before doing this, however, I will detect whether the browser supports MP3 audio. If it doesn't, I can notify the user and point them toward a transcript of the audio instead:

function detectAudioMP3Support() {
const audio = document.createElement('audio');
const canPlayMP3 = audio.canPlayType &&
audio.canPlayType('audio/mpeg; codecs="mp3"')
return canPlayMP3 === 'probably';
}

function playAudio() {
if (detectAudioMP3Support()) {
// Code to play the audio
// ...
} else {
// Code to display link to transcript
// ...
}
}

The preceding code uses the HTMLMediaElement's canPlayType method to discern support. We've abstracted this into a detectAudioMP3Support function, which we then call to decide whether we'll go ahead and play the audio, or alternatively, display the transcript of the audio. Displaying the transcript of the audio is a form of graceful degradation as it still allows users to gain some utility from the audio without being able to play it.

It's important to note that feature detection by itself is not graceful degradation. If I detected MP3 support but then silently failed if it wasn't available, then that would not achieve much. However, the activation of an alternative pathway for our users—in this case, enabling the reading of the transcript—is a perfect example of graceful degradation and resilience to failure.

There's something curious about building resilience into the software. By thinking about and accommodating potential unexpected failure states, we are, in effect, making those failure states expected. This makes our software more stable and more usable. Over time, what we once had to be resilient towards will now be an everyday part of our software's stability.

Resilience is a vital part of writing clean, reliable code. Fundamentally, we write code to solve problems for users. If our code can tolerate and accommodate edge-cases, unforeseen circumstances, and unexpected inputs, then it will fulfill this purpose more effectively.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.13.70