views:

229

answers:

3

I want to do validation on my business code. I'm thinking on 2 ways to do this.

One, do the validation on my class property setters in the following fashion

class Student{

public string Name{

    get { return _name; }

     set {

        if (value.IsNullOrEmpty) throw exception ...
    }
}

}

Now, the problem with this approach is that, validation code is run every time Name gets assigned, which we may not need, like when fill it in with data from DB.

Two, which I prefer, put static methods on these entity classes, like

class Student{

public **static** void ValidateName(**string name**) {


    if (string.IsNullorEmpty(name)) 
    {
        throw ...
     }

    ...
}

Notice I'm using a static method instead of a instance method, like class Student{

public void Validate() {

    // validation logic on instance properties
    if (string.IsNullorEmpty(Name)) 
    {
        throw ...
     }

    ...
}

is because I'm not always getting a Student obj passed in, I do get primitive types like string name passed into a method often time, like

public static FindStudentByName(string name) { // here I want to first do validation Student.ValidateName(name);

   // qeury DB
   ...

}

If I do get passed in a student obj, then of course I can do

public static AddStudent(Student s) {

    // call the instance method
    s.Validate();
}


Now, I'd like to keep things very simple, so I don't want to go any one of the following approaches

  1. Use attributes on properties, like [StringLength(25)].

    One, because this requires Reflection and affects performance, there are tricks to get performance hit low, but again I want to keep it simpler the better.

    Two, I want my site to be able to run in Medium Trust. As reflection as I understand it requires Full Trust.

  2. Use any of the Validation Blocks out there, like MS. Enterprise Library etc found on CodePlex.

Now, I want to get your opinion on this,

what are some of the potential problems with the approach I'm going with?
Would this approach perform better, more readable, easier to maintain than the other approaches?
How are you doing validation on your middle tier?

Thank a bunch!

Ray.

+1  A: 

Option two is something that doesn't actually enforce validation, at least not without you manually calling validate. Therefore consumers of your objects could violate the rules.

I personally would go with something similar to your first example, as it ensures that ALL data is valid. it is an additional check on the DB side of things, but from what i have noticed, typically isn't a big deal.

Mitchel Sellers
I kinda want consumers to call on validation explicitly, so they have the flexibility and control over when validation happens. But, thanks so much for pointing it out!
ray247
The trouble with calling a validation explicitly is that nothing is stopping your consumers from skipping it or forgetting it. To guarantee validation, you need something outside their control.
Corbin March
Corbin's point was my reason why I wouldn't go with #2, NEVER trust users....
Mitchel Sellers
+3  A: 

I perform domain validation in the middle tier with a rules engine, very similar to the one written about here. A friend's project uses an approach similar to what you're proposing in your latter example and the end result is unmaintainable (brittle, hard to implement generic validation UIs). The rules engine approach is maintainable because it localizes all the validation and persistence rules in a single well organized location AND has each rule as a fully fledged class - but exposes the validation on domain classes similar to what you have proposed. Some people like dynamically compiling so they store them in a database for a high level of post-deployment configuration; in my case I like them compile time checked so there are rule definitions with lambdas exposed on a static class.

I know this isn't in line with what you want to do, but asking how I would do it and saying other approaches aren't simple enough would be like saying "how can you write reliable code, I want to keep it simple so unit tests are out of the question." To me treating each rule as its own class is good because its easier to maintain and document albeit more complex to implement.

cfeduke
+1  A: 

The approach you suggest seems to indicate that the set of validation should not be applied always. Which is ok. I've seen plenty of rules and validations we want 'most of the times' but not really always. So, the question becomes 'when do you want these validations to apply' ?

Say that, for instance, you have some validations you always want to apply and some you want to verify only when... I don't know.. you're about to save to the storage (database). In that case, the checks that apply always should be in the properties (see more on this below), and those that apply only when you're about to save to the storage should be in a method (maybe named along the lines of 'VerifyRulesForStorage') that will be called when appropriate (e.g. in the middle of your 'SaveToStorage' method).

One thing worth considering, I think, is the duplication you risk incurring when you have the same validation across multiple entities. Be it in the property, or in a 'VerifyRulesForStorage' method, it is likely that you'll have the same check (e.g.: String.IsNullOrEmpty, or CheckItsANumber, or CheckItsOneOfTheAcceptedValues, etc etc) in many places, across many classes. Of course, you can resolve this via inheritance (e.g. all your entities inherit from a base Entity class that has methods implementing each type of check), or composition (probably a better approach, so that your entities' class tree is driven by other, more appropriate, considerations, e.g.: all your entities have a Validator object that implements all those checks). Either way, you might want to stay away from static methods, cine they tend to create problematic situations if you are Test-Driven (there are ways around, when needed).

In our system, we actually have metadata describing the validation rules. The class' property name is used to retrieve the proper metadata, which then tells the system which rules to apply. We then have a validator object that instantiates the proper type of object to actually perform the validation, through a factory (e.g. we have one class implementing the IsRequiredString rule, one implementing the IsNumber rule, etc etc). Sounds like a lot of complexity, but, in a lrge system like ours, it was definitely worth it.

Finally, the off-the-shelves libraries out there might be a good alternative. In our case they weren't because of particular requirements we had - but in general.. there are benefits in using a wheel someone else has developed (and will support) over building your own (trust me, I love to rebuild wheels when I can.. I'm just saying there are cases where each approach is better than the other).

FOR