Fault tolerance on the web

Months ago I wrote The reasons I don’t use Typescript and one reason more than others struck a nerve with some readers. I said developers “can embrace the fault-tolerant nature of the web and wisely use JavaScript’s strict type enforcement when actuall…

Months ago I wrote The reasons I don’t use Typescript and one reason more than others struck a nerve with some readers. I said developers “can embrace the fault-tolerant nature of the web and wisely use JavaScript’s strict type enforcement when actually necessary.”

Many readers drove by, rolled down their window, and yelled, “Fault tolerance sucks!” and then sped off when asked why. Others denied that JavaScript even has strict typing abilities and accused me of “spreading misinformation”.

So, I’m writing this to explain my reason in more detail and to document the very long and very useful list of tools already in JavaScript that not only help you verify types, but help you further harden your code at runtime.



Is fault tolerance good?

(I wanted to share a link to an old blog post on Los Techies – I think – written by Addy Osmani – I think – that introduced me to this topic, but I can’t find it. If you know it, please share!)

A system is said to be fault-tolerant if when a component of the system fails the system continues to function.

This is what it looks like:
Airplane engine failure

Note how the plane is still up in the air. This is a good thing.

This is what fault-tolerance does not look like:
Windows 10 BSOD

An issue inside a component inside a program inside an operating system caused the whole operating system to just give up. If that wasn’t a bad enough design, the system then forces you to sit and wait while it rubs it in your face – there’s still 75% more failure to go!

In the spirit of that old GM vs. Microsoft joke, what if cars were built this way? Your car would suddenly shut down because one of its four tires didn’t have the exact tire pressure dictated by the manufacturer’s specifications? This would be a terrible driving experience and kind of dangerous.

So yes, fault tolerance in systems is good!



A fault tolerant web

Thankfully, early engineers designed web platform technologies – HTML, CSS, JavaScript – and the browsers that implement them to be more airplane and car and less Windows.

For example, what will happen when this document is loaded by your browser:

<!DOCTYPE html>
<html>
<body>
  <h1>Hello, world!
</body>
</html>

It will display “Hello, world!” despite the missing closing tag.

What about this document?

<!DOCTYPE HTML><title>Hello</title><p>Welcome to this example</p>

That works too. In fact, it’s an example straight from the optional tags spec.

What about this?

<!DOCTYPE HTML><title>Hello</title><asdfghjkl>Hello, world!

Does this mean we should omit tags or not bother closing tags or write nonsense? Of course not, but it would be a real shame if the user was left staring at a blank page because the browser crashed on a missing or unknown tag.

The web platform has been designed to be fault-tolerant. It values producing something for the user over requiring everything at all times to be absolutely perfectly correct in order to function. Kind of like how an airplane is designed to resist gravity as much as possible, even in unexpected circumstances.

Here’s another example with CSS:

div {
  display: grid;
}

The code is modern and technically perfect, but older browsers won’t know what grid is and yet they will dutifully carry on with their CSS calculations and paint content as best they can without giving up and crashing. Even this won’t crash a browser:

div {
  banana: split;
}

Again, the point is not that the web platform tolerates sloppiness, but rather should something imperfect or unsupported slip through your quality controls, it won’t completely ruin your users’ experience.

When we create our systems – our apps – we choose to embrace or reject the nature of the web by conscientiously allowing a little wiggle room or by attempting a level of rigidity that might shatter in the face of something unknown.

There’s a sweet spot between careless and “can’t accept JavaScript, must use TypeScript.”

JavaScript allows things to happen that some languages would not allow, which seems to rub a lot of TypeScript fans the wrong way. I believe they are used to working with languages and in environments that are more predictable and controllable, like a having a highly-programmed autonomous car confined to known roads. Web apps, on the other hand, have a human driver who’s late for work trying to take the fastest route. Web apps simply demand a more tolerant runtime.

When it is time to build in some rigidity – even absolute correctness – there are many tools available natively just waiting for you to use them.



Leverage JavaScript’s tools when necessary

JavaScript includes lots of features and tools that increase the strictness and ensure correctness of your code, including type checking.

Here they all are (I think I got them all), each with a link to MDN and a brief explanation for their use case:



Type checking

These are useful for enforcing the type of an object or comparing the types of objects.

typeof

The typeof operator returns a string indicating the type of the unevaluated operand.

It’s not perfect, but it enables type checking for string, number, bigint, boolean, function, symbol, object, and undefined.

Object.prototype.toString.call(obj)

Every object has a toString() method…toString() returns “[object type]”, where type is the object type.

This method can check object types like Array, Date, RegEx, and more. This is best wrapped up in a little helper function.

instanceof

The instanceof operator tests to see if the prototype property of a constructor appears anywhere in the prototype chain of an object.

There’s also a more verbose, but self-explanatory way of checking: Object.getPrototypeOf(obj) === MyClass.prototype. Arrays have a gotcha, see next.

Array.isArray()

