Template Systems
Mar 19, 2004
The main problem with languages such as PHP, ASP, PSP and other scripting languages which embed code in the HTML, is that they mix presentation with logic. When logic and presentation is intertwined with eachother, one cannot be changed without (probably) corrupting the other. The result is a hard-to-manage, tiresome-to-change, difficult-to-scale web application.
The solution to this problem is Template Systems. These are supposed to intertwine logic as little as possible with the presentational HTML. The most important aspects of a Template System, in my opinion, are the following, in order of importance:
- Separate logic from presentation
- Unclutter presentational HTML
- Be designer (HTML-guy) friendly
There are several other aspects, like these, they are probably all closely related to eachother, but I think these are probably the most important ones, in my opinion. Of course, it is also important for a Template System to be fast, and easy to work with, but these are not attributes unique to Template Systems specifically, but important for coding in general.
So, focusing on these attributes, I went out and tried to find a Template System that suit my needs. Since I want to work with Python, I narrowed my search to the Python community and its libraries.
There are many template systems available for Python, some of which share the same syntax. These are some of the ones I've been looking at: AHTS, Cheetah, CherryPy, HTMLTemplate, htmltmpl, PSO, PyMeld, TAL (SimpleTal, Zope), STML, Twisted: Woven (and successor Nevow).
I've looked at others systems too, but those didn't fall into the Template System category, in my opinion, but rather the ASP/PHP/PSP-category using inline code in HTML documents.
So, how do these stack up to my criteria? Surprisingly bad, actually. That isn't to say that these are bad libraries or systems, but rather that they don't do what it is I need them to do. However, I think that a Template System must go to certain lengths to at least try to separate logic from presentational HTML in order to call itself a Template System at all, but perhaps that's only my opinion.
Let's look at examples of Template Systems that, in my opinion, don't separate logic from presentational HTML very well, if at all.
<TABLE>
#for $client in $clients
<TR>
<TD>$client.surname, $client.firstname</TD>
<TD>
<A HREF="mailto:$client.email">$client.email</A>
</TD>
</TR>
#end for
</TABLE>
The example above is from Cheetah, one of the more widely used Template Systems. Obviously, there is a lot of logic in this relatively simple example; the template is telling the code in the background to "loop through the list of clients". It's essentially the equivalent of using PHP, ASP or PSP to do the same thing, which is also evident in their own example.
So, if you're coming from, for example, a PHP background, the only reason I can think of to switch to Cheetah, or similar template systems, is if you'd rather use Python, but then you might as well use PSP (Python Server Pages); you're still going to intertwine code with presentational HTML.
There are several other Template Systems that intertwine code with presentational HTML in roughly the same way; they tell the code in the background to "make a conditional statement here", "loop through this list here", and so forth. Worse, they do this explicitly, with syntax that is often quite similar to regular inline languages/systems like PHP and PSP. Some Template Systems like these, that don't sufficiently separate logic from presentational HTML, nor unclutters the HTML, nor is particularly designer (HTML-guy) friendly (see my list of criterion above), are (links go to examples/references): AHTS, Cheetah, CherryPy, htmltmpl, STML, Zope ZPT and Simple Tal.
I'm not saying that these "Template Systems" are bad, or that they won't get the job done. I'm sure most of them, if not all, are quite alright. But, if you, like me, are looking for a Template System that separates logic from presentational HTML; if you want something better than PHP/PSP, something that will smoothen the interaction between coder and designer, something that won't confuse or annoy both the coders and designers on the team, then these "Template Systems" probably won't solve your problems.
What I'm looking for is a more data-centric Template System, one which doesn't have the template instruct the background code to make conditional statements, or to iterate through a list. The designer making the template shouldn't have to know pretty much anything at all about coding. He/she should just make HTML mock-ups, assign some kind of identity to key elements that the background code can pick-up, and let it, combined with the Template System, do the rest.
<TABLE>
<TR obj="rep_employees">
<TD obj="con_name">name surname</TD>
<TD>
<A obj="con_email" HREF="">e-mail address</A>
</TD>
</TR>
</TABLE>
The above example is from a Template System simply called HTMLTemplate, the logic is reduced to small prefixes which indicate how the identified HTML tag is to be processed. There is no programming syntax, however, the designer has to know when to use what prefix to each identified element.
A similar Template System is PyMeld, it completely separates logic from presentation, has a concise syntax, although it requires the coder to explicitly iterate through the data, as opposed to just pass a data structure and have the Template System itself iterate through it, like HTMLTemplate does.
Other Template Systems, that don't separate logic from presentational HTML as well as PyMeld and HTMLTemplate does, but better than those who hardely even tries to, are Twisted: Woven, its successor Nevow, and PSO.
While HTMLTemplate automatically iterates through the data structure the coder passes to it (as opposed to having to create a loop statement oneself), you still have to explicitly call the "iterate" method for elements that should be repeated, as well as prefix the element's name with "rep_". The system would be even better if it just understood that since I'm passing an array structure, I'll want it to iterate through it (doh).
There is one Template System that does that, but it's not for Python, it's for Ruby, and it's called Amrita. With Amrita, the coder doesn't have to tell the Template System to "iterate through this list for me and do the magic underneath", the coder only has to pass a data structure, and a template to expand it into, and Amrita figures out what to do with them. If Amrita is passed an array, it understands that it's supposed to iterate through it, there is no need to explicitly tell it to, neither for the coder, nor for the designer who makes the template.
At a glance though, modifying HTMLTemplate, or perhaps PyMeld, to automatically discover what to do with data passed to it, is probably not particularly difficult. So instead of writing a new Template System that sufficiently lives up to my criteria, I could probably just make some changes to one of those.
One other thing about some Template Systems though, like Amrita and PyMeld, is that they use the HTML attribute "id" to identify elements for the background code. Not very smart, since the "id" element has meaning in the HTML-world too. Preferably, the Template System should use something unique to it, and remove the reference while processing the template.
<TABLE>
<TR tmpl:id="employeelist">
<TD tmpl:id="name">name surname</TD>
<TD>
<A tmpl:id="email" HREF="">e-mail address</A>
</TD>
</TR>
</TABLE>
In the above -- fictional -- example, instead of using "obj", or prefixes, like HTMLTemplate does, or "id" like Amrita and PyMeld does, the identifiers are in a different namespace, the name of which, preferably, should be configurable. Another thing that the, for my purposes, "better" Template Systems make possible, is to add and/or change arbitrary attributes on the HTML tags identified to be processed.
The ultimate Template System would also, apart from separating the logic from the presentation completely, make it possible to optionally send parameters to the background code, such as perhaps to define what order by which the employees are to be listed.
This is not to say that those Template Systems that I write off as bad for my purposes are bad in general. I don't mean to say that any of these systems are better than any other, but rather to share my findings with other people who, possibly, are or will be in the same position as I am right now; trying to find a Template System that 1. separates logic from presentational HTML, 2. doesn't clutter the template HTML, and 3. is friendly (preferably transparent) to the designer, as well as the designer's software.
Unfortunately, only Amrita for Ruby, and PyMeld for Python, completely separates the logic from the presentation, but Amrita is the only Template System that automatically understands that if I pass it an array, named like an identifier in the template code, that array should be iterated through. Both PyMeld and HTMLTemplate need to be explicitly told that the array passed to them should be iterated through, as opposed to, I don't know what else.. Too bad Amrita, the only really clever Template System, is for Ruby and not for Python.
And finally, I'm not experienced with any of the Template Systems I've looked at, I've simply looked at the template file and from that determined wether there is logical statements in it or not. If there is logic in the presentational HTML, the template, then the logic is certainly, by definition, not completely separated from it. Also, this review should not be thought of as a comprehensive look at available Template Systems, it certainly is not.
Any tips or opinions regarding Template Systems is welcome, but please read this post in its entirety first.
Comments
You have some good points but it seems like you're perhaps missing the fact that the idea behind most, if not all, template systems is to seperate business logic from presentation. Presention would often have to include presentional logic, thats the "catch 22" with dynamic sites I'd say..
Comment by johan at 23:18, 19 Mar, 2004 #
Johan: Quite right, but one doesn't need a Template System to seperate business logic from the presentation layer, one could do that just as well with PHP, ASP or PSP, too (even though those languages allow you to intertwine more logic as well, they're not holding a gun to your head and forcing you to).
And, since Amrita and PyMeld completely separates all logic from the presentational HTML, it can be done. The thing is that the Template System has to be data-centric, as opposed to template-centric. Pass it an array and it will iterate through it, because it's an array, that's why, not because it is explicitly stated in the template that it should be iterated through.
Comment by Tomas at 23:31, 19 Mar, 2004 #
It uses PHP instead of Python, but I find ExpressionEngine from pMachine to be very close to what your looking for. I've just started using it, but I was searching for a Content Management System that used MySQL and PHP, and didn't render pages as HTML, but used templates, for on the fly generation of pages based on data pulled from the database. Give it a whirl, I believe the trial is free.
Comment by allgood2 at 01:20, 20 Mar, 2004 #
allgood2: The template language seems like that of Movable Type. I'm not really interested in a content management system, I'm looking for a Template System toolkit which allows me to tie my own logic to an (X)HTML interface.
Comment by Tomas at 02:16, 20 Mar, 2004 #
Well, that logic is more of a layout code than application code. It would be hard to separate presentation and template code completely. How could I do something as simple as a table with rows of alternating style classes (for alternating colors) without some code in the template?
I'm using Smarty for a couple of projects, and I've worked with it before. Mostly you just prepare the data to be presented in the application code, shape it into strings and arrays, and pass them on to Smarty which in turn tosses them into the template. (Smarty is great when the design team isn't the same as the programming team.)
But to do alternating colors, you still need a wee bit of logic in there:
{section name=vars loop=$_debug_keys}
{if %vars.index% is even}
class="dark"
{else}
class="light"
{/if}
{/section}
That's the equivalent of foreach($_debug_keys as $vars). (note: you don't have to use {} in Smarty, you can redefine it to pretty much anything.)
Is there really a template system that is completely HTML Guy-friendly? Even something as simple as the alternating colors requires some logic, and I don't want that logic in the application code. That should go in the layout code.
I suppose you could do something like this:
{loopsection template=foo loop=$bar}
and then define the template used for the iteration somewhere else. But it would still require logic for alternating.
...and I like the automatic caching in Smarty.
Well. I'm tired, so I'll try to make some more sense tomorrow.
Comment by Johan Svensson at 03:11, 20 Mar, 2004 #
Johan:
It would be hard to separate presentation and template code completely. How could I do something as simple as a table with rows of alternating style classes (for alternating colors) without some code in the template?
You could use Amrita, for Ruby, or PyMeld, for Python. Both separate the logic from the presentation completely. I don't mean "almost", or "nearly", or "mostly", but precisely "completely".
Both these Template Systems can arbitrarily modify any attribute of identified elements (using a DOM), i.e. that way you could add the CSS class name "odd" to every other line in the list. Problem solved.
As you mention, some kind of logic is required to do these kind of operations. Right. But that logic needn't be in the template, it can also be data-centric, i.e. be completely separated from the template itself. Such is the case with PyMeld and Amrita.
Comment by tomas at 03:18, 20 Mar, 2004 #
I can't help but look at that as logic separated from the presentation, and then some of the presentation moved back into the logic.
Comment by Johan Svensson at 03:26, 20 Mar, 2004 #
Ah, I just had a brief look at Amrita. I think you could do that degree of separation in Smarty as well. I'll have a look later.
Comment by Johan Svensson at 03:29, 20 Mar, 2004 #
Johan: You're probably right. That is some of the presentation moved into the logic, instead. To have every other line styled differently is, really, equal parts logic and presentation, one cannot be separated from the other. At least, I can't think of any way it can.
Comment by Tomas at 03:35, 20 Mar, 2004 #
I agree with other posters: *BUSINESS* logic should ideally not care about input and output modes, but UI logic is *certainly* intertwined to some degree with the desination medium, and rightfully so. Too many abstraction levels is just as difficult to maintain and scale as too few. Context-switching between languages in the same file (a la ASP), used correctly, is a compelling feature, not a bug. At *some point*, your code will have to hit the nuts and bolts of loops and conditionals producing markup, it may as well be in a form where both are peers.
Furthermore, HTML is just a document markup language. Large chunks of what we would normally consider part of the presentation layer in the non-web world *is* already separate: CSS for layout and formatting, JavaScript for validation and form control logic, and the web browser itself for rendering and navigation. There is no monolithic "presentation layer," it is spread out already among a number of players.
Templates languages are cool and all for simple interfaces, but you can accomplish the same separation of concerns with traditional platforms like ASP.NET *without* sacrificing the flexibility and power of a server scripting language working within the markup.
Comment by Richard Tallent at 04:11, 20 Mar, 2004 #
Richard: To separate business logic from presentational HTML is easy in ASP, PHP as well as PSP. None of those languages holds a gun to your head and forces you to intertwine more logic than simple loops and conditionals, just like most Template Systems, even though they make it possible. Why use a Template System to solve a problem that doesn't need a Template System to be solved?
Comment by Tomas at 11:54, 20 Mar, 2004 #
Actually, what you mentioned as "wrong" template engines are simply different approaches to templating - and all of them are valid ones. See TemplateView for comparison of different templating techniques. All of them have their pros and cons, but, again - all of them are valid and do serve the puprose of separating logic and presentation. See, that's MVC. Presentation logic should go to the presentation layer. Though MVC separates business logic from presentation it also insists on using a templating mechanism which implements presentation logic.
Comment by Leonya at 13:46, 22 Mar, 2004 #
Leonya: Actually, what you mentioned as "wrong" template engines are simply different approaches to templating - and all of them are valid ones."
Yeah, that's what I said. Read the entire post before you comment on it.
Comment by Tomas at 14:20, 22 Mar, 2004 #
Johan: "Presention would often have to include presentional logic, thats the "catch 22" with dynamic sites I'd say"
Tomas: "since Amrita and PyMeld completely separates all logic from the presentational HTML, it can be done."
Note that HTMLTemplate also completely separates presentation logic from display: the custom tag attributes are compiler - not renderer - directives. HTMLTemplate compiles HTML templates into a simple, custom object model (the View layer, if you like) that is manipulated programmatically by an attached Controller object.
Anyway, Tomas is correct: while presentation logic is [quite rightly] coupled to presentation display, there's no requirement for the two to mix. The Model-View-Controller manages to separate the two just fine: presentation display layer = View, presentation logic layer = Controller. (Any "Catch-22" is purely in the mind of PHP apologists; they just need to get out and about a bit to discover it's not so.:)
Johan: "How could I do something as simple as a table with rows of alternating style classes (for alternating colors) without some code in the template?"
In HTMLTemplate, you'd use something like:
# Template:
<table>
<tr obj="rep_row" class="odd">...</tr>
</table>
# Code:
def BoolGen():
"""Returns a 'False True False ...' sequence generator."""
e = False
while 1:
yield e
e = not e
class Controller:
def render_template(self, obj, rows):
obj.rep_row.iterate(rows, BoolGen())
def render_item(self, obj, link, boolGen):
if boolGen.next(): obj.atts['class'] = "even"
Johan: "I can't help but look at that as logic separated from the presentation, and then some of the presentation moved back into the logic."
Perhaps you're confusing presentation logic with business logic. Only the poorest of systems wouldn't allow you to decouple the presentation display from the business logic. The presentation logic and display are always going to be coupled, of course; can't do much otherwise.:) The difference is that this coupling is fairly loose in stuff like PyMeld, Amrita and various DOM-based systems, whereas it's very tight in code-in-markup systems like PHP, ASP, Cheetah and PSP. Both have benefits vs. tradeoffs; e.g. the linearity of code embedded in markup will be easier on folk who aren't strong on abstraction, while a clean separation of the two is friendlier to both designers and programmers and their tools.
Tomas: "So, how do these stack up to my criteria? Surprisingly bad, actually."
Actually, PyMeld, HTMLTemplate and Nevow.Renderer all meet your three listed requirements just fine. However, you later indicate a fourth requirement: a particular style of templating where a complex, pre-built data structure is directly mapped onto a passive template. More like an super-sophisticated printf-style string substitution than the interactive View-Controller operation of these three systems, or the code-in-markup or markup-in-code approaches of others. I think I've heard of these in the past, though Amrita is the first example I've seen. I'm a bit doubtful it'll be a superior option (at a first glance, it looks less flexible and less efficient), but I couldn't really say without actually using it. You could certainly modify HTMLTemplate to create such a system (can give you pointers on doing this). Or maybe port Amrita if that's an option.
Comment by has at 20:49, 22 Mar, 2004 #
A useful guide I've found when comparing template systems is Terence Parr's paper Enforcing Strict ModelView Separation in Template Engines [88k PDF]. In it, he proposes the following 5 rules which are implied by strict separation of model and view:
1. the view cannot modify the model either by directly altering model data objects or by invoking methods on the model that cause side-effects. That is, a template can access data from the model and invoke methods, but such references must be side-effect free. This rule arises partially because data references must be order-insensitive.
2. the view cannot perform computations upon dependent data values because the computations may change in the future and they should be neatly encapsulated in the model in any case. For example, the view cannot compute book sale prices as "$price*.90". To be independent of the model, the view cannot make assumptions about the meaning of data.
3. the view cannot compare dependent data values, but can test the properties of data such as presence/absence or length of a multi-valued data value. Tests like
$bloodPressure<120
must be moved to the model as doctors like to keep reducing the max systolic pressure on us. Expressions in the view must be replaced with a test for presence of a value simulating a boolean such as
$bloodPressureOk!=null
Template output can be conditional on model data and computations, the conditional just has to be computed in the model. Even simple tests that make negative values red should be computed in the model; the right level of abstraction is usually something higher level such as "department x is losing money."
4. the view cannot make data type assumptions. Some type assumptions are obvious when the view assumes a data value is a date, for example, but more subtle type assumptions appear: If a template assumes $userID is an integer, the programmer cannot change this value to be a non-numeric in the model without breaking the template. This rule forbids array indexing such as colorCode[$topic] and $name[$ID]. The view further cannot call methods with arguments because (statically or dynamically) there is an assumed argument type, unless one could guarantee the model method merely treated them as objects. Besides graphics designers are not programmers; expecting them to invoke methods and know what to pass is unrealistic.
5. data from the model must not contain display or layout information. The model cannot pass any display information to the view disguised as data values. This includes not passing the name of a template to apply to other data values.
---
I should point out that the paper does devote the latter 15% or so to Parr's STRINGTEMPLATE system (which I've not used) - but even ignoring that, the rest of the paper stands up well. Have any of you already read this paper? Any thoughts about how the systems mentioned thus far stack up in the comparison?
Sorry 'bout the post length!
Comment by Sid at 16:04, 24 Mar, 2004 #
Johan,
the cycle function gives you a more compact way of alternating row styles in smarty:
<table>
{section name=row loop=$data}
<tr class="{cycle values="oddrow,evenrow"}">
<td>{$data[row]}</td>
</tr>
{/section}
<table>
Would be curious to see how this is done using the other template systems talked about.
Comment by Sid at 16:14, 24 Mar, 2004 #
Take a look at ClearSilver (www.clearsilver.net), it's
a pretty neat templating system with Python bindings.
It separates the application logic from the presentation
logic, through an explicit blob of computed data (application
logic computes the data, presentation logic reads the data).
ClearSilver has been used internally at Yahoo Groups.
Comment by Foo Manchu at 14:20, 28 Mar, 2004 #
Foo: ClearSilver separates logic from presentation about equally well as PHP does, i.e. not at all.
Comment by Tomas at 14:44, 28 Mar, 2004 #
Well, here's a little elaboration on my previous comment.
I agree that ClearSilver has a template language that
allows too much logic in it. In MVC terminology, it has
both the V and C built into it. But the M is separated.
Application logic and presentation (with associated logic)
are separated. Which is not true with PHP.
I have worked with PHP and with ClearSilver, and I
found ClearSilver to be much better in that I had a script that just computed data without regard for how it will be presented, and I had a template which for the most part simply read the computed data into placeholders. I could
then change these independently. You could simulate this
kind of thing in PHP but no one does that. Most PHP scripts
intersperse the data computation with the HTML and
rendering logic.
Occasionally, I would use some rendering logic in the Clearsilver template
(e.g., alternate colors of rows, or force a linewrap every
three items or something). These are the kinds of
situations where the V and C need to be separated, though
I'm not sure I'd want to maintain 3 entities for a single page. Depends on the page I guess.
When I first saw ClearSilver and the tags in the template
language, I thought that this was just PHP. But when
I started using it, I found it was much better to use, with
a clear separation of concerns.
Something like the initial resistance to Python's use of
indentation-as-scope which evaporates on real use.
So perhaps, you might want to try out all the systems
you have been looking at on a small representative page that you want to templatize. You might find that you
like some of these systems or that you can live with
their warts because you like some other part of them.
I found Terrence Parr's paper interesting, thanks to Sid for
the link.
Comment by Foo Manchu at 00:13, 29 Mar, 2004 #
i have to side with those pointing out the distinction between the presentation logic and business logic.
the rudimentary looping and conditional testing in presentation logic serves only to render the data for the particular display medium. it's entirely decoupled from the model side.
you're seeking to separate presentation logic from presentation layout. i'm not sure why you'd want to do this. you either need to add an extra "presentation logic programmer" to the virtual division of labor, or force the designer to learn to code in order to provide presentation logic, or add presentation logic to the responsibilities of the business logic developer.
makes much more sense to give the designer control of simple logical constructs that let him lay out the display as he sees fit. much better for the designer to be responsible for an "$isEven" flag than for the developer on the model side to have to maintain a bunch of weird, domain-irrelevant flags like "empList.isEven()" to his code.
Comment by flacco at 23:14, 14 Apr, 2004 #
I've had the most luck with MVC using java servlets with jsp. You can pretty much get complete separation and reuse a lot of code in javaservlet/jsp architectures. I find that most java MVC architectures are very complicated however so I had to create my own. Any other MVC architectures used by anyone that are simpler than java's but have the same power?
Comment by Uedauhes at 00:29, 23 Jul, 2004 #
Uedauhes: Mojavi seems rather good.
Comment by Tomas Jogin at 01:29, 23 Jul, 2004 #
flacco: "you either need to add an extra "presentation logic programmer" to the virtual division of labor, or force the designer to learn to code in order to provide presentation logic, or add presentation logic to the responsibilities of the business logic developer."
How is this any different than having your presentation logic embedded in the HTML? Someone still has to write the presentation code. Putting it in the HTML forces the designer to deal with it; if you cleanly seperate it then you can choose who deals with it - the designer, business logic programmer, or whoever else. It lets you customize your division of labor to fit the talents of your team members.
Comment by Dean Kusler at 07:00, 11 Aug, 2004 #
The discussion has been closed on this entry. Thanks to everybody who participated.