Say it once, Don't Repeat It

The following is a story about me (you can call me "guy") who was working as a
consultant on-location (we can refer to as heaven) where he had an interesting
conversation with one of the lead system architects (herein after referred
to as God).

One day, Guy explained to God that the webapp has many parameters hitting it,
some of which are actually the same types of parameters but with varying and
arbitrary names, and that while there's is no realistic way to stop the Angels
from creating templates with parameters named however they choose, Guy suggested
to God that he use Validation::Class to help organize/standardize the
handling of parameters in the webapp and specifically leverage it's automatic
handling of parameter aliases. God chuckles, "but that would suggest that we
would need to create two definitions describing the same piece of data" said God
referring to the existing Moose attribute definitions, and the proposed
Validation::Class field definitions. I tried to talk to God about context and
how different rules apply at different layers but god is ... well God. The
following is much of what was discussed when I last talked to God.

Before I begin, I'd first like to regurgitate a statement from the Validation::Class
whitepaper which reads, "A data validation framework exists to handle failures,
it is its main function and purpose, in-fact, the difference between a validation
framework and a type-constraint system is how it responds to errors. There are
generally two types of errors that occur in an application, user-errors which
are expected and should be handled and reported so that a user can correct the
problem, and system-errors which are unexpected and should cause the application
to terminate and/or handling the exception. Exception handling is the process of
responding to the occurrence, during computation, of exceptions (anomalous or
exceptional situations).".

For the readers that may not already be aware, your OO system is NOT a
user-input validation mechanism nor should it be used as such.

The following is just one of many cases to be made about why you shouldn't use
your OO system for user-input validation.

A "field" in Validation::Class is not the same as an attribute in an OO system,
i.e. in Validation::Class fields are never required to be present. This means
that any field in a class can be validated individually or in concert with any
other field(s) which is very useful. In order to achieve this with an OO system
you would need to either make all attributes optional or make required attributes
able to accept undefined values. Both choices leave you making a poor design
decision. Consider the following OO configuration:

# has 'a'
# isa 'maybe|Str'
# required

# has 'b'
# isa 'maybe|Str'
# required

In order to validate (a or b) independently I would be forced to declare
both attributes as optional or (if undef values are accepted) have the calling
class determine which arguments are missing and fake them as both would need to
be present at the time of instantiation, even if as undef. There are a few more
approaches I can think of, none of them ideal. Needless to say that by making
all attributes optional you've effectively bypass the single point-of-validation;
I hope that statement is self-explanitory.

Alternatively, and I imagine more commonly, you could define your class
normally, throw in some coercions, trap and massage exceptions, then report
those "exceptions" to your users (poor saps), and hopefully you app is only
localized for one language or your could design your exception traps to be aware
of the end-users language and throw localized exceptions. And if you're doing
all that then you're basically rolling your own validation framework and that's
just awesome, .. and I'm sure you've covered every nuance and consideration :}

Consider the following V:C configuration:

# field 'a'
# required

# field 'b'
# required

No field is required to be present and there is no single point-of-validation,
i.e. the validation logic is not in the constructor and because it is separate
and accessible as a function on the class we can validate and re-validate at-will.

For the sake of clarity, I use the phrase single-point-of-validation to mean
that, in an OO system, technically once you get pass the constructor each method
assumes the data remains valid, even if the data has passed through multiple
methods which manipulates the data, and there is no way to recall the validation
logic in the constructor (afaik).

... So that was a long-winded explanation of the obvious, OO-type-contraint
systems are not practical for user-input validation and definitely not as practical
as a "real" validation library, like Validation::Class. But you already knew that.

Just the other day, Mithaldu explained to me that re-usability of Validation::Class
is one of it's greatest strengths but he didn't think I touched on it enough in
the documentation, especially in the form of an example.

I explained to him that Validation::Class was created around the philosophy of
"Say it Once", i.e. to declare validation rules once, use them anywhere/everywhere.
I told him that once your defined a validation class using the keywords (sugar),
you could use the single class to validate data in your webapp controller,
model, command-line scripts and even on the client via JavaScript, and anytime
the validation rules change, so will these affected areas. He said, "Next time
lead with that", and then he challenged me to put together a small program that
showcased my claims.

So here it is, the following is a minimalistic example of a micro webapp using
Validation::Class on the client and server.

github: https://github.com/alnewkirk/dry.cgi/blob/master/dry.cgi
demo: http://sandbox.anewkirk.dev.ana.io/

* dry.cgi uses a single validation class to validate a mojolicious-lite app
parameters on both client-side and server-side. We could also use the validation
class as a buffer for our data model.

Leave a comment

About Al Newkirk

user-pic ... proud Perl hacker, ask me anything!