The Array.isArray() method determines whether the passed value is an Array.

There are edge cases that make using this method safer than instanceof.

Number.isInteger()

The Number.isInteger() method determines whether the passed value is an integer.

There are edge cases to be aware of as well as Number.isSafeInteger().

Number.isFinite()

Number.isNaN()

===

The strict equality operator checks whether its two operands are equal…[it] always considers operands of different types to be different.

Skips the type coercion for a more accurate comparison.



Object integrity

These are useful for ensuring that what you are accessing is what you expect it to be.

const

The value of a constant can’t be changed through reassignment, and it can’t be redeclared.

Variables declared with var and let can potentially be reassigned a value your code can’t handle, so using const helps protect against this.

?.

The optional chaining operator permits reading the value of a property located deep within a chain of connected objects without having to expressly validate that each reference in the chain is valid.

Optional chaining in my opinion is the greatest addition to JavaScript since ServiceWorker. It’s our most powerful tool to fight Uncaught TypeError: Cannot read property, which has been identified by Rollbar as the number one production JavaScript error see Top 10 JavaScript Errors From 1,000 Projects.

Data shapes in web apps can be unpredictable due to the fact that most data originates somewhere outside the app (e.g. your own services, 3rd-party services, hosted files and objects, and more). Even well-defined custom types can fail to account for all of an object properties, so TypeScript or no TypeScript, you should use this on data your code didn’t originate.

hasOwnProperty() and in

The hasOwnProperty() method returns a boolean indicating whether the object has the specified property as its own property (as opposed to inheriting it).

When you need to verify that a property exists directly on an object, use this. Use in only when you know that checking the object and its prototype chain is acceptable.

?? and ??=

The nullish coalescing operator is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand.

This is needed when you can’t allow the normal falsey rules because a valid value might be rejected, i.e. when you do need to accept 0 (zero), '' (empty string), or false values.

Pair it with assignment to ensure nullish values are replaced with something valid, e.g. foo ??= something.

Object.is()

The Object.is() method determines whether two values are the same value.

Its rules for equality are slightly different than === and ==.

Object.seal()

The Object.seal() method seals an object, preventing new properties from being added to it…Values of present properties can still be changed as long as they are writable.

This is like const on steroids. The shape of the object cannot change – you can’t add or remove properties – but you can edit their values.

Object.freeze()

The Object.freeze() method freezes an object. A frozen object can no longer be changed [in any way].

Like seal(), but you can’t even edit existing properties. Frozen means nothing about that object can be changed, but one thing to remember is an object’s “values that are objects can still be modified, unless they are also frozen.”



Fault tolerance is still not enough

Whether you’re writing TypeScript or not, those 15 tools should be used often, but in the end it still won’t be enough. After types have been checked and objects prove they have the properties we expect them to have, there’s still a void in this problem space. That void is validation. No, not input validation for security purposes – you do that server-side – but rather an extension of the validation we’re already doing, i.e. ensuring what we have been given meets our requirements before operating on it.

I suggest you read Adam’s Tossing TypeScript for a detailed explanation on this and then try his allow lib.

Are these validations always needed? No. There are advantages to JavaScript’s forgiving nature and allowing for it with eyes wide open can result in more simple and resilient code that might just save your users from an unnecessary bug.


Print Share Comment Cite Upload Translate
APA
Jordan Brennan | Sciencx (2024-03-29T14:32:04+00:00) » Fault tolerance on the web. Retrieved from https://www.scien.cx/2021/07/20/fault-tolerance-on-the-web/.
MLA
" » Fault tolerance on the web." Jordan Brennan | Sciencx - Tuesday July 20, 2021, https://www.scien.cx/2021/07/20/fault-tolerance-on-the-web/
HARVARD
Jordan Brennan | Sciencx Tuesday July 20, 2021 » Fault tolerance on the web., viewed 2024-03-29T14:32:04+00:00,<https://www.scien.cx/2021/07/20/fault-tolerance-on-the-web/>
VANCOUVER
Jordan Brennan | Sciencx - » Fault tolerance on the web. [Internet]. [Accessed 2024-03-29T14:32:04+00:00]. Available from: https://www.scien.cx/2021/07/20/fault-tolerance-on-the-web/
CHICAGO
" » Fault tolerance on the web." Jordan Brennan | Sciencx - Accessed 2024-03-29T14:32:04+00:00. https://www.scien.cx/2021/07/20/fault-tolerance-on-the-web/
IEEE
" » Fault tolerance on the web." Jordan Brennan | Sciencx [Online]. Available: https://www.scien.cx/2021/07/20/fault-tolerance-on-the-web/. [Accessed: 2024-03-29T14:32:04+00:00]
rf:citation
» Fault tolerance on the web | Jordan Brennan | Sciencx | https://www.scien.cx/2021/07/20/fault-tolerance-on-the-web/ | 2024-03-29T14:32:04+00:00
https://github.com/addpipe/simple-recorderjs-demo