Are validation errors exceptions?

I was discussing with a customer about the best way to design, code and use business validation logic. First of all, there were a number of decisions already made:

  1. Business entities will be represented as typed datasets
  2. There will be one data access logic components (dalc) per each business entity. The dalc will do CRUD operations
  3. There will be (roughly) one business logic component per business entity
  4. The business validation logic will be implemented in one method, Validate(), member of the business logic component

So, in general terms, we'll have: VoucherDalc, DsVouchers and VoucherManager. Now let's focus on the validation issue. As many validation errors could be detected in the DsVouchers dataset, a reasonable signature for Validate() is:

public ValidationError[] Validate(DsVouchers ds)

Where a ValidationError object (structure?) has enough information to describe the problem to the final user. The method is public so as to allow the UI logic to call Validate() when necessary. Furthermore, the business logic component (VoucherManager) will also be responsible for passing update requests to the data layer, so it needs this method:

public void Update(DsVouchers ds)

But, so that no invalidated data is sent to the data layer, Update() should call Validate(), for this reason a better signature (and implementation) for Update() is:

public ValidationError[] Update(DsVouchers ds) {

ValidationError[] errors = this.Validate(ds);

if (errors.Length > 0)

return errors;

...

}

But I don't like this because:

  1. Is it natural (from a business design point of view) that Update() returns a ValidationError array? Not really
  2. Programmers calling Update() may easily ignore the returned value, so errors are ignored!

That's why a better implementation could be:

public void Update(DsVouchers ds) {

ValidationError[] errors = this.Validate(ds);

if (errors.Length > 0)

throw new ValidationException(errors); // now we use an exception

...

}

Performance suffers because of the use of exceptions but we win:

  1. No unnatural returns from Update()
  2. Errors are harder to ignore (a very lazy developer can still do a try { ... } catch {} though)
  3. If carefully written the ValidationException can travel thru physical layers

So, in spite of the general recommendation of using exceptions only for errors that happens outside the application control (e.g. printer not ready, server not available, disk full, ...) may be it's a good idea to use exceptions to report validation problems as part of the Update() method. Opinions?

5 Comments

  • I'll be following this one closely as I've been part of many similar discussions. Opinion? Well, I wish I had one on this. Basically, you are throwing an error back the the PL saying "The information you gave me was invalid - please try again" - what's wrong with throwing an exception here... I don't think anything is wrong with it actually. You can't ignore exceptions - and you want to make sure someone fixes it before re-submitting. Basically, you would agree that the DAL should only accept "good" data without exception. Thus if the data is "bad" it should be with an exception (excuse my play on words here).



    Now, what you do with the validation errors might be interesting - I've seen solutions where the PL have a running exception collection that maintains a "to do" list used to guid users through handling errors. I've seen others that simply report the errors back to the user in some way that can be reflected in the GUI.



    My bigger question is around hierarchical data. Are you validating an object at a time - or a whole tree of objects: Policy(s)->Client(s)->Vehicle(s)->Address(s) etc...Some times a business rule needs to have a much broader context to perform object or attribute level validation - ie. a child object must be aware of the values of its parent to perform validation.



    One even bigger question might be - how you handle data driven business rules - rules that change over time yet are immutable (they always exist and are replaced with new ones over time). I got way off topic here - sorry.

  • I don't think validation should cause exceptions. Exceptions are expensive to throw.



    Look at validation for a page object in ASP.NET and mimic that behavior. I would create an interface IValidateable, with method Validate(), and properties ValidationErrors and IsValid. Extend the DataSet and include your new interface on the derived type.



    Another alternative is to create a type DataSetValidator that exposes the same method and properties.



    Your example shows that you are validating a DataSet, so I assume that you are actually validating based on business logic rather than the DataSet's schema. So, I would tend towards a design where you marshall the DataSet to another layer and you encapsulate business validation within it. You want to minimize the number of trips over the wire, so you might design a Response object to return from the validation framework that includes information relating to the message, similar to the HTTP status code.



    Just thinking out loud, but I reserve exceptions for "MyComputerIsOnFireException" and "SomeoneUnpluggedTheDatabaseServerAgainException". Eveything else is typically a test for condition.

  • ArgumentNullException and ArgumentException are two examples of using .Net exceptions to express an issue with a parameter and therefore validation. So making the leap to ValidationException is a small one and I am all in favor of it.



    Regarding performance...the issue should really be give me good data and i won't throw an exception and your performance won't be effected. Returning a data structure that talks about all of the different errors introduces a new structure to the mix that everyone must also become familiar with...and now use as a return type...a reference parameter...or you could jump to unmanaged code and create a memory map tied to your process space...but wait will that work with asp.net? sorry a stream of thought....



    but everyone understands an exception...i vote to use it.

  • Throwing an exception containing all of the validation errors for an object is definitely the way to go for server-side validations! Why should you be concerned about performance if something abnormal has happened such as validation errors? Validation errors cause information not to be processed in the normal manner. A system's performance should be considered for "normal" processing scenarios, not the 10% - 15% scenarios such as validation errors. If your system is constantly throwing validation errors, then you need to revisit your UI design. That should be providing users with a clear understanding of what they should be providing as information for processing and the format they should provide it.

  • Am I missing something here? The DataSet has the ability to gather error messages (validation or otherwise). There are HasError flags on the DataSet, each DataTable and each DataRow. The DataRow also has a RowError attribute and you can also set ColumnErrors. My issue is how do you handle these nicely is ASP.NET - the GUI does a reasonable job for you.

Comments have been disabled for this content.