1

I've read Defensive Programming vs Exception Handling? and if/else statements or exceptions, but none contain something relevant to what I'm searching for.

Taking into account that exception handling is more computational expensive than just carefully designing your code and avoiding certain scenarios, I recently came to the following question: what is the computational complexity "threshold" over which Exception Handling should be preferred?

In my case, I am receiving data from an external middleware and some times fields are null. There are two cases I can handle this.

First

try {
    if (user.departNameEn.Equals(selectedUser) 
    || user.departNameFr.Equals(selectedUser) 
    || user.departNameDe.Equals(selectedUser)) {
        string fileName = AppDomain.CurrentDomain.BaseDirectory 
            + @"Images\Users\" + user.Id + user.ShortName + ".png";
        if (File.Exists(fileName))
        {
            retVal = fileName;
            return retVal;
        }
    }
}
catch (NullReferenceException e)
{
    continue;
}

Second

if (!string.IsNullOrEmpty(user.departNameEn)
    && !string.IsNullOrEmpty(user.departNameFr)
    && !string.IsNullOrEmpty(user.departNameDe)
    && !string.IsNullOrEmpty(user.Id)
    && !string.IsNullOrEmpty(user.ShortName)) {
    if (user.departNameEn.Equals(selectedUser) 
    || user.departNameFr.Equals(selectedUser) 
    || user.departNameDe.Equals(selectedUser)) {
        string fileName = AppDomain.CurrentDomain.BaseDirectory 
            + @"Images\Users\" + user.Id + user.ShortName + ".png";
        if (File.Exists(fileName))
        {
            retVal = fileName;
            return retVal;
        }
    }
}

Intuitively, the first approach is much more clean and elegant than the second one but which of these is computationally less expensive? Where do the limits of defensive programming end?

Note to duplicate report: As I explained in the introduction, I've read the two main topics for Exception Handling vs Defensive Programming but what I'm actually asking is something different and very specific: when Defensive Programming becomes computationally more expensive than just simplifying your code and adding a single try-catch statement?

12

I am receiving data from an external middleware

File.Exists

So let's look at the bigger picture. You have data. That data was serialized. Then send over a wire. Then deserialized. And in the end, you even access the file system based on that data.

Looking at how you handle this from a perspective of performance is completely unnecessary, because computation power is really not the bottleneck by far in your scenario. It's like wondering whether the diver of an 18-wheeler should be put on a diet to save on overall weight.

As for the 18 wheeler: the best solution is to let the driver do whatever makes him happy and motivated to drive their truck. A pound or two in either direction really do not matter. So do what is best for the programmer. Whatever is the more readable, easier to understand code by your standards is the best solution here.


On an unrelated note:

user.departNameEn.Equals(selectedUser)

is there a reason you call Equals or is that maybe just a bad Java habit?

user?.departNameEn == selectedUser

This line does the same and will not throw on one side being null. The only "disadvantage" would be that if selectedUser is null it's considered equal too, instead of throwing as in your line.

  • For your last comment: 1. It's a "bad" habit from Java, yes, but Equals() at least to me reminds me that I compare object and not primitive types (string is not a primitive). 2. I am aware of the null safe operator but the project I am working runs on an older version of .NET that does not support it. 3. My question is whether there is an overall limit to Defensive Programming and not to find a specific workaround to "cover" the problem. – Lefteris008 Sep 17 '18 at 8:39
  • 7
    string is not a value-type, that's true, but why care? == is fine with null on one side. The null-safe operator is optional, just leave it out. Your solution assumes user is never null anyway. And as for your question: yes, the limit on defensive programming is when it does not give you any perceivable advantage (as in this case). Then you should ignore it and go for things that do give you an advantage, for example more readable code. – nvoigt Sep 17 '18 at 8:46
7

Are you expecting null data?

Exceptions are intended for exceptional circumstances.

