DEV Community

Discussion on: Is “Defensive Programming” actually healthy?

Collapse
 
cubiclebuddha profile image
Cubicle Buddha • Edited

Thank you for your kind reply. Yes, I’ve been cooking up the blog articles for many months now. :)

So as for your code I your response, I’m a bit confused about the benefit. Your function returns undefined (as you mentioned). I don’t understand why you feel that’s a good thing. That means that a consumer code needs to either handle the undefined case every time, and if they forget to do so it will be a runtime exception. And that exception would be some kind of unclear “undefined exception.” Even in JS it would be better to throw an error so as to be explicit about the reason why it couldn’t find a match. But there’s a better way with TypeScript where you kind find out months before an error would ever be discovered. The compiler is run on every check in. Why wouldn’t you want the faster feedback of finding out when you check your code in?

Personally, I find that I go much faster if I have a short feedback loop where I can find out what I did wrong. Now, I realize that I’m arguing for static type analysis, which is not everyone’s cup of tea (although the recent Stack Overflow survey showed immense support for TypeScript). But the main point I’d like to make is that it truly is better to avoid bugs in production if you can catch them sooner.

Collapse
 
dvddpl profile image
Davide de Paolis

probably I did not articulate my reply properly.
I totally agree in the benefit of the static type checking. and I definetely want to catch error at compile time.
And i said that i would implement that check not with an IF /ELSE IF nor with a SWITCH, rather with a Mapping like suggested above by @jvanbruegge :

type TrafficLight = "red" | "yellow" | "green";
type TrafficAction = "stop" | "go" | "pause";

type TrafficResponse = {
    [k in TrafficLight]: TrafficAction;
};

function respondToTrafficSignal(signal: TrafficLight): TrafficAction {
    const mapping: TrafficResponse = {
        red: "stop",
        yellow: "pause",
        green: "go"
    };
    return mapping[signal];
}

BUT i would also be even more defensive and check for possible error at runtime in case - at runtime the function is called with an invalid value.
At runtime Typescript does not exist, after you compile all your type checking is gone and what you have is the function I posted.

function respondToTrafficSignal(signal) {
    var mapping = {
        red: "stop",
        yellow: "pause",
        green: "go"
    };
    return mapping[signal];
}

See and play around with this Typescript Playground snippet for comparison
Therefore, if the invocation of the function could be dynamic ( server could respond with blue or user could type in orange ) i would add a catch and a fallback to prevent a runtime error.

Hope i was clearer now :-)

Thread Thread
 
cubiclebuddha profile image
Cubicle Buddha • Edited

Yup yup. Yea the map + the undefined check would be the ideal approach. Sorry I didn’t understand at first. Classic misunderstanding with remote communication. My bad! :)

Oh and as far as the server sending bad or new data types, I have been using a library called TSOA to enforce runtime types at the boundaries. It’s a way of preventing “garbage in garbage out.” It’s pretty cool stuff. There are similar libraries that do runtime checking in the UI too.

Thread Thread
 
jvanbruegge profile image
Jan van Brügge

No, I would not add runtime checks to this. If you call the function with something different than the types specify that's on your own. The caller has to verify that he can call the function