in reply to Template modules, logic, and SOC

So here I present to you Moyer's Eleventh Rule of Templating Languages. "Any sufficiently complicated templating language contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Perl"
Very true. Which is why I prefer to put plain perl/ruby/whatever code in the templates ala PHP/JSP over, well, any template system I've used.

That's not to say that template systems are the best way to create dynamic apps. I've been messing with Common Lisp + cl-who which works more or less like CGI's HTML generation modules, but with Lisp's syntax. So far it's a joy to use: you can get as detailed as possible and the code is a both smaller and easier to read than the equivalent HTML and you get all of Lisp's power (including macros) in the bargain.

In the end, I'm pretty sure the "separate code from presentation" guys have it all wrong. Just take a look at the enormous amount of code that gets generated when you want to use JSP's taglibs, for instance.

You may want to separate the view from the lower level / model code, but there's no good reason I can see to even try to "keep the code out of the view".

Replies are listed 'Best First'.
Re^2: Template modules, logic, and SOC
by kyle (Abbot) on Jan 23, 2008 at 19:34 UTC

    ...there's no good reason I can see to even try to "keep the code out of the view".

    I think the usual reason is, "so they can be worked on separately." This is especially nice if you have dedicated designers doing HTML and CSS distinct from the people who work on Perl and SQL and JavaScript (oh my), but it's also nice for an individual who wants to be able to mutate things independently.

      Well, if you have an Object-Relational system like DBIx::Class, you should/will usually put all (or at least most) of the SQL needed in the model classes anyway. I very much prefer to make the model easy enough to use so that I can use it directly in the view.

      I have had doubts about the separation between front-end and back-end programmers for a long time. Especially for applications. JSP/PHP like templating works OK for things like CMS templates (provided you the model API is stable enough over updates) but they get seriously annoying when you're writing reusable widgets or heavily interactive applications.

      Anyway trying to keep a template system flexible enough to actually work, and still rigid enough that you can get any inexperienced HTML guy mess with it without potential consequences is futile. There will never be such a system. In the end the programmers will take your straight-forward page-by-page design and cut it up and break it apart anyway, just to get consistency.

Re^2: Template modules, logic, and SOC
by arbingersys (Pilgrim) on Jan 23, 2008 at 19:45 UTC

    I should mention how I came up with the name Template::Recall for the module. Perrin Harkins dubbed Mason (PHP/JSP fit this bill) styled template systems as "callback" and TT2, HTML::Template systems as "pipeline".

    Template::Recall really works like the "callback" model, except in reverse. Perl isn't inserted between sections of the code and "called back" to by the template; instead, the template is (effectively) inserted between blocks of Perl code, and it is "called back" to. This is why it only requires substitution, and no logic.

      Sorry, this is just another pipeline module in my opinion. Callback means that the template is in charge of the program flow. In your case, the perl code calls the template and passes in data, thus pipeline.

      Frankly, there's nothing new under the sun with templating. What you've done is pretty much identical to several modules that have been on CPAN for years, like CGI::FastTemplate. In fact, there's no reason you can't use HTML::Template, Text::Template, TT2, etc. in the way you're showing here.

      I think you'll find that substitutions are really not enough. You at least need conditionals, because some things are too small to make a whole separate template and put the conditional in the perl code. And loops make for much more readable HTML code, which is one of the major reasons to use a template. And whitespace control is important. And formatting all of your numbers and dates in perl before you call the template gets ugly when you start needing the same data in multiple formats. And putting all this into your perl code means any significant HTML change has to be done by a perl programmer, which is fine for some dev teams and not for others.

      My advice is to get over your idea that the view shouldn't contain logic. It's supposed to contain logic -- logic about how to display the data. It may sometimes be convenient to write the view logic in perl, and sometimes in a view-specific shorthand like TT2.

        Frankly, there's nothing new under the sun with templating. What you've done is pretty much identical to several modules that have been on CPAN for years, like CGI::FastTemplate.

        Actually, I was aware that CGI::FastTemplate existed, and it was the only one I could see that worked "identically" to Template::Recall when I submitted to CPAN. It just seemed that CGI::FastTemplate existed in the wrong namespace for a general purpose (perhaps non- web-based) template system, and besides, it hasn't been updated since 1999.

        In fact, there's no reason you can't use HTML::Template, Text::Template, TT2, etc. in the way you're showing here

        Sure. All template systems essentially share the same goal. But there is one definite benefit that I can think of for using Template::Recall over these, at least for simple loops. I mention this in my introduction, regarding an output of row data to a simple table like that in my writeup. Using a pipeline system, you have to iterate over the data twice to output the table. Once when generating the array of hashes, and then again as (say) HTML::Template renders it against <TMPL_LOOP> on the call to print $template->output();. With Template::Recall (and Mason/PHP/JSP), there is no such cost, because you can output the row as soon as you receive it. Template::Recall just does it through a method call, which in my opinion, is cleaner.

        My advice is to get over your idea that the view shouldn't contain logic. It's supposed to contain logic -- logic about how to display the data. It may sometimes be convenient to write the view logic in perl, and sometimes in a view-specific shorthand like TT2.

        Actually, I've never held the opinion that the view should contain no logic. Substitution in my mind is effectively a part of logic. I just want to put as little logic as possible in the template. You're right, sometimes it may be better to have logic in the templates, for instance where you have a team of advanced designers, but there are plenty of other times where projects are driven by people who prefer to do as much in Perl as possible.

      Don't get me wrong, I kind of like the system you described, for a templating system :-).

      One of the problems I can see, though, is that for some kinds of output you'll either end up writing "one-off" callbacks, which means you'll now have highly integrated code and template fragments that you'll need to keep in sync spread over multiple files.

      In those cases, you may be better off either writing a function that just returns the complete HTML fragment, or putting the formatting details in code in the template directly, just to make it clear what's going on.

        you'll... end up writing "one-off" callbacks

        Yeah, I can see this happening. There was once or twice while working on Sylbi where it seemed like a waste to call a template because the section I was rendering was so small. Of course, you can stuff template sections in __DATA__...