[Catalyst] Re: Controllers vs Models

David Storrs dstorrs at dstorrs.com
Mon Jun 6 18:15:19 CEST 2005

On Jun 6, 2005, at 11:25 AM, Justin Tocci wrote:

> Thanks David for replying.

Not a problem.  You have an interesting concept.

>> The  Platonic ideal MVC system has all business logic in the  
>> Controller,
>> all state in the Model, and all presentation is handled by the View.
> I disagree. I think the controller should control program flow in a  
> generic way, and that business logic is best factored out of it.

Well, two thoughts here.  First, I was talking about how the MVC  
pattern is usually presented in the literature.  I believe you are  
talking about how you think the MVC pattern /should/ work.

Second...your idea is interesting, and very powerful if done right,  
but I'm cautious about it.  I think it might end up being a silver  
bullet that hits you in the foot.  See below for why.

>> How much more separated out can the business logic get? Or are you
>> saying that it could be stored off in a config file (or DB)
>> somewhere?
> This is exactly what I'm saying. Ideally, the controller should go  
> to a different component to get the business logic, where all the  
> business logic and only the business logic lives. I don't want this  
> to get political, so... consider the example below.

Basically, you are talking about reducing the Controller to a pure  
dispatch role--it accepts events from the external world and forwards  
them to the business logic component.

Although this is good in theory, what it really amounts to is another  
layer of indirection with associated overhead.  The code to handle  
dispatch is pretty minor--especially in Catalyst, where it pretty  
much just consists of putting an attribute on the subroutine that  
implements the business logic.  I don't see what win you are looking  
to get by this separation.

Well, maybe I do...you are saying you want to have the logic in the  
DB, and have the controller fetch it out as needed.  This is often  
called SCID programming (Source Code In Database), and it has some  
powerful potential, although I personally have never seen a good  
implementation of it.

In this case, the problem is that either (A) the Controller will need  
to have enough knowledge of the business logic to know what to fetch  
(at which point you might as well have just put the business logic  
directly in the Controller and saved a DB access), or (B) the  
Controller must simply dispatch the request to the business logic  
component and say "here, I got this...figure out what to do with  
it."  Option B is exactly what Catalyst does now, so this just adds a  
redundant dispatch cycle.

> Example:
> You have a View component that should act a little differently  
> sometimes. For instance, a list page component should have a  
> different title depending on which table it is displaying. One way  
> to do it would be to have a separate component for each, another  
> might be to put logic in the View that picks a different title  
> based on the name of the table it is displaying. Another might be  
> to put the logic in the controller.

Another would be to use a template (c.f. Template Toolkit,  
HTML::Mason, etc), where the title is filled in from a variable.   
This is the way Catalyst currently does it.  I think this is exactly  
what you're looking for--the "business logic" (i.e., what title to  
use) is in the template file on disk, not in the View (or Controller,  
or Model) class.

> What I am proposing is to set the business logic off to the side,  
> separate it from the controller. This way you have all your  
> business logic in one easy to read place. You have no duplicate  
> components, and your logic isn't in the view. Most people (I think)  
> would put it in the controller, and that means it gets caught up in  
> with the logic for program flow, making the code harder to read,  
> write and maintain. So pull it out. Program flow to the left,  
> business logic to the right. You start with a default set of rules  
> with low priorities and override them with your rules by giving  
> them higher priorities. When your rules don't override the default,  
> the default rule wins and is used.
> Example default rules:
> 10 column name should substitute under bars with spaces
> 10 column name should be capitalized
> 10 IF column type is 'date' THEN display format is 'mm-dd-yy'
> Custom rules:
> 100 IF column name is 'nasa' THEN display 'NASA'
> 100 IF column name is 'describes' THEN display 'Description'
> 100 IF column type is date and user type is government THEN display  
> format is 'yyyy-mmm-dd'
> Result:
> column name 'easy_money' displays as 'Easy Money'
> column name 'nasa' displays 'NASA'
> column name 'describes' displays 'Description'
> user type is 'commercial' and column type is date, format is 'mm-dd- 
> yy'
> user type is 'government' and column type is date, format is 'yyyy- 
> mmm-dd'
> Advantages:
> Rules promote re-use of your basic components by allowing easier on- 
> the-fly customization.
> The scope side of the rules is very powerful. It allows you to  
> write rules that affect your whole app, a very particular  
> situation, or anything in between.
> Format is clear. Easy to read, write and maintain.
> Rule file could be re-used in applications with completely  
> different program flow, in effect, it becomes a re-usable component  
> for that organization or company.

This is called (logically enough) "rules-based programming" and there  
are entire languages written around it...e.g. Prolog.

Based on my limited experience of it, RBP is really, really hard.

The problem is that there is no clear control flow; the easiest way  
to think of it (for me) is from a quantum mechanical standpoint:   
every rule represents a probability of some particular outcome.  The  
rules engine takes all the rules, superimposes them into a unified  
waveform, and then collapses that waveform into a single outcome.   
How exactly you got that particular outcome is hard to track.  Which  
rules fired?  In what order?  For example, in your list above, you  
have 'easy_money' display as 'Easy Money' because the 'substitute  
underscore' and 'capitalize name' rules fired in that order.  If they  
had fired in the opposite order, then 'easy_money' would display as  
'Easy money'.  How do you ensure that these rules fire in the correct  
order?  Once you've done that, how do you insert a new rule into the  
chain at the correct point?  All of these questions are answerable,  
but they are not trivial.

If you want to get a taste of RBP, you might try playing around with  
the CLIPS expert system a bit... http://www.pst.com/clpbro.htm
Do a couple toy projects in it and then see if you still have the  
same enthusiasm for RBP.  If so, then by all means go ahead and write  
the necessary Engines/Models/Controllers for Catalyst...I think it  
would be a useful addition to the Catalyst menagerie.  But make sure  
you know what you're getting into, first.

> Sorry, at this point I'm looking for confirmation that Catalyst is  
> the right tool to attempt this with, and perhaps tips on how. You  
> are the second person to respond like this and that gives me  
> confidence I'm in the right place. Thank you.

You're welcome...glad to be of assisstance.  I hope some of this  
stuff is useful to you.


More information about the Catalyst mailing list