views:

211

answers:

7

I've read a lot of Refactoring literature as of late and a common theme I see in examples is the reduction of lots of IF statements. The below is a very simple code block that first checks to see if an email address is supplied and if so, then proceeds to validate the email address. I typically see a lot of this type of code which always looks a bit messy, especially if there are multiple variables.

if (string.IsNullOrEmpty(email)) {

    throw new ApplicationException("Email Address Required");
}

else {

    if (!ValidationService.EmailAddressIsValid(email)) {
        throw new ApplicationException("Invalid Email Address");
    }

}

My question is, is this example perfectly acceptable? Does it smell? How might one refactor this snippet?

+6  A: 

throw never returns, so I would use the following for better readability:

if (string.IsNullOrEmpty(email)) {
    throw new ApplicationException("Email Address Required");
}

if (ValidationService.EmailAddressIsValid(email)) {
   throw new ApplicationException("Invalid Email Address");
}

// continue here if no error was detected
ur
-1: is not really *refactoring* and does not reduce the number of if-s
chiccodoro
couldn't disagree more chiccodoro. while it doesn't reduce the number of if-s, it did remove one else and made it more readable, especially if that is at the top of your method and acting as a guard...
Bryce Fischer
@Bryce: Well, it might *slightly* improve readability (although that's quite subjective), but the OP's question was about *the reduction of lots of IF statements*. With this proposal, you still have 2 if statements directly in the code. If you have multiple methods doing the same check, you have the validation logic in many places instead of one. That's however what many refactoring concerns are about (IMHO). (BTW: Sorry for late answer, didn't notice your comment because it doesn't start with @chiccodoro)
chiccodoro
A: 

It's fine but you could simplify it more.

if (string.IsNullOrEmpty(email)) {
    throw new ApplicationException("Email Address Required");
} else if (ValidationService.EmailAddressIsValid(email)) {
 throw new ApplicationException("Invalid Email Address");
}
Moncader
-1: No refactoring, no reduction of if statements, not even as simple and readable as it could be if one merely simplifies the code.
chiccodoro
Code refactoring is the process of changing a computer program's source code without modifying its external functional behavior in order to improve some of the nonfunctional attributes of the software. Therefore I did refactor the code. Get your facts straight before you downvote someone.
Moncader
A: 

The first thing you could do would be to remove the lines else { and its corresponding }.

This is because the first throw statement would ensure that the code currently in the else block would never execute if the email address was missing.

Richard Fawcett
+6  A: 

It's hard to refactor such a small snippet - And I'll skip the usual statement about not refactoring without tests...

When I see code like this, I think

  • Why does the ValidationService not hold the logic for the null check? If this is not in a class that holds validation logic, then why are we checking for required fields here?

  • I would probably make the null check into a helper so the code could be more like:

    ThrowIfRequiredFieldMissing(email, "Email Address");

  • remove the else, since throw cannot continue

  • Create a helper for the throwing: FailIf( !Validation.EmailAdressIsValid(email), "Email Address"). This would throw your validation exception, and allow you to change exceptions later if needed (although I'd cross that bridge when you come to it)

There's lots of other possibilities, like a dictionary of Func<>s, or a strategy pattern applied to a list of fields, and on and on and on. But without more code, deciding what to do (if anything!) is just guesswork.

Philip Rieck
+1  A: 

Refactoring is more than just a little bit of code styling.

You're validating a user entry, so you would probably want to define or reuse an existing validation framework instead of embedding if statements in the code. You're almost there it seems, since you have the ValidationService for the second validation.

So my proposal: Include the string.IsNullOrEmpty check in the implementation of EmailAddressIsValid.

Of course this only moves one if statement, but if you use the EmailAddressIsValid in multiple places it will reduce the if statements. Further the validation logic is then really consolidated in one place. Currently it isn't.

Another minor thing: Rename EmailAddressIsValid to IsEmailAddressValid, because it's a common convention to use "Is" as a prefix for functions that return a boolean.

chiccodoro
A: 

Ugly variant, but workable

string msg = string.Empty;    
if (string.IsNullOrEmpty(email))
{
   msg = "Email Address required";
}
else if (ValidationService.EmailAddressIsValid(email))
{
   msg = "Invalid Email Address";
}

if (msg != string.Empty())
   throw new ApplicationException(msg);
Marcel de Kleine
+2  A: 

If you would really like to make your code readable, you could even do something like this:

throwExceptionIfEmailIsEmpty(email);
throwExceptionIfEmailIsInvalid(email);
// continue to process the e-mail here...

With this code extracted into separate functions:

private void throwExceptionIfEmailIsEmpty(String email)
{
    if (string.IsNullOrEmpty(email))
        throw new ApplicationException("Email Address Required");
}

private void throwExceptionIfEmailIsInvalid(String email)
{
    if (ValidationService.EmailAddressIsValid(email))
        throw new ApplicationException("Invalid Email Address");
}

It might seem a bit exessive, but it makes it way much easier to see what's really going on!
(Inspired by Uncle Bob's Clean Code - Functions should do one thing. They should do it well. They should do it only. (or something like that) - if anyone wondered ;))

Nailuj
And just to mention: you could even take it a step further, and wrap the two throw-functions into yet another function such as `throwExceptionIfEmailIsEmptyOrInvalid(email)`. Your code gets both easier to read and self-documenting.
Nailuj
... or just `ValidateEmail(email)`. (+1)
chiccodoro