Why templating languages aren’t a bad idea
Before I get into any meaty details, a quick question. You have a dynamic, database-driven web application and you’re ready to sit down and bang out its HTML output. One part of one page will be an ordered list containing comments left by visitors. You have the following choices for doing this:
Option A:
<ol class="comments"> {% get_comment_list %} {% for comment in comment_list %} <li>{{ comment }}</li> {% endfor %} </ol>
Option B:
item = page.new_content_element('ol') item.class = 'comments' for comment in db.get_post(post_id)['comments']: c = item.new_subelement('li') c.contents = comment
Which one do you think is preferable?
If you went with option B, go talk to Elver Loho who, in his rant on templating languages, seems to come to the conclusion that this is more suited to “rapid web development and Web 2.0.” If you went with Option A, congratulations: you’re sane.
Elver’s main beef with template languages seems to be that there’s no way to avoid having some sort of logic in them; since logic of some sort is inevitably necessary to generate the correct output, he wonders whether it might be better to just do away with template languages altogether and have pure logic. Styling will be accomplished by hanging CSS onto the markup generated by the logic.
And he seems to think that this transition is somewhat inevitable:
In any case, yes, it certainly works to have some logic in the template and it’s certainly a practical approach, but it stops working quite fast. Unless you’re a superman of some sort, you’re not good enough to design and code at the same time. You get the design from the designer and then you add code to it… Now suppose the design has to be tweaked a bit, but, oh no, it fucks up when loaded back into the designer’s favourite app! And after a lot of iterative development (also called: evolution), you end up with more and more logic inside the template.
There are a ton of things wrong in that paragraph, some of which I will now enumerate.
- Only a “superman” can design and code at the same time? I did it with this blog, and I doubt I’ll be leaping tall buildings in a single bound anytime soon. For a larger project, yes, it is handy to have separate people, or separate teams, working on the front and back ends, but that doesn’t mean that one person is incapable of doing both.
- The designer can’t load it back into his editing app? Gee, I’ll have to tell Jeff that he must have been imagining things all those times he thought he was editing Django templates in TextMate.
- You inevitably end up with more logic inside the template? Not in my experience. If you find yourself needing a lot more logic to get the template to do what it should, that’s a sign that you need to re-examine the view you’re rendering with it — why does Elver seem to assume here that nobody will ever apply iterative development to anything other than a template?
And thence proceeds Elver’s argument into a sort of Old Testament edict about separating presentation and logic: yea, the Lord saith that whosoever doth mingle the two shall be cursed, and cursèd shall be all of his seed, even unto the seventh generation. But that ignores the fact that separation of logic and presentation is a guideline, not a commandment, and that treating it as the latter will have nasty consequences. Like, say, having to do item = page.new_content_element(‘ol’)
instead of just <ol>
; that’s throwing the baby out with the bathwater.
As for the aforementioned “rapid development and Web 2.0”, well, markup-based templates are pretty darned good at that; sure, HTML and XML can be more complicated than you’d expect, but the most important and commonly-used aspects of both can be learned quickly. And they’re extremely fast for mocking things up — you can just drop in some lorem ipsum and roll with it rather than first having to write a database-driven backend to hook some sort of markup-generating program into.
And, frankly, replacing the front-end guy by putting more work on the back-end guy isn’t likely to work for most people.
Does this mean that we should just abandon the separation of logic from presentation altogether, and mingle them at will? Of course not; pretty much every developer worth his or her salt realizes the problems with that once it’s time to make a significant change to My First PHP App™. Remember, this is a guideline we’re talking about.
Elver also has some nasty words for Django‘s template language in particular:
Why is this bad? Well, you’re already writing SQL*, Python/whatnot, XML and JavaScript. Now you’ve got yet another language to learn and use. Not that big a deal, really, true.
But consider this. The whole point of decoupling presentation from logic is that you decouple code from how the thing ends up looking. Not only have you failed to do it, you’ve actually invented a new, buggy, inferior and untested programming language to hide that fact from yourself.
To paraphrase Jason, this is the part where I cough and it sounds like a naughty word. Any template language suitable for use in a dynamic, database-driven site has to provide at least a few features that aren’t in any HTML standard:
- A way to specify that particular pieces of dynamic content go in a particular place.
- A way to deal easily with bits of content which might be present in one instance of a page, but not another.
- A simple way of handling repetitive elements.
- A method of dealing with pieces of content which repeat across multiple pages, independent of the views which generate those pages.
Django’s template system provides all of those, and without diving too deeply into the programming end of the pool:
-
Django templates get variables which can be dropped into the output at any point. They look like this:
{{ var_name }}
. Is that really likely to blow the mind of someone who’s already learned “SQL, Python/whatnot, XML and JavaScript”? -
Meet
{% if %}
. It’s your friend. No matter how little programming someone knows, they can get this pretty quickly. -
This is why we have
{% for %}
(to deal with reptition within a single page) and{% extends %}
(to deal with repetition across many pages). Still nothing particularly difficult going on. -
This one involves a little programmer intervention, but still isn’t hard at all. Let’s say that you always want to pull out a list of the five most recent entries in a blog, and display them on every page. You could write the code to do this and copy/paste it into every view, but that’d be stupid. You could write a function to do this and call it in every view, but that’s not much better. Or you could write a piece of code which can be called by a tag in a template and, since templates can share repetitive code, you could drop the tag once into your base template and be done with it. As it happens, I use that trick on this very site;
{% get_recent_entries %}
goes into one template, and suddenly every page has a list of the most recent blog entries.
As for “buggy and inferior”, well, Django’s template language has worked like a charm on an awful lot of sites over a period of several years, so I’d be careful about jumping to conclusions there.
And let’s not even get into how Elver’s proposal for ensuring that he “decouples code from how the thing ends up looking” is to… um… replace the way the thing ends up looking with some more code.
So, short and sweet:
- Separation of logic and presentation is a guideline, not a commandment. You won’t find it in Leviticus no matter how hard you look.
- Markup is a heck of a lot better at quickly mocking up how something will look than any program you’ll ever write.
- Markup-based template languages can provide a lot of useful functionality and flexibility without looking too much like programs.
Whew.