FAQ
This question may be slightly off-topic, as it stems from my use of Mason
in templates. Maybe I wouldn't have had this problem if I used something
else. But I intend to re-organize my existing app with Catalyst, in a way
that would allow me to continue using Mason, and I would like to know
proficient Catalyst users' opinion on what seems to be fairly general
design problem.

I looked at TT once; it scared me: I didn't like the way it looked and
found it more difficult to type than Mason. Let me assume for a moment
that the question is generic, and I will attempt to present it in abstract
terms.

Mason templates usually consist of two parts: the template itself and the
code providing values for its variables. Mason calls that code <%init>,
and the variables defined there can be interpolated into the template.
<%init> is not the only source of values for template variables, and it is
entirely optional. Variables can also be defined as template arguments; in
that case, their values will be supplied by the caller. But I am not
concerned with arguments. I am concerned with the variables whose values
are created through hard work, requiring possibly a lot of code and
interactions with various agents. In a complicated Mason template, that
usually happens in the <%init> section, which contains regular perl code.

Additionally, perl can be used across the template in a manner similar to
c preprocessing directives, providing means for conditional rendering and
for generation of repetitive patterns (tables, lists, &c.).

Even further, instead of inserting a value of a variable into the text,
a chunk of perl code can be called in-line and replaced with its return
value.

Alternatively, instead of calling perl code embedded into the template,
the template can insert another template.

I am conflicted about the best way to use templates even in the
non-catalyzed Mason, and I would like to resolve this conflict before I
move it to Catalyst. Here's an example. I can generate the same output
with these two template variants:

----- variant 1 ------

Dear Dr. <% $surname %>, ...

<%init>
my $surname = get_ldap_surname($uid);
</%init>
~~~~~~~~~~~~~~~~~~~~~~

----- variant 2 ------

Dear Dr. <& lib/ldap_surname.mason, uid => $User &> ...

~~~~~~~~~~~~~~~~~~~~~

The first variant does all the work within the same template, while the
second variant delegates that same work to another template, which can be
reused in other templates. I can't afford more than a trivial example, but
please imagine that a typical template can have dozens of variables and/or
sub-templates (known as components in Mason).

If I consistently follow the first variant, I end up with fairly
efficient, but extremely messy and unreadable code that provides
everything the template needs in one place. The template itself
tends to be complicated and incomprehensible.

However, if I delegate bits of work (as well as rendering) to various
sub-templates, I can achieve highly readable object-oriented structure,
with simple and easy-to-understand components -- in terms of appearance as
well as behavior -- at the cost of elevated redundancy and poor
performance. Many components end up going to the same place for copies of
the data, not knowing that their siblings have already been there and
queried the same table row, for example.

I wonder what is considered good design, vis-a-vis this dilemma, and what
is the Catalyst way of doing this. I understand, roughly, that my first
variant is more easily adaptable to Catalyst: take all that code in
<%init>, put it in one controller action and make it fill places in a
single template -- right? What should I do if I want to implement the
second variant, based on sub-templates, and what can I do to avoid
redundancy in controller actions, if I go that way? Is there a third way I
am not aware about?

Thanks,

--Gene

