Ok, thanks to you all and this great discussion I want to try to make
our current project into an MVC-style app, so what now? This MVC
discussion could not have come at a better time - our little app is all
grown up now and needs a real architecture. I have read the MVC threads
in depth now, and I have questions.
WHERE WE ARE NOW
--------------------------
We have a multiuser application that has about oh, I dunno, 100
different "screens" to the interface. They can be roughly divided into
the following areas - status, admin, registration, reports, and graphs.
Most of the actions involve either retrieving data from a database or
processing a form and inserting into a database (in other words, it's a
very typical web application). This application started as a CGI
script. For performance reasons, we installed mod_perl and use
Apache::Registry to run it now. It's pretty much still a dumb CGI
script with a mod_perl wrapper, but I did develop a couple of modules to
do user authentication with AuthCookie-based solutions and tied that
into Apache::Session for state maintenance between requests. The CGI
script has grown to accomodate these ~ 100 actions and is now basically
a 4,000 line if statement. The script decides which request to do based
on a target= parameter passed in (in other words, target=summary or
target=doctoractivity, etc...). For sanity's sake, many months ago, we
switched to HTML::Template (our view) to define our screens, which has
worked well to date. On the back end we have PostgreSQL with a healthy
sized schema of around 150 tables or so that has ~ 350 megs of data and
on the order of 500,000 transactions a day (lots of data turnover, some
tables get UPDATEd so frequently as to have 100% data turnover within 15
minutes). Anyways, back to the perl part....
Basic code structure:
[snip]
my $dbh = DBI->connect( $r->dir_config('RMSDBI_DSN') ,
$r->dir_config('RMSDBI_user') , $r->dir_config('RMSDBI_password') );
# giant if statement - closest thing I have to a controller, I suppose
if ($target = 'summary') {
my $tmpl = getTemplate('summary');
doSummary($dbh,$tmpl);
print header . $tmpl->output();
} elsif ($target = 'doctoractivity') {
my $tmpl = getTemplate('doctoractivity');
doDoctorActivity($dbh,$tmpl);
print header . $tmpl->output();
} elsif .......
[snip]
# lots of subs basically one per target, closest thing I have to a
model, I suppose
sub doSummary {
($dbh, $tmpl) = shift;
$sth = $dbh->prepare("SQL STATEMENT HARD-CODED HERE");
# process result set into hashes and arrays of hashes such as @summary
that HTML::Template wants
[snip]
$tmpl->param(summary => @summary);
}
sub doDoctorActivity {
($dbh, $tmpl) = shift;
$sth = $dbh->prepare("SQL STATEMENT HARD-CODED HERE");
# process result set into hashes and arrays of hashes such as @summary
that HTML::Template wants
[snip]
$tmpl->param(summary => @summary);
}
etc....
This basic pattern repeated ad infinitum. It's grown way out of
control, is a pain to work with, and just feels wrong, very wrong. :-)
To be fair, it grew very fast and it was all we (by we I mean the two
of us that were this entire dept. back then) could do to keep up with
the feature requests, let alone worry about proper architecting of the
software. We're paying for it now, of course.
WHERE WE WANT TO BE
------------------------------
I would like to introduce some semblance of organisation, sanity,
maintainability, separation of logic, etc.... to this project. In other
words, MVC would be a good fit.
Some of the concrete, basic questions I have are:
1. Is there one Controller or many? Should I have one for each main
area of my site? /myapp/admin/ goes to an Admin Controller,
/myapp/reports to another controller, etc...
2. Does the first part of my code above even remotely resemble a
Controller? I mean, it takes the input, calls essentially a 'model'
object (but passing it the view object, nice, eh? =), but then seems to
break the model nicely by doing things like printing out the HTML from
the Controller, etc...
3. How do you prevent a Controller from just becoming another big if
statement, or is this their purpose in life?
4. In the case of a form, what perl structure is used to pass the data
into the model?
5. Do you create an actual class for each form?
6. Do you need to create objects at all? Is OO a prerequisite to MVC?
6.5. (thought of while proofreading :-) Is the statement "there is one
set of controllers for each defined view" correct? In other words, if
we someday want to output the "reports" section of the site as Excel
spreadsheets in addition to HTML, would we define a new set of
controllers or how would that work?
Now onto the model, I think I have a little better grasp of the model
compared to the controller, but I have questions...
7a. Is it insane to leave my SQL hard-coded in there? The queries
don't change all that much, and it's nice to have the query in the same
place as the processing of the result set so you can kind of "see" the
structure of the result set better. This helps our less-experienced
developers.
7b. Should I really investigate real object persistence like discussed
at the POOP site (I have used Tangram with some success on tiny side
projects but nothing remotely this size)? Begging the question, should
I really be migrating to more of an OO style of programming?
7c. Is there some middle ground that would consolidate our database
query code but not be a full abstraction layer which I simply think is
overkill for what we need and for our current talents?
7d. Or do I -really- want an object/structure that represents every
result set we need to get back from the database?
8a. What structures are used to pass back the data from the model
through the controller to the view?
8b. The view is expecting HTML::Template style hashes and arrays, do I
form these in the model (which seems to be too much knowledge of the
view while still in the model) or does the controller convert it to the
structures expected by the HTML::Template view?
8c. The model is getting DBI record sets from the db. I have to put
this data into -something-, why not the exact format that HTML::Template
view needs rather than process it twice?
9. Does the bottom half of my code resemble a model layer at all?
Would each of those subs typically become a separate mod_perl module,
or all live in a library of some sort, etc...begs the question again, is
this all really supposed to be OO and I'm supposed to have a bunch of
MyApp::Model::DoctorActivity modules that the controller 'use's?
And finally, the view. This layer seems to be the 'simplest' of them to
me since it's really limited in what it can do programmatically (for a
good reason, I know).
10. We have situations like "if you are an admin show all three menu
options, if you are regular joe user, you get one option. With
HTML::Template now we handle this like so...getTemplate sets a number of
standard parameters on each and every template. Kind of publishing the
user's session to the template for the template designers to use. So,
templates often look like this:
menu option #1
menu option #2
<tmpl_if admin_user>
Super secret option only admin can see
</tmpl_if>
How does this fit into the MVC model? Is this an appropriate use of the
view? Doesn't "feel" like it is.
These are just some of the many, many questions I have on this topic. I
just can't quite get my head around it. I've got a small window of
opportunity to introduce some of these concepts into our application but
I need to be able to understand them a little better. Some
stripped-down code samples would be nice (sometimes it's hard to
decipher real code examples because of all the little quirks and
intricacies of their specific situation clouding the raw demonstration
of MVC and how it works), but any feedback at all to my questions would
be met with wild enthusiasm. =) Thank you very much and I'm looking
forward to your feedback.
-Fran