List Info

Thread: Re: Making Controllers thin and Models thick




Re: Making Controllers thin and Models thick
country flaguser name
United States
2007-07-18 09:49:50
--- Bill Moseley <moseleyhank.org> wrote:

> On Wed, Jul 18, 2007 at 09:39:25AM +0000, Zbigniew
> Lukasiak wrote:
> > Hi there,
> > 
> > I am too working on a thick model component. 
It's
> a ResultSet base
> > class with functions bearing (provisional?)
names:
> build_create and
> > build_update.  They do params validation and
> update the database in a
> > transaction with data for both the individual
> record and related
> > stuff.
> 
> Sounds like both you and Ken are pushing the
> validation into the
> model -- or rather the ORM layer.  The model needs
> to do some
> validation, of course, and I like to push that into
> the RDBMS where
> possible.
> 
> I do wonder if that's not coupling the ORM and the
> validation too
> closely.  Not that it happens very often, but if you
> decided to change
> ORMs you would would still want the same validation
> of input data.
> 
> I tend to have a separate layer between the
> controller and the model
> for validation.
> 
> > In short the CRUD controller actions using it can
> be as simple as:
> > 
> > sub update : Local {
> >    my ( $self, $c, $id ) = _;
> >    if ( $c->request->method eq 'POST' ){
> >        my $update_result = $c->model(
'DB::Table'
> )->build_update(
> > $id, $c->request->params() );
> >        if ( $update_result-> eq 'OK'
){
> >            $c->res->redirect(
$c->uri_for(
> "table/view", $id") );
> >        }else{
> >            $c->stash( update_result =>
> $update_result );
> >       }
> >    }else{
> >        $c->stash( item => $c->model(
'DB::Table'
> )->find( $id ) );
> >    }
> > }
> 
> 
> I suspect you write that enough times and you will
> notice the common
> code.
> 
> My Create/Update controllers tend to look like this:
> 
>     sub edit : Local {
>         my ( $self, $c, $id ) = _;
> 
>         $c->post_redirect( 'list', 'Foo was
updated'
> )
>             if $c->update_from_from( $id );
> 
>     }
> 
> Because update_from_form knows the action path and
> can therefore find
> the associated form.  It can also determine what the
> concept of a
> posted form is in a single place.  And the
> associated form knows what
> model class to update or create a row in.  And the
> model class knows
> how to validate ids.  And the form knows how to look
> at the model
> class and determine lookup values for one-to-many
> and many-to-many
> relationships.
> 
> I might validate $id a bit more to make sure the
> current user can
> access it, but that can also happen in a chain or
> auto method.  Or
> that might be considered part of the validation and
> the form module
> can validate that the user can access $id.  But, I
> kind of consider
> that more of a controller responsibility since an
> invalid $id in the
> path for a given user is an invalid path (and thus
> maybe a 404).
> 
> -- 
> Bill Moseley
> moseleyhank.org
> 

I've come to the reluctant conclusion that for
anything other than trivial applications you will need
to validate in a couple of places.  Obviously the
database should be properly designed to enforce
integrity rules.  If you are using a database that
let's you create custom types, like Postgresql, you
can take it a bit further and actually create self
validating types for your columns.  I do this for very
common things like email addresses.  Postgresql is
nice for this since you can create custom types and
domains using Perl as your procedural language.

I end up mirroring a lot of this in DBIC using
DBIC::Validate since I'd rather catch syntactical
errors in my code instead of throwing a database
error.  For me that's the last line of defense.

Validation in the business logic is a different beast
since here you are enforcing not just types value but
actual business rules.  Although in theory you can do
all of this in the database or at the ORM level it's
usually best not to since your business logic is
actually trying to capture the full domain of activity
for your system, and this is hard to do with tables
and triggers.  Not impossible, just can be messy and
not too flexible.

I tend to think of this as 'spell checking versus
grammar checking'.  Your domain code is the grammar
for a particular business activity.  At least I think
of it that way.

At the User Interface level you also have checking
that has it's own needs.  For example you might have a
business process to create a new account for a user. 
At the UI level you ask for a new password and to
repeat the password in another field to verify that
you typed it correctly.  For me that is validation for
a user interface model and doesn't belong in the
domain logic, ORM or in the controller.  This is where
reading the code for the Reaction project has really
helped me to think about this.  

If this sounds like validation is scattered all over
your code, it doesn't have to be.  Because validation
tends to be a lot of configuration files stuff that
you can centralize if you want.  Data::Formvalidator
can cover a lot of this, since you can use it in DBIC
and has decent integration with Template Toolkit if
you are using that for your presentation layer.

--john



       
____________________________________________________________
________________________
Need a vacation? Get great deals
to amazing places on Yahoo! Travel.
http://travel.yahoo.com/


_______________________________________________
List: Catalystlists.rawmode.org
Listinfo: ht
tp://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-
archive.com/catalystlists.rawmode.org/
Dev site: http://dev.catalyst.per
l.org/

Re: Making Controllers thin and Models thick
country flaguser name
United States
2007-07-18 10:29:56
On Wed, Jul 18, 2007 at 07:49:50AM -0700, John Napiorkowski
wrote:
> I've come to the reluctant conclusion that for
> anything other than trivial applications you will need
> to validate in a couple of places.  Obviously the
> database should be properly designed to enforce
> integrity rules.  If you are using a database that
> let's you create custom types, like Postgresql, you
> can take it a bit further and actually create self
> validating types for your columns.  I do this for very
> common things like email addresses.  Postgresql is
> nice for this since you can create custom types and
> domains using Perl as your procedural language.

Yes, validation is a bit generic of a term.

For me, the database should try and enforce a valid state
of
the application.  An order row better reference a customer
row.
An order status better reference a valid value in the status
table or
have a valid check constraint.

Doesn't mean a bit of raw DBI can't hose the application, of
course.

For application state changes I try and abstract that into a
method in
the model.  I rarely have ORM specific code in the
controller.

I tend to not validate things like email addresses or phone
numbers at
the RDBMS level -- it's not critical to the state of the
application
typically.  That's left to an I/O layer that is my user
input
validation code.  That code can be used outside of Catalyst
-- and
as I commented before, it's not tied to the model/ORM
either.

Application state changes are typically caused by user
input. And user
input is often multiple fields.  So, it makes sense to
defined
forms for handling a set of fields all as one unit.  That
validation
is also not easily defined in a static configuration file
(or by
constraints on the database) so it also makes sense the
forms are
bundled with code.

I doubt there's any best approach.  But, if the idea is
thin
controllers then I like using one line of code. ;)

-- 
Bill Moseley
moseleyhank.org


_______________________________________________
List: Catalystlists.rawmode.org
Listinfo: ht
tp://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-
archive.com/catalystlists.rawmode.org/
Dev site: http://dev.catalyst.per
l.org/

Re: Making Controllers thin and Models thick
user name
2007-07-18 12:24:55
On Jul 18, 2007, at 10:49 AM, John Napiorkowski wrote:
> validating types for your columns.  I do this for very
> common things like email addresses.  Postgresql is
> nice for this since you can create custom types and
> domains using Perl as your procedural language.

<pet-peeve>
Please tell me you're either doing *real* email validation
(e.g.  
Mail::Address), or something overly lax..  Aside from sites
that  
won't let me enter valid email addresses (keep in mind that
just  
about the only character not legal in an email address is
NUL).  I've  
even had sites who "updated" their validation such
that people who  
previously had accounts could no longer login. 
("+" is the really  
common one to get rejected, but I had a friend who had his
email  
rejected once because it had a "-" in the domain
name!)

