You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Andy Wardley <ab...@andywardley.com> on 2002/06/05 15:01:28 UTC
Separating Aspects (Re: separating C from V in MVC)
Continuing from the thread on the modperl mailing list:
On Sun, Jun 02, 2002 at 05:04:01PM -0400, Sam Tregar wrote:
> > I don't think the standard HTML::Template has support for formatting
> > numbers, dates, etc.
>
> And thank the sweet lord it doesn't! HTML::Template is a "do one thing
> and do it well" module. If you want routines for formatting "numbers,
> dates, etc." then CPAN has just what you need.
I (mostly) consider formatting of numbers, etc., to be a presentation
issue, not a programming one. That's why TT supports this kind of
thing in the templates (or in the code if you prefer).
Of course, the fact that it's a module/object is entirely hidden. TT
abstracts the front end templates from the backend implementation, so
that the HTML designers don't have to know if a data structure is
implemented as a hash, object, or subroutine, it just does the right
thing.
This allows the developers to worry about implementing a back-end system
in the best way possible and the front-end designers to just use it.
> HTML::Template::Expr may present a solution to this particular desire,
> although it isn't one I've come across. How often are HTML designers
> fiddling with numeric formats? Are they really HTML designers if they can
> deal with, say, a printf-style format string?
In TT, you would usually pre-declare a particular format in a config
file, pre-processed templates, or some other "global" style document.
e.g.
[% USE money = format('%.02f') %]
In your main page templates you would do something like this:
[% money(order.total) %]
Then you can change the money format in one place and your designers
don't have to worry about sprintf formats.
If you prefer to write your own formatting subroutine you can do it
like so:
my $vars = {
money => sub { return sprintf("%.02f", shift) };
order => {
total => 22.95,
}
};
$template->process($file, $vars) || die $template->error();
Guess what? You don't have to change any of the templates. They still
use the same syntax:
[% money(order.total) %]
This is abstraction. Not to be confused with MVC which is one particular
architecture well suited to GUI applications. Blindly applying MVC without
understanding the real issues (abstraction of front/back ends, separation of
concerns, don't repeat yourself, etc.) is likely to build a system which is
highly fragmented. Maintenance becomes harder because everything is split
up into many different pieces and it becomes difficult to see the wood for
the trees.
Aspect oriented programming teaches us that as soon as you decompose a
system into a particular structure you inevitably fragments aspects which
cut across the system. I have seen this in close and painful detail over the
past few months while helping to build a very strictly partitioned MVC
architecture system for Fotango(.com). We're using TT for presentation,
Openframe for the application pipeline/dispatch and a custom data backend
called Vx.
Despite our best intentions, this web site doesn't neatly fall into
clearly defined chunks of model, application and view. Well, actually,
those parts do split down quite nicely. But then you look at localisation,
for example, and we find there is localisation required in the data backend,
localisation required in the applications and localisation required in the
templates. Thus, localisation is an aspect which cuts across the system.
By building a strict MVC we've fragmented localisation and have to trawl
through hundreds of different files to localise the site.
Another example is that different countries running their localised versions
of this web site will want to change the URLs. Where the english version
uses /product/shirt/red.html, the french version should instead be
/produit/chemise/rouge.html, for example. Again, these URLs are (currently)
embedded throughout the system and making any changes to them is a painful
process involved many files spread across the M, the V and the C. In an
ideal world, English and French would just be different views of the same
model. Alas, it's never that easy because the chances are that parts of
the model and parts of the controllers will also need changing.
See, the problem is that MVC is just one particular decomposition. It's
generally a good one because application, data and presentation are typically
the three biggest aspects that you want to separate. However, it doesn't
take into account any of the other dozen or so aspects that you might want
to model in your system. Nowhere in MVC or any other Design Pattern does
it tell you to define all your URLs in one place in case you ever need to
change them en masse. You have to think of that all by yourself. MVC is
no substitute for thinking and it often encourages the opposite, lulling
you into a false sense of security by the fact that you think you're doing
the Right Thing.
I've seen far too many example of people who didn't pass objects into their
templates, didn't embed Perl code, or didn't do this or that because they
thought that it might violate the MVC principal. The end result was that
they jumped through hoops and made the system more complex than it needed
to be for the sake of "purity". Sometimes it really is a good idea to embed
Perl code in templates. Not often, no, but if the Perl code is performing a
*presentation* function and not an *application* function, and as long as
it's defined in one convenient place so that you can get your hands on it,
then it can be the Right Thing to do.
Now I'm not suggesting that embedding Perl is a good idea, per se, but I'm
saying that the smart people know when and how to break the rules.
Separation of concerns is the goal, and MVC is one particular approach that
can help you to acheive that.
To address the problem in the fotango site, I'm borrowing a technique
from AOP called aspect weaving. I currently define 12, yes 12 separate
models (either as Perl code or XML files) each of which defines one aspect
of the site. One defines the abstract site/section/page structure, another
defines the URL -> page mapping, another defines page titles, short names,
descriptions and anything other information about a page (e.g. not content)
that might need to be localised. Another aspect defines pure style elements
(e.g. colours, fonts, CSS styles, etc), another defines flags and other
data for building the site interface, another defines database connection
and other backend data values. And so on.
Each of these elements can be "subclassed" to change one particular
aspect of the site. A simple bit of code weaves the 12 different aspects
together into one coherent data model which is the definitive reference
model for everything in the site.
This is all still in development as I type (or rather it's not in development
because I stopped to type this :-). Assuming that it matures well and
proves that it does what it says on the tin, I'll be releasing it as some
kind of general tool for the modelling and building of web sites. It will
be entirely generic so you will be able to use it equally well with TT as
with HTML::Template.
So to summarise a long, rambling post, MVC often isn't the answer by itself
and sometimes it's not the answer at all. AOP might help, but only until we
reach the next problem horizon.
Five years ago I was saying "Object Oriented Programming isn't the answer
by itself and sometimes it's not the answer at all". Any idiot can write
an object, but we all know that it takes a great deal more to design a
coherent OO application.
In five years time, I'll probably be saying "Aspect Oriented Programming
isn't the answer by itself..." :-)
Or, more generally:
[% silver.bullet %] isn't the answer by itself...
A
Re: [Templates] Re: Separating Aspects (Re: separating C from V in MVC)
Posted by Ed <en...@fldna.net>.
On Fri, Jun 07, 2002 at 09:14:25AM +0100, Tony Bowden wrote:
> On Thu, Jun 06, 2002 at 05:08:56PM -0400, Sam Tregar wrote:
> > > Suppose you have a model object for a concert which includes a date. On
> > > one page, the designers want to dipslay the date in a verbose way with
> > > the month spelled out, but on another they want it abbreviated and fixed
> > > length so that dates line up nicely. Would you put that formatting in
> > > the controller?
> > In the script:
> >
> > $template->param(long_date => $long_date,
> > short_date => $short_date);
> > In the template:
> >
> > The long date: <tmpl_var long_date> <br>
> > The short date: <tmpl_var short_date>
>
> Can I vote for "yick" on this?
>
> A designer should never have to come to a programmer just to change the
> formatting of a date.
>
> I'm a huge fan of passing Date::Simple objects, which can then take a
> strftime format string:
>
> [% date.format("%d %b %y") %]
> [% date.format("%Y-%m-%d") %]
>
> Tony
>
xmlns:date="http://exslt.org/dates-and-times" wins for me.
date:date-time()
date:date()
date:time()
date:month-name()
... etc
xslt solutions win for me because it its supported (or seems to be)
by many major languages, and applications.
xslt stylesheets can be processed, reused and shared with my c,perl,
java,javascript, ruby, mozilla, ieexplorer ... kde apps, gnome apps
... etc
Imagine having your templates and data supported and interoperable ...
Aren't we trying to rid the world of proprietary (only works here) things?
Ed .... (an axkit lover)
Re: [Templates] Re: Separating Aspects (Re: separating C from V in MVC)
Posted by Tony Bowden <to...@kasei.com>.
On Sat, Jun 08, 2002 at 08:51:48AM +0800, Gunther Birznieks wrote:
> >I'm a huge fan of passing Date::Simple objects, which can then take a
> >strftime format string:
> > [% date.format("%d %b %y") %]
> > [% date.format("%Y-%m-%d") %]
> And the latter does not require a programmer?
Of course not. It just requires someone who can read a simple chart of
strftime formats. I've never worked with a designer who hasn't been able
to understand the DESCRIPTION section of, for example,
http://unixhelp.ed.ac.uk/CGI/man-cgi?strftime+3
It wouldn't be difficult to make up a more "designer friendly" version
of it if it was really needed.
Tony
Re: [Templates] Re: Separating Aspects (Re: separating C from
V in MVC)
Posted by Gunther Birznieks <gu...@extropia.com>.
At 04:14 PM 6/7/2002, Tony Bowden wrote:
>On Thu, Jun 06, 2002 at 05:08:56PM -0400, Sam Tregar wrote:
> > > Suppose you have a model object for a concert which includes a date. On
> > > one page, the designers want to dipslay the date in a verbose way with
> > > the month spelled out, but on another they want it abbreviated and fixed
> > > length so that dates line up nicely. Would you put that formatting in
> > > the controller?
> > In the script:
> >
> > $template->param(long_date => $long_date,
> > short_date => $short_date);
> > In the template:
> >
> > The long date: <tmpl_var long_date> <br>
> > The short date: <tmpl_var short_date>
>
>Can I vote for "yick" on this?
>
>A designer should never have to come to a programmer just to change the
>formatting of a date.
>
>I'm a huge fan of passing Date::Simple objects, which can then take a
>strftime format string:
>
> [% date.format("%d %b %y") %]
> [% date.format("%Y-%m-%d") %]
And the latter does not require a programmer?
Re: [Templates] Re: Separating Aspects (Re: separating C from V in
MVC)
Posted by Sam Tregar <sa...@tregar.com>.
On Fri, 7 Jun 2002, Tony Bowden wrote:
> > $template->param(long_date => $long_date,
> > short_date => $short_date);
> > In the template:
> >
> > The long date: <tmpl_var long_date> <br>
> > The short date: <tmpl_var short_date>
>
> Can I vote for "yick" on this?
Sure. That's what's great about Perl - there's always more than one way
to do it. If you don't like HTML::Template then don't use it.
-sam
Re: [Templates] Re: Separating Aspects (Re: separating C from V in MVC)
Posted by Tony Bowden <to...@kasei.com>.
On Thu, Jun 06, 2002 at 05:08:56PM -0400, Sam Tregar wrote:
> > Suppose you have a model object for a concert which includes a date. On
> > one page, the designers want to dipslay the date in a verbose way with
> > the month spelled out, but on another they want it abbreviated and fixed
> > length so that dates line up nicely. Would you put that formatting in
> > the controller?
> In the script:
>
> $template->param(long_date => $long_date,
> short_date => $short_date);
> In the template:
>
> The long date: <tmpl_var long_date> <br>
> The short date: <tmpl_var short_date>
Can I vote for "yick" on this?
A designer should never have to come to a programmer just to change the
formatting of a date.
I'm a huge fan of passing Date::Simple objects, which can then take a
strftime format string:
[% date.format("%d %b %y") %]
[% date.format("%Y-%m-%d") %]
Tony
Re: Separating Aspects (Re: separating C from V in MVC)
Posted by Sam Tregar <sa...@tregar.com>.
On Thu, 6 Jun 2002, Perrin Harkins wrote:
> For posterity, and possible inclusion in the next rev of the templating
> tutorial, how would you recommend people handle this sort of situation
> without using HTML::Template::Expr?
>
> Suppose you have a model object for a concert which includes a date. On
> one page, the designers want to dipslay the date in a verbose way with
> the month spelled out, but on another they want it abbreviated and fixed
> length so that dates line up nicely. Would you put that formatting in
> the controller?
In the script:
$template->param(long_date => $long_date,
short_date => $short_date);
In the template:
The long date: <tmpl_var long_date> <br>
The short date: <tmpl_var short_date>
> What if you had a model object that generates a list of these concerts,
> and on a certain page the designers want to show it in two columns.
> Would you split it into two arrays in the controller?
I'm not sure I understand what you mean. You're asking about how to flow
a list between two columns? With vanilla HTML::Template that would
requrie a small amount of work in the script. Either there would need to
be a column_break variable thrown in at the appropriate place or two
separate loops. I think I would prefer the former. In the template that
would look like:
<table><tr>
<tmpl_loop concerts>
<tmpl_if column_break> </tr><tr> </tmpl_if>
<td> <tmpl_var long_date> </td>
</tmpl_loop>
</tr></table>
In the script you'd just set the column_break in the appropriate row (or
rows for a multi-column layout).
Is that a point in favor of scripting in the templates? Perhaps. Of
course by limiting the power of template syntax I've made some things more
difficult. If simple things should be simple and hard things should be
possible then not everything can be simple!
-sam
Re: Separating Aspects (Re: separating C from V in MVC)
Posted by Perrin Harkins <pe...@elem.com>.
Sam Tregar wrote:
> Now, I don't use HTML::Template::Expr. I think it's generally not such a
> good idea. But it's there if you want it...
For posterity, and possible inclusion in the next rev of the templating
tutorial, how would you recommend people handle this sort of situation
without using HTML::Template::Expr?
Suppose you have a model object for a concert which includes a date. On
one page, the designers want to dipslay the date in a verbose way with
the month spelled out, but on another they want it abbreviated and fixed
length so that dates line up nicely. Would you put that formatting in
the controller?
What if you had a model object that generates a list of these concerts,
and on a certain page the designers want to show it in two columns.
Would you split it into two arrays in the controller?
- Perrin
Re: Separating Aspects (Re: separating C from V in MVC)
Posted by Sam Tregar <sa...@tregar.com>.
On Wed, 5 Jun 2002, Andy Wardley wrote:
> In TT, you would usually pre-declare a particular format in a config
> file, pre-processed templates, or some other "global" style document.
> e.g.
>
> [% USE money = format('%.02f') %]
>
> In your main page templates you would do something like this:
>
> [% money(order.total) %]
>
> Then you can change the money format in one place and your designers
> don't have to worry about sprintf formats.
In HTML::Template::Expr:
sub money { sprintf "%.02f", $_[0] }
HTML::Template::Expr->register_function(money => \&money);
Then in the template:
<tmpl_var expr="money(order_total)">
Now, I don't use HTML::Template::Expr. I think it's generally not such a
good idea. But it's there if you want it...
> See, the problem is that MVC is just one particular decomposition. It's
> generally a good one because application, data and presentation are typically
> the three biggest aspects that you want to separate. However, it doesn't
> take into account any of the other dozen or so aspects that you might want
> to model in your system. Nowhere in MVC or any other Design Pattern does
> it tell you to define all your URLs in one place in case you ever need to
> change them en masse. You have to think of that all by yourself. MVC is
> no substitute for thinking
Oh, absolutely. MVC is just a framework, and it only addresses a subset
of the problems in any large system. I think that's actually a strength.
I would be deeply suspicious of any paradigm that claimed to solve ALL my
problems. I prefer small, simple (tools|paradigms) that do one thing and
do it well.
> I've seen far too many example of people who didn't pass objects into their
> templates, didn't embed Perl code, or didn't do this or that because they
> thought that it might violate the MVC principal.
Here!
> The end result was that they jumped through hoops and made the system
> more complex than it needed to be for the sake of "purity".
It was? I don't think this is the only result. It might be that these
people you've observed were just the hoop-jumping, complexifying types.
I've built quite a number of large systems without embedded Perl and object
variables without excessive hoop-jumping.
Here's my theory: the best usage of most templating systems are virtually
indistinguishable and all result in reasonably maintainable systems.
However, the bad usage of some templating systems is much worse than
others. Also, the general usage of a templating system, even by otherwise
bright people, tends more towards the bad than the good.
Thus my solution: a templating system that simply will not allow you to
put anything significantly complicated in the template. You can't. If
you want complexity you'll just have to put it in the code, where it
belongs. That's HTML::Template in a nutshell.
> [% silver.bullet %] isn't the answer by itself...
Here here. Neither is <tmpl_var silver_bullet> but I'd rather get shot
with mine than yours!
-sam