Unfortunately, a lot of other devs hate to see that your code may actually crash and start asking questions about what scenario could cause it and asking if maybe there's a more gentle way to get out of the error. So, I'll often back down and start having softer error-handling, but on the whole it does complicate things further as the errors cascade and now you have to reason about handling combination of errors that have low likelihood of happening. So, to me, just having an early crash is way better.
Had to deal with the same issue as you.. other devs and managers don't like those errors.. but it makes things fragile and more difficult to troubleshoot.
Does Swift have assert statements? If so, is there a reason you chose this method instead?
To be clear, I tend to use assert statements more than fatalErrors.
Basically the happy path is that this simply never happens. You open a websocket and listen for incoming messages and process them. The actual situation is that you open a websocket and some time later it dies and then you simply attempt to reopen it until it succeeds and resume processing messages. The app has several states: connected, connecting, and not connected and should transition from one to the other depending on what happens.
Our frontend people struggled a lot with this exact issue. They only thought of the happy path and simply ignored any form of expected failure. So the first version of the app worked great for a while until it just stopped working. The fix: "just reload the app" was of course not really acceptable. All that was needed was a little defensive coding: assume this call will sometimes fail and simply try again when that happens. Then also handle the case where retrying will also fail because actually the request is wrong (input validation) and the error is the system telling you that it is wrong. If you don't have any code that handles that, you are going to have a very flaky UX.
var o = new SomeObject();
if (o.computeSomething != null && o.computeSomething != undefined) {
o.computeSomething(...);
}
Their reasoning was that in JavaScript (with the old syntax) you just add functions to the prototype, so you could forget to do it or mistype it. SomeObject.prototype.computeSomethinnn = function () ...
I was sort of tripping over myself in objections to what they were doing:* you shouldn't check for null or undefined, but rather do `o.computeSomething instanceof Function`
* there's no need to do `!= null` and `!= undefined` because `!=` (as opposed to `!==`) actually checks for both
* you shouldn't do the check at all because if you actually mistype the function name all you're doing is hiding the error. Failing sooner is better.
* a missing method should be picked up in the unit tests (but they didn't have any tests at all because "our system is too complex to be tested automatically")
* probably some others...
That team really hated JavaScript and their code showed it.
BTW, the indentation above is not wrong... they did indent by 3 spaces. I read a story about 3 space indents on thedailywtf.com and thought that it was clearly made up... after this team I believe it.
It also helped when tutoring new python students -- when they mixed space-indented code they copied from the internet with tab-indented code they copied from the internet, they'd get all sorts of fun errors. Setting the tabwidth to an even number sometimes allows them to hide. 3, though, really makes them stick out.
As far a I know, ESlint can't detect missing methods, and they weren't even using a linter. TypeScript can, but they weren't using that.
Probably a compromise between 2 and 4?
I do stick to 4 spaces at work though.
I'd also wish for similar rigor from people developing whatever filesystens my data is on. :-)
Fail fast is generally a good idea, if you can do it safely.
Software fails, you can make failures rarer, but you can't make they go away. You have to deal with it, it's not an option.
This involves a lot of thinking and collecting information about potential risks and evaluating their probability and severity.
Then you just mitigate the worst risks, probability times severity (other factors are also possible). Some residual risk always remains.
1. Determine the last sane state of the system, and work forward from there. (Read the servo position and try to go from there)
2. Have a the "recovery" routine to reset the system. (Take all positions to "zero")
3. Just stop. (Yes, I know this can be bad). And ask a human for help.
Stable storage is a key factor in making this philosophy work. [1]
[1] https://qconlondon.com/london-2012/qconlondon.com/dl/qcon-lo...