My rule of thumb on email validation is "don't
bother".  Or rather,  
if you really care, send mail to it and ask them to respond.
 After  
all, just because it's valid doesn't mean it *works*.  I
think a lot  
of sites do it "just because".  Originally it was
done because people  
kept "making mistakes."  Of course the most of the
mistakes were  
intentional attempts to avoid getting spammed (somewhere.com
was  
*real* popular for fake addresses).

If you're just checking for typos "/.+.+..+/" is probably  
sufficient.  (Assuming of course that you don't want me to
enter  
"somewhere.com!nazgul" as my email address, even
though it might well  
work, and is certainly "legal".)
</pet-peeve>

> I end up mirroring a lot of this in DBIC using
> DBIC::Validate since I'd rather catch syntactical
> errors in my code instead of throwing a database
> error.  For me that's the last line of defense.

Are you referring to DBIx::Class::Validation, or is there
another  
module.  I looked at that, but it didn't seem to make any
use of the  
actual schema data.

> I tend to think of this as 'spell checking versus
> grammar checking'.  Your domain code is the grammar
> for a particular business activity.  At least I think
> of it that way.

That's a good metaphor.

_______________________________________________
List: Catalystlists.rawmode.org
Listinfo: ht
tp://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-
archive.com/catalystlists.rawmode.org/
Dev site: http://dev.catalyst.per
l.org/

OT: fake email addresses (was: Making Controllers thin and Models thick)
country flaguser name
Germany
2007-07-18 13:47:44
* Kee Hinckley <nazgulsomewhere.com>
[2007-07-18 19:35]:
> Of course the most of the mistakes were intentional
attempts to
> avoid getting spammed (somewhere.com was *real* popular
for
> fake addresses).

http://asdf.com/asdfem
ail.html
http://weblog.sint
eur.com/?p=15846

Regards,
-- 
Aristotle Pagaltzis // <http://plasmasturm.org/&g
t;

_______________________________________________
List: Catalystlists.rawmode.org
Listinfo: ht
tp://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-
archive.com/catalystlists.rawmode.org/
Dev site: http://dev.catalyst.per
l.org/

[1-4]

about | contact  Other archives ( Real Estate discussion Medical topics )