DEV Community

Discussion on: Is “Defensive Programming” actually healthy?

Collapse
 
cubiclebuddha profile image
Cubicle Buddha

I’m not sure I see how a dictionary would solve this. Could you provide a code example so I could see and understand?

Collapse
 
yaser profile image
Yaser Al-Najjar

Sure, I'm using Python generally but this could apply to any lang:

def respond_to_traffic_signal(signal):
    signals_meanings = {
        'green': 'go', 
        'red': 'stop', 
        'yellow': 'pause'
    }

    return signals_meanings[signal]

try:
    print(respond_to_traffic_signal('green'))
except KeyError:
    print('not found')

As a general rule of thumb, whenever I see many if's, I just think directly: "Can I use a dictionary here instead?"

Thread Thread
 
cubiclebuddha profile image
Cubicle Buddha

The problem with that dictionary solution is that it relies on throwing an error at runtime. There’s no information provided to the compiler to catch it sooner. Which means that you’ll only find out if you forgot a case (or a key the dictionary) if you write a unit test that tests for exhaustiveness. But rather than write a unit tests, wouldn’t it be better to find out at compilation that a mistake was made?

So I would recommend that you give the article another read and then try out the samples I provided in the article in a REPL. It’s probably not apparent the advantages without seeing how quickly the error pops up in a TypeScript playground. You’ll find that they allow you to discover bugs much faster (since you don’t have to run the code).

Thread Thread
 
yaser profile image
Yaser Al-Najjar

Ah, now I get your point...

You're trying to get things checked at compile time, but I'm not sure if the compiler is really suited to check the app logic (the compilers' job is to check syntax and such).

wouldn’t it be better to find out at compilation that a mistake was made?

Not really, I trust my tests more than the compiler, cuz the app logic might break one day (one way or another), and the beauty of tests is to get that logic checked everytime you go into the building stage.

Thread Thread
 
jvanbruegge profile image
Jan van Brügge • Edited

@yaser

the compilers' job is to check syntax and such

I completely disagree here, ideally the compiler would check all your app logic too, the more you can get checked by the compiler, the less tests you need to maintain. Languages like Haskell are popular just because the compiler can help you a lot.

I trust my tests more than the compiler

Tests can never show the absence of bugs, only the presence. Having a type system cut the possible inputs down to (in this case) a finite amount of values is far more valuable than testing the 4 values you mention in your unit tests.

@Cubicle

The problem with that dictionary solution is that it relies on throwing an error at runtime

Not with TypeScript, the following code will throw a compiler error if you change the TrafficLight type, without adding something to the object:

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];
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
cubiclebuddha profile image
Cubicle Buddha

Great work Yan. Yes, your type would require each key to be present. It’s another thing I love about TypeScript. There are so many ways to express concepts. :)

Thread Thread
 
yaser profile image
Yaser Al-Najjar • Edited

I agree with you in this TypeScript scenario.

But, as for Python (or any similar lang), I'm not sure this would be the case since this even goes against the Python moto: "let the exceptions fly and catch them later".

So, defensive programming model might be different from a lang to another.

Thread Thread
 
cubiclebuddha profile image
Cubicle Buddha

Interesting. I tried to find an article about Python and “letting the exceptions fly” but I couldn’t find anything.

One should always choose the best tool for the job. Sometimes that might be throwing/catching an error, and other times it might mean preventing it with the type system. Why limit yourself to one tool?

“When all you have is a hammer, every problem starts to look like a nail.”

Thread Thread
 
yaser profile image
Yaser Al-Najjar

I think the last time I heard it about was in a video or so, but the correct idiom is "Easier to ask for forgiveness than permission"

This video explains it in a nice way: youtube.com/watch?v=x3v9zMX1s4s
And this article summarizes things: devblogs.microsoft.com/python/idio...

Sometimes that might be throwing/catching an error, and other times it might mean preventing it with the type system

I can totally relate after I saw how TypeScript goes (I never used it before, just the old normal JS).