[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