Search Discussions

  • Jay Shirley at Feb 4, 2009 at 8:59 pm

    On Wed, Feb 4, 2009 at 12:39 PM, Gene Selkov wrote:
    This question may be slightly off-topic, as it stems from my use of Mason in
    templates. Maybe I wouldn't have had this problem if I used something else.
    But I intend to re-organize my existing app with Catalyst, in a way that
    would allow me to continue using Mason, and I would like to know proficient
    Catalyst users' opinion on what seems to be fairly general design problem.

    I looked at TT once; it scared me: I didn't like the way it looked and found
    it more difficult to type than Mason. Let me assume for a moment that the
    question is generic, and I will attempt to present it in abstract terms.

    Mason templates usually consist of two parts: the template itself and the
    code providing values for its variables. Mason calls that code <%init>, and
    the variables defined there can be interpolated into the template. <%init>
    is not the only source of values for template variables, and it is entirely
    optional. Variables can also be defined as template arguments; in that case,
    their values will be supplied by the caller. But I am not concerned with
    arguments. I am concerned with the variables whose values are created
    through hard work, requiring possibly a lot of code and interactions with
    various agents. In a complicated Mason template, that usually happens in the
    <%init> section, which contains regular perl code.

    Additionally, perl can be used across the template in a manner similar to c
    preprocessing directives, providing means for conditional rendering and for
    generation of repetitive patterns (tables, lists, &c.).

    Even further, instead of inserting a value of a variable into the text, a
    chunk of perl code can be called in-line and replaced with its return value.

    Alternatively, instead of calling perl code embedded into the template, the
    template can insert another template.

    I am conflicted about the best way to use templates even in the
    non-catalyzed Mason, and I would like to resolve this conflict before I move
    it to Catalyst. Here's an example. I can generate the same output with these
    two template variants:

    ----- variant 1 ------

    Dear Dr. <% $surname %>, ...

    <%init>
    my $surname = get_ldap_surname($uid);
    </%init>
    ~~~~~~~~~~~~~~~~~~~~~~

    ----- variant 2 ------

    Dear Dr. <& lib/ldap_surname.mason, uid => $User &> ...

    ~~~~~~~~~~~~~~~~~~~~~

    The first variant does all the work within the same template, while the
    second variant delegates that same work to another template, which can be
    reused in other templates. I can't afford more than a trivial example, but
    please imagine that a typical template can have dozens of variables and/or
    sub-templates (known as components in Mason).

    If I consistently follow the first variant, I end up with fairly efficient,
    but extremely messy and unreadable code that provides everything the
    template needs in one place. The template itself tends to be complicated and
    incomprehensible.

    However, if I delegate bits of work (as well as rendering) to various
    sub-templates, I can achieve highly readable object-oriented structure, with
    simple and easy-to-understand components -- in terms of appearance as well
    as behavior -- at the cost of elevated redundancy and poor performance. Many
    components end up going to the same place for copies of the data, not
    knowing that their siblings have already been there and queried the same
    table row, for example.

    I wonder what is considered good design, vis-a-vis this dilemma, and what is
    the Catalyst way of doing this. I understand, roughly, that my first variant
    is more easily adaptable to Catalyst: take all that code in <%init>, put it
    in one controller action and make it fill places in a single template --
    right? What should I do if I want to implement the second variant, based on
    sub-templates, and what can I do to avoid redundancy in controller actions,
    if I go that way? Is there a third way I am not aware about?

    Thanks,

    --Gene
    The Catalyst method is quite simple, since it tries to adhere to the
    MVC design patterns.

    You would not set the variable in your templates, instead in the controller.

    sub action_name : Local {
    my ( $self, $c ) = @_;
    $c->stash->{surname} = $c->model('LDAP')->get_ldap_surname($id);
    }

    Then your template gets 'surname' and you can just do:

    Hello <% $surname %>!


    You can substitute out your model for an API compatible-version and
    your app works.
    You can substitute out your template language and your app still works.

    -J
  • Gene Selkov at Feb 4, 2009 at 11:25 pm

    On Wed, 4 Feb 2009, J. Shirley wrote:

    The Catalyst method is quite simple, since it tries to adhere to the
    MVC design patterns.

    You would not set the variable in your templates, instead in the controller.

    sub action_name : Local {
    my ( $self, $c ) = @_;
    $c->stash->{surname} = $c->model('LDAP')->get_ldap_surname($id);
    }

    Then your template gets 'surname' and you can just do:

    Hello <% $surname %>!
    I understood as much. The problem I am grappling with is the complexity of
    the web pages I have to present, with many different states and
    transitions. There is no way I can code for that with a single template.

    I am used to the idea that I can have a parent template (autohandler in
    Mason), which provides basic navigation and status display for the site;
    autohandler then invokes another template (a master template for that
    particual page's content) which itself uses various odd templates for
    recurrent elements in the page, and the change of state sometimes consists
    of replacing one little component of a sub-component with a component of a
    totally different nature (say, a name is replace with a list of names, or
    a blank display component is replaced with a message resulting from a
    prior action).

    Mason seems to be perfect for that; I have built a fairly complicated
    site, and succeeded in making it look simple for the user, but it is an
    ugly mess within. It's enough for me to spend a month without doing
    something with it that I forget how it works. Even worse, I have to pass
    the project on to someone, and before that happens, I want to achieve some
    transparent architecture that a stranger can navigate and understand.
    Having done some minor work in Catalyst on other projects, I have high
    expectations. But I don't have a clear vision of how such recursive
    templating will play out in Catalyst.

    If I understood the Catalyst model correctly, I will need some sort
    of nested views. Or am I complicating the problem beyond necessity? How
    else can I achieve mutable views with a hierachy of sub-views?


    Thanks,

    --Gene
  • Andrew Rodland at Feb 4, 2009 at 11:45 pm

    On Wednesday 04 February 2009 05:25:41 pm Gene Selkov wrote:
    On Wed, 4 Feb 2009, J. Shirley wrote:
    The Catalyst method is quite simple, since it tries to adhere to the
    MVC design patterns.

    You would not set the variable in your templates, instead in the
    controller.

    sub action_name : Local {
    my ( $self, $c ) = @_;
    $c->stash->{surname} = $c->model('LDAP')->get_ldap_surname($id);
    }

    Then your template gets 'surname' and you can just do:

    Hello <% $surname %>!
    I understood as much. The problem I am grappling with is the complexity of
    the web pages I have to present, with many different states and
    transitions. There is no way I can code for that with a single template.
    There's no "single template" implied. By default you're probably going to have
    a template per-action, though that's completely up to you, and TT provides
    tools such as WRAPPER, INCLUDE, and BLOCK to let you organize and reuse your
    code. I'd suggest spending a little time with the Template::Manual as well as
    having a look at some real-life Catalyst apps.

    Andrew
  • Bill Moseley at Feb 5, 2009 at 12:24 am

    On Wed, Feb 04, 2009 at 05:25:41PM -0600, Gene Selkov wrote:
    On Wed, 4 Feb 2009, J. Shirley wrote:

    The Catalyst method is quite simple, since it tries to adhere to the
    MVC design patterns.

    You would not set the variable in your templates, instead in the controller.

    sub action_name : Local {
    my ( $self, $c ) = @_;
    $c->stash->{surname} = $c->model('LDAP')->get_ldap_surname($id);
    }

    Then your template gets 'surname' and you can just do:

    Hello <% $surname %>!
    I understood as much. The problem I am grappling with is the complexity
    of the web pages I have to present, with many different states and
    transitions. There is no way I can code for that with a single template.
    Hopefully, not, but you can come close.
    I am used to the idea that I can have a parent template (autohandler in
    Mason), which provides basic navigation and status display for the site;
    autohandler then invokes another template (a master template for that
    particual page's content) which itself uses various odd templates for
    recurrent elements in the page, and the change of state sometimes
    consists of replacing one little component of a sub-component with a
    component of a totally different nature (say, a name is replace with a
    list of names, or a blank display component is replaced with a message
    resulting from a prior action).
    Maybe I've had too much TT Koolaid (try some, it's yummy), but my
    one-word answer would be "WRAPPER".

    My templates for each page typically only contain the markup to render
    the specific data for that request. Wrapper templates handle
    everything else (menus, layout, columns, banners, everything) is
    pulled in from nested wrapper templates. It's very rare that an
    include file is referenced more than once.


    Also, this makes me cringe a bit:

    Dear Dr. <% $surname %>!

    I would think you would hide that in an object (or hash if you like as
    TT doesn't care), and do:

    Dear Dr. [% user.surname %]

    so you don't spend all your coding time populating the stash in your
    controllers.


    --
    Bill Moseley
    moseley@hank.org
    Sent from my iMutt
  • Alexander Tamm at Feb 5, 2009 at 9:11 am

    I am used to the idea that I can have a parent template (autohandler in
    Mason), which provides basic navigation and status display for the site;
    autohandler then invokes another template (a master template for that
    particual page's content) which itself uses various odd templates for
    Using Mason with Catalyst does not imply that you have to lose your
    autohandlers. Actually, we've found the transition from Mason-only sites
    to Catalyst+Mason sites to work quite smoothly.
    Also, this makes me cringe a bit:

    Dear Dr. <% $surname %>!

    I would think you would hide that in an object (or hash if you like as
    TT doesn't care), and do:

    Dear Dr. [% user.surname %]

    so you don't spend all your coding time populating the stash in your
    controllers.
    You're actually comparing apples to oranges here. In your Mason-example
    you've put the surname into the stash, while your TT-example stashes the
    entire object.

    If you stash the object, your Mason-example would look like:

    Dear Dr. <% $user->surname() %>!

    which is pure perl, which "user.surname" most decidedly isn't. It's a
    matter of opininon, but I'd rather use perl than something else with a
    learning curve. Haven't tried out TT, so this is just my biased opinion.

    Alex
  • Malcolm at Feb 5, 2009 at 12:40 am

    On Wednesday 04 February 2009, Gene Selkov wrote:

    I understood as much. The problem I am grappling with is the complexity of
    the web pages I have to present, with many different states and
    transitions. There is no way I can code for that with a single template.

    I am used to the idea that I can have a parent template (autohandler in
    Mason), which provides basic navigation and status display for the site;
    Is there any reason for not using Mason? I've been using it with Catalyst
    without any problems.
  • Jay Shirley at Feb 5, 2009 at 1:22 am

    On Wed, Feb 4, 2009 at 4:40 PM, Malcolm wrote:
    On Wednesday 04 February 2009, Gene Selkov wrote:

    I understood as much. The problem I am grappling with is the complexity of
    the web pages I have to present, with many different states and
    transitions. There is no way I can code for that with a single template.

    I am used to the idea that I can have a parent template (autohandler in
    Mason), which provides basic navigation and status display for the site;
    Is there any reason for not using Mason? I've been using it with Catalyst
    without any problems.
    I think it is almost like using Emacs as a text editor, versus vi.
    Emacs users espouse the amazing features and customization, while vi
    users just sit down and write code because they're using an inferior
    editor (I use vi.)

    You already have a framework, so why use Mason?

    Mason's dhandlers and autohandlers are some of its better features,
    but they're not really designed to work in conjunction with Catalyst
    (you can still use them, but... probably more work than you would get
    unless you had specific goals to reach.)

    If you simply think of templating languages, I find that Mason's
    distinguishing advantages disappear if you -only- use is as a
    templating language.

    So, it boils down to: Do you know Mason well enough to get the most
    out of it, while still designing your Catalyst application concisely
    and in an abstract fashion? If not, probably best to use TT, which is
    simpler and offers some really neat features that seem to favor better
    Catalyst applications (WRAPPER, most notably).

    Hope that helps, and I can avoid any flamewars :)
  • Felix Antonius Wilhelm Ostmann at Feb 5, 2009 at 8:58 am

    J. Shirley schrieb:
    On Wed, Feb 4, 2009 at 4:40 PM, Malcolm
    wrote:
    On Wednesday 04 February 2009, Gene Selkov wrote:

    I understood as much. The problem I am grappling with is the complexity of
    the web pages I have to present, with many different states and
    transitions. There is no way I can code for that with a single template.

    I am used to the idea that I can have a parent template (autohandler in
    Mason), which provides basic navigation and status display for the site;
    Is there any reason for not using Mason? I've been using it with Catalyst
    without any problems.
    I think it is almost like using Emacs as a text editor, versus vi.
    Emacs users espouse the amazing features and customization, while vi
    users just sit down and write code because they're using an inferior
    editor (I use vi.)

    You already have a framework, so why use Mason?

    Mason's dhandlers and autohandlers are some of its better features,
    but they're not really designed to work in conjunction with Catalyst
    (you can still use them, but... probably more work than you would get
    unless you had specific goals to reach.)

    If you simply think of templating languages, I find that Mason's
    distinguishing advantages disappear if you -only- use is as a
    templating language.

    So, it boils down to: Do you know Mason well enough to get the most
    out of it, while still designing your Catalyst application concisely
    and in an abstract fashion? If not, probably best to use TT, which is
    simpler and offers some really neat features that seem to favor better
    Catalyst applications (WRAPPER, most notably).

    Hope that helps, and I can avoid any flamewars :)
    one simple question: i love the autohandlers and use a liddle hack to
    implement it to TT ... is that not a good feature? I extend the
    navigation in the autohandles or setting some defaults for all templates
    in a directory. Perhaps there is already a official Plugin for TT i dont
    know?

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Mit freundlichen Gr??en

    Felix Antonius Wilhelm Ostmann
    --------------------------------------------------
    Websuche Search Technology GmbH & Co. KG
    Martinistra?e 3 - D-49080 Osnabr?ck - Germany
    Tel.: +49 541 40666-0 - Fax: +49 541 40666-22
    Email: info@websuche.de - Website: www.websuche.de
    --------------------------------------------------
    AG Osnabr?ck - HRA 200252 - Ust-Ident: DE814737310
    Komplement?rin: Websuche Search Technology
    Verwaltungs GmbH - AG Osnabr?ck - HRB 200359
    Gesch?ftsf?hrer: Diplom Kaufmann Martin Steinkamp
    --------------------------------------------------
  • Aristotle Pagaltzis at Feb 15, 2009 at 10:05 am

    * Gene Selkov [2009-02-05 00:30]:
    I understood as much. The problem I am grappling with is the
    complexity of the web pages I have to present, with many
    different states and transitions. There is no way I can code
    for that with a single template.
    Use Chained dispatch in Catalyst to accumulate all the necessary
    data in the stash, go to a specific template, and then implicitly
    use wrapper templates to build out the surrounding bits.

    Mason gives you tools to build a page outside-in (going from
    generic to specific parts). In Catalyst you use Chained dispatch
    for that. Your templates should build up the page inside-out, and
    they should not be calling *any* methods in your model. As far as
    possible they should only be using stashed variable values. If
    you call any methods they should only be helper methods from the
    context like `uri_for`.

    There should be no application logic in the templates, only
    display logic. We all know that, right? Well, selecting which
    component template or which block to use for rendering is more
    often application logic than display logic. You should be very
    suspicious every time you put a conditional in your templates.
    I?m not saying display logic has no conditionals, there are
    plenty, but stare long and hard at your boolean expressions.
    Should they really be calculated in the template or should they
    be passed in through the controller via the stash?

    Think about coupling; consider how much infrastructure you would
    have to mock up in order to unittest a template. If you need the
    whole app set up and running for the template to work, you?re
    doing it wrong. (I?m not perfect at this by a long shot yet.
    Short-sighted pragmatism is easier than forethought, and much
    that is claimed to be forethought is really empty dogmatism.)

    Basically, to design your Catalyst app properly you need to
    disregard about 90% of Mason.

    Imagine it like zoom-in/zoom-out sequence. Chained dispatch zooms
    in on the most specific part of the page, then wrapper templates
    zoom out to the full picture.

    Regards,
    --
    Aristotle Pagaltzis // <http://plasmasturm.org/>
  • Bill Moseley at Feb 22, 2009 at 5:15 pm

    On Sun, Feb 15, 2009 at 11:05:20AM +0100, Aristotle Pagaltzis wrote:
    Your templates should build up the page inside-out, and
    they should not be calling *any* methods in your model. As far as
    possible they should only be using stashed variable values. If
    you call any methods they should only be helper methods from the
    context like `uri_for`.
    Hope that quote is not out of context.

    So are you saying you should never do this?:

    Hello [% user.first_name | html %]

    That instead you should have in your controller:

    $c->stash->{first_name} = $user->first_name;

    and then:

    Hello [% first_name | html %]

    Maybe "first_name" is considered an attribute instead of a method, but
    I do this:

    From: [% user.full_email %]

    Which the full_email method uses first_name, last_name, and email
    attributes.

    And a wrapper template might want to do this:

    [% buddies = user.buddies; PROCESS display_buddies IF buddies %]

    Perhaps that technically belongs in the (chained) controller, but my
    controllers would quickly become a tangled mess if I had to call every
    method in the controller for every view possibility.

    Yes, perhaps TT provides too much power (to abuse) but that kind of
    usage really helps keep the controllers clean. The controller
    converts the request for a user into a user object, but it's up to the
    view to decide to display the user's first name only or their full
    name, IMO.

    --
    Bill Moseley
    moseley@hank.org
    Sent from my iMutt
  • Aristotle Pagaltzis at Feb 23, 2009 at 10:05 am

    * Bill Moseley [2009-02-22 18:20]:
    On Sun, Feb 15, 2009 at 11:05:20AM +0100, Aristotle Pagaltzis wrote:
    Your templates should build up the page inside-out, and they
    should not be calling *any* methods in your model. As far as
    possible they should only be using stashed variable values.
    If you call any methods they should only be helper methods
    from the context like `uri_for`.
    Hope that quote is not out of context.

    So are you saying you should never do this?:

    Hello [% user.first_name | html %]

    That instead you should have in your controller:

    $c->stash->{first_name} = $user->first_name;
    Ack, no. What I said really didn?t make much sense, although what
    I actually meant does. Now that you pointed out the inconsistency
    I?m not sure how to put my point as a simple rule of thumb.

    No, `user.first_name` in the template is perfectly acceptable.
    Calling methods to retrieve values from stashed objects is
    perfectly reasonable.

    What I meant is that the templates should not go fetching data
    from the the model by themselves, nor of course should they be
    making insert/delete calls against the model. They should also
    avoid calling any methods on the context object, as far as
    possible. Frequent exceptions are `c.uri_for` and `c.req`?s
    various methods.

    The point is: if rendering the template requires the entire Cat
    app to be set up and running, you are probably relying on global
    state, and the template will be hard to test in isolation and
    hard to reuse. Ideally it would be no harder to render from a
    10-liner than from the Cat app.

    Regards,
    --
    Aristotle Pagaltzis // <http://plasmasturm.org/>

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedFeb 4, '09 at 8:39p
activeFeb 23, '09 at 10:05a
posts12
users8
websitecatalystframework.org
irc#catalyst

People

Translate

site design / logo © 2021 Grokbase