The simple rule of thumb for situations like this is to handle standard cases with logic, not exceptions.
If a NULL is an error, indicating a transmission failure for example, then an exception is suitable. If however, it is indicating that an optional field is empty, then this is a "normal" use-case, and should be checked with logic.

The example used in the question implies that the data in invalid if some data is missing (and that this is unexpected).
I would recommend exceptions in this case.

  • My simple rule of thumb perfectly matches your answer: Use exceptions if and only if you want to signal to your caller that your method failed to fulfill its contract. I never use exceptions in the normal control flow. – Ralf Kleberhoff Sep 17 '18 at 19:13
  • These fields should not regularly contain null data but as it seems mandatory fields are empty. – Lefteris008 Sep 18 '18 at 6:40
3

This depends on more information than you are giving us. What does it mean if some fields are null? Is that (1) totally admissible and should just be interpreted as a value of ""? (2) not supposed to happen but common in practice and susceptible to a workaround? (3) possible to deal with but only with user input? (4) a flaw that makes processing that record impossible? (5) a sign of such serious trouble that the entire import must be abandoned ("halt and catch fire")?

Exceptions are not just more expensive to process at runtime, they also structure control flow in a different way than standard control structures. You can build almost any possible logical flow with if statements, but once you throw an exception out of a block there is no reasonable way of getting back into it again, and nested catch clauses are almost impossible to write in an readable way. Also, programming a try...catch raises certain expectations in readers of the code; if these are not actually true, this makes the code much harder to understand. Those are at least three different aspects of choosing how to handle uncommon situations; others can apply depending on what exactly your code is processing.

  • (1/2) From the examples I've provided, you can see that I am parsing five fields that come externally from a middleware call (code not available for that). Middleware is not handled by me, so it is possible that each one of them could be null. Trying to perform an equality check with a null on C#, throws an exception. So, either I create a much more complex if-else statement that removes this possibility, or I simplify it and encase it in a try-catch statement. My question is more general: where if-else performance advantage ends over a try-catch? – Lefteris008 Sep 17 '18 at 7:44
  • (2/2) Can I create an if-else condition that has 15 members to validate and still be more efficient than a more shorter version with three members and encased into a try-catch? – Lefteris008 Sep 17 '18 at 7:46
1

The two code examples are not logically equivalent.

In the first case just one needs to be filled and satisfy the condition. In the second case, all three need to be non-empty.

This in my opinion is the big thing why you should go for the first version. You made the code more complex and ended up with something else then intended. Use the code the expresses the best what you want to do in the easiest to understand way.

0

The goal of defensive programming is to check that everything you want is in the right state before starting not the "I don't wanna exception way" of doing things.

In your case : some field can be empty by defintion. So no checking for null is just to avoid NRE is not defensive programming it is the normal way of handling it.

On my side defensive programming is mainly based on throwing (in java) IllegalStateException/IllegalArgumentException a lot (so I'm more in offensive programming as defined per Wikipedia).

Furthermore the first sample code you provide to illustrate what you want to ask is definitively wrong whatever way you want to go : cathing a NullReferenceException is a no go. By doing that, you may catch the NRE you want but if the code evolve, you may also catch unwanted NRE specially if later, you or someone else update the code.

Finally as an aside for the code you quoted the best move is just to switch the side of your test : selectedUser.equals(...) because you are probably sure at this point that selectedUser is neither null nor empty. This is not a defensive programming solution, just what you should do to have the clearest code and avoid unwanted errors.

  • The user object that I am validating, is generating in a for-each loop from items that come directly from the middleware (auto-generated WSDL code). I can anytime change this code, but I don't want to. Plus, my question, yet again, is about the advantage limit of Defensive Programming over Exception Handling and not to overcome this problem. – Lefteris008 Sep 17 '18 at 9:27
  • @Lefteris008 see my edit, I developped more the defensive programming aspect. – Walfrat Sep 17 '18 at 14:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.