Thoughts on broken vs wrong
I was recently watching “Elm crash course - Building unbreakable webapps fast” by @supermario and while he was talking about wrong vs broken
I had a Aha! moment.
How many troubles and broken code because of null and undefined?
Broken vs wrong
- wrong
-
a particular value may not be semantically or logically valid
eg: the sky is green instead of the sky is blue - broken
-
an unexpected syntactical error that stops the application
eg:Uncaught TypeError: Cannot read properties of null
They are both an undesired state of the application, of course.
But, can we argue that while a broken state totally stops an application and a user from further interacting — a wrong state would let a user interact, at least, to extract possible value from the application while still showing some semantically incorrect information?
How many times Uncaught TypeError
How many times?
How many times Uncaught TypeError: Cannot read properties of null
and its dear friend Uncaught TypeError: Cannot read properties of undefined
?
How many times coding under the assumption a variable would be there?
How many times required properties in ts
interfaces disappear in API calls?
A classic example
Let says you’ve got GET api/xyz
which as part of the response should always™ return xyz
as string
.
Now, you may have even a similar interface for the response.
interface Response {
xyz: string;
}
You did agree with the BE and all seems fine and merry.
Your editor too is happy when you write resonse.xyz.toUppercase()
. ts
is happy.
Well done! Feature completed!
All seems fine, except that one day xyz
to your great surprise get back as null
from the API.
And Uncaught TypeError
is there. Again. Nagging you… How many times should I tell you… Cannot read properties of null (reading 'toUppercase')
? Didn’t you know?!
And you may think: Hey, but super editor highlight, ts
, and [put you favourite BE developer name here or API service] told me that would never ever happen and that everything was fine! How does it comes that now we have xyz
as null
?
You just experienced a runtime error.
When you transpile from ts
to js
all your types are basically stripped out.
If you want to be sure to have a specific type of value during code execution you should write some logic for that.
In this case, ts
won’t check out of the box that the API response matches the interface you provided.
The false promise of ts?
Note: Static type checking is done at compile time. Runtime type checking is done as part of program execution.
TypeScript is a strongly typed language that came with the promise of powerful editor integration and syntax highlight to catch bugs and have Result You Can Trust
and Safety at Scale
.
For sure static type checking helps on refactoring or with basic internal typos, but is this enough at runtime?
I’m afraid no. Worst, it can give you a false impression of correctness as just seen in the example.
Considerations on runtime type checking
So, what’s the solution at runtime? Well, runtime type checking :)
Elm does support runtime type checking out of the box creating a safe area within the application.
Of particular interest are BadBody
error in an API request to detect a not consistent type, and Decode
to attempt to consume data from outside the application.
The main idea is to check and decode (cast to a type if possible) during runtime and handle the case when the data is not consistent with the types.
In particular, we should check at least:
- API response
- loading data from storage
- input values
Here are some packages that may be handy for the runtime type checking:
In summary
Elm has many many interesting ideas and at the same time null
and undefined
have been such troublemakers in the js world.
ts
is great for static type checking, but extra care is required at runtime, no doubt about it.
Probably schema validators and runtime type checkers are the way. Not sure if casting or sanitization to an expected type would be fine too as the definitive solution, but surely it would mitigate the issue.