[Catalyst] best practices for Catalyst development

David Storrs dstorrs at dstorrs.com
Thu Aug 11 19:55:34 CEST 2005


On Aug 11, 2005, at 12:10 PM, Dominique Quatravaux wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> David Storrs wrote:
>> Well, as you say, it doesn't match either the historical or the
>> modern usage
>
> I have to nit-pick a bit here. Our most venerable c2.com
> (http://c2.com/cgi/wiki?ModelViewController) is far from reaching a
> consensus on the "historical" definition of Model-View-Controller,
> except if what you mean by that is the Smalltalk doctrine.

Yup, I did.

> Unfortunately Smalltalk treats MVC mostly as an object-oriented
> pattern (View being an Observer of Model, requirements on inter-class
> coupling and control flow), which is ideally suited to GUI apps but
> not relevant for the Web

Hence my distinction between "historical" and "modern".  But yes,  
"desktop" and "Web" would have been better choices.

> [...]
>
> In other words: the very fact that there *is* a controversy on what
> "modern" MVC means, may be nothing more than yet another thinko from
> the would-be Java software architect crowd >:->

Yes, it may.  I'm quite prepared to believe it.  I'm also prepared to  
believe that there really is a difference.  Can we talk about it and  
come up with reasons for and against, or do we need to pick one view  
and take it as received wisdom?


> Let's get pragmatic again. Perrin is IMHO successfully arguing the
> need for a clean separation between stuff-that-is-useful-in-crontabs,
> stuff-that-draws-pictures-blasts-out-HTML-whatever and
> stuff-that-holds-everything-together.

Could you, or Perrin, point me at his arguments?  I've seen a lot of  
assertions, but so far I don't believe anyone in the thread-- 
including me--has said "I do XYZ because of ABC.  Here are the pros  
and cons that I evaluated to make this decision."

Maybe that's the problem...I've been trying to solicit other people's  
opinions because I don't feel like such an expert that I should be  
tossing mine off.  Clearly, this approach isn't working.  Let me try  
it a different way:


Catalyst is an MVC framework. When you write an application in it,  
you need to divide all of the functionality of your application into  
one of those three categories (M, V, or C) [*].  Here's how I do my  
divisions; I'm new at this and realize that I have a lot to learn.  I  
would appreciate it if others on the list would look this over and  
offer constructive criticism on how I might do it better, or reasons  
for why I might want to pursue an alternative:

     [*] Ok, technically, you don't NEED to put all your  
functionality into M, V, or C...you can have all the functionality in  
App.pm if you want.  Or you can have completely separate modules that  
are not in the M, V, C paradigm.  These options are outside the  
intention of Catalyst and outside the scope of this thread.

     Also, this discussion is aimed at **best practices**.  We all  
know that in the real world of short deadlines, we take shortcuts.   
This is about how you would do it if you were doing it The Right Way(tm)


My divisions:

- V
     The View is only responsible for generating HTML output.

     TT.pm    A series of methods that do nothing but set $c->stash-> 
{template}

     The actual View logic goes in the templates, as TT directives.

     PRO: - There is almost no code in the View, so there is almost  
nothing to test/debug.
          - Low cognitive load: if I assume correct values in the  
stash, I can look at
              a template and figure out exactly what I will see.
     CON: ??


- M
     The Model represents a thin database-access layer, with little  
or no application-specific functionality.

     CDBI.pm        Inherits from C::M::CDBI::Sweet.
                      A base class for all the other model classes.
                      It establishes the connection and contains  
utility functions.

     <table>.pm     Inherits from CDBI.pm, above.
                      One class per table, containing nothing but the  
CDBI setup code.

     PRO: - There is almost no code in the Model, so there is almost  
nothing to test/debug.
          - Preference:  to me, the word 'Model' implies a passive  
object and the word
             'Controller' implies an active one.  Therefore, this  
style of implementing the
             Model as a passive database-access module fits easily  
into my brain.

     CON: - This is the opposite of the desktop MVC model, where the  
Model is the active object.
             Departing from standards is bad and can cause  
confusion.  OTOH, the passive Model
             is common in Web applications, so I think this is but a  
venal sin at worst.


-C
     The Controller contains all the application-specific code.  It  
is has predominant (though not exclusive) responsibility for  
controlling flow through the app.

     Controller.pm    A base class inherited by all the other  
Controllers.  Contains general
                         utility functions.

     Login.pm    Uses CDBI::Authentication to manage the login/logout  
actions

     Order.pm    Create, update, or delete an order.  I am starting  
to think I should break this
                     out into separate Controllers for each sub-task.

     Report.pm    View a report

     <other controllers, one per task-group>

     Each controller is responsible for catching the URL for a  
particular action, populating the
     stash, and then forwarding to TT.pm to have the template set.

     There should be separate,
     completely self-contained modules which the C calls out to in  
order to generate the values
     that are then stashed.  Doing it this way means that those  
generic modules are not dependent
     on your web app and can be reused in crontabs, CLI apps, etc.  
[Nod towards each of the multiple
     people on the thread who has previously asserted this idea.]

     PRO: - It is clear where code for a particular task will be.
          - Preference:  As previously mentioned, the word  
'Controller' sounds active to me, so
             it fits easily into the idea of doing most of the work.
          - Having almost all the app's code in the C means fewer  
points of interaction with the
             M and the V and therefore fewer points of failure.

     CON: When debugging, I need to flip back and forth between the  
code and the
              template file to verify that all the correct values are  
being stashed.

     DISCUSSION: I am unsure of whether it makes
     more sense to set the template here, to keep the two pieces of  
information (what template, and
     what values it is to be filled with) near each other.  If I did,  
that would leave no actions
     for TT.pm, which would leave it empty and unnecessary except for  
its inherited process() method.
     This would make it completely unnecessary to test or debug the  
View, which might be a good thing.
     OTOH, it feels strange and dangerous to have empty-but-necessary  
modules lying around...what if
     some eager-beaver deleted it to "lean up the disk"?  That's  
paranoia, but good developers look
     left, right, AND up before crossing the one-way street.

--Dks



More information about the Catalyst mailing list