Template processors and engines are one of those pieces of software where it seems every developer wants to reinvent the wheel. Goodness knows I’ve done it earlier in my career. Tell me if this sounds familiar:

  1. You need to mix data into a document so you start with Perl’s string interpolation in "double quotes" or sprintf formats. (Or maybe you investigate formats, but the less said about them the better.)
  2. You realize your documents need to display things based on certain conditions, or you want to loop over a list or some other structure.
  3. You add these features via keyword parsing and escape characters, thinking it’s OK since this is just a small bespoke project.
  4. Before you know it you’ve invented another domain-​specific language (DSL) and have to support it on top of the application you were trying to deliver in the first place.

Stop. Just stop. Decades of others who have walked this same path have already done this for you. Especially if you’re using a web framework like Dancer, Mojolicious, or Catalyst, where the template processor is either built-​in or pluggable from CPAN. Even if you’re not developing a web application there are several general-​purpose options of various capabilities like Template Toolkit and Template::Mustache. Investigate the alternatives and determine if they have the features, performance, and support you need. If you’re sure none of them truly meet your unique requirements, then maybe, maybe consider rolling your own.

Whatever you decide, realize that as your application or website grows your investment in that selection will only deepen. Porting to a new template processor can be as challenging as porting any source code to a new programming language.

Unfortunately, there are about as many opinions on how to choose a template processor as there are template processors. For example, in 2013 Roland Koehler wrote a good Python-​oriented article on several considerations and the different approaches available. Although he ended up developing his own (quelle surprise), he makes a good case that a template processor ought to at least provide various logic constructs as well as embedded expressions, if not a full programming language. Koehler specifically warns against the latter, though, as a template developer might change an application’s data model, to say nothing of the possibility of executing arbitrary destructive code.

I can appreciate this reasoning. I’ve successfully used Perl template processors like the aforementioned Template::Toolkit (which has both logic directives and an optional facility for evaluating Perl code) and Text::Xslate (which supports several template syntaxes including a subset of Template::Toolkits, but without the ability to embed Perl code). We use the latter at work combined with Text::Xslate::Bridge::TT2Likes emulation of various Template::Toolkit virtual methods and it’s served us well.

But using those modules’ DSLs means more sophisticated tasks need extra time and effort finding the correct logic and expressions. This also assumes that their designer(s) have anticipated my needs either through built-​in features or extensions. I’m already writing Perl; why should I switch to another, more limited language and environment provided I can remain disciplined enough to avoid issues like those described above by Koehler?

So for my personal projects, I favor template processors that use the full power of the Perl language like Mojolicious’ embedded Perl renderer or the venerable Text::Template for non-​web applications. It saves me time and I’ll likely want more than any DSL can provide. This may not apply to your situation, though, and I’m open to counter-arguments.

What’s your favorite template processor and why? Let me know in the comments.