Templating

Definition

A domain-specific language and deployment process designed specifically to generate custom text output.

Example Use Cases

Relation to the Application

Templating is often a separate subsystem, defined along several characteristics:

Sometimes, of course, none of these are true. An application might do templating in the same language as the application, executed in the same process, with files in the same location, coded by the same developer. The differences are a matter of degree.

A key point: the output of a templating operating is usually intended as a final stage of delivery, to be sent to a consuming device or platform. Very rarely is the output of templating re-incorporated into application logic or operated on in any other way. Data is templated at the last moment before delivery, then it leaves the application context.

The Two Philosophies of Templating

There are two competing theories of how templates should interact with the application:

  1. Weak Templates: Templates should be limited in both data and features. They should only be able to interact with data “given” to them, and they should have a very limited logical featureset. Having logic inside templates just creates another level of code and potential issues, often written by a developer not familiar with the larger application.

  2. Strong Templates: Templates should have most of the logical features of the “full” programming language, and should even be able to retrieve data beyond that which is provided to them. A templating language only exists to provide a layer of computational sandboxing, features specifically designed for the manipulation of text, and the convenience of a separate DevOps context.

Most systems will exist somewhere in the middle. In particular, the weak templating philosophy has some vocal adherents for “logic-less” templates, but it imposes considerable limitations on template development that often frustrate developers working with it.

The Template “Context”

Most all templating languages operate on the idea of a special “sandbox” or context in which the template executes. The templating language will have access to the data specifically injected into this context, or the results of functions made available to that context, and nothing else.

context.SetValue("name", "Deane");
template.Render(context);

In the example, a token called “name” will be available inside the template, containing the string value “Deane.”

In some cases, selected data retrieval functions might be available to templates, but this is not common. “Extra” data might be made available to a template, which it can use or ignore, but seldom can a template proactively retrieve data from outside the context.

Tag Structure of Templating Languages

Templating languages are usually designed to be simpler than “full” programming languages. They’re also designed to be intermixed with “markup” of some kind – usually HTML. This means that template code is usually intermixed with markup code, offset by delimiters.

Anything in these tags is either executed (and removed) or replaced with something else (and therefore also removed). Anything outside these tags is part of the generated output.

There are also a few templating languages that abandon the “intermixed tag” formal altogether:

Feature: Token Replacement

As templating code is intermixed with markup code, much of templating involves the insertion of placeholders or tokens which are replaced with data injection into the templating context.

<p>
  <strong>First Name:</strong> {{ person.first_name }}
</p>

In the above example, a data object called person has been injected into the template context. It has a property called first_name which will be retrieved and will take the place of {{ person.first_name }}

Feature: Filters

In many cases, data needs to be formatted or modified before it’s output. The most common metaphor for this is the concept of “piping” data in a command line using the | character.

<p>
  <strong>First Name:</strong> {{ person.first_name | upcase }}
</p>

In that example, the output of person.first_name will be filtered through a filter called upcase, which will presumably convert the text to upper case.

In most systems, filters can be chained and can sometimes take arguments:

{{ person.age | plus:10 | format_number:'N0' }}

Feature: Conditionals

Logic in templates might branch, though it’s much more common to use conditionals to simply display or not display a particular chunk of markup:

{% if person.age >= 55 %}
  <p>You're legible for a senior discount!</p>
{% endif %}

Most templates will support the standard operators: equal, not equal, greater than, lesser than, etc. Some also have a simple negation tag, like unless, which would be the opposite of if.

Given that most templating languages are less exact than full programming languages, and, in particular, less strict about typing, sometimes it’s difficult to determining “nothing-ness.” Does this mean…

Every language is little different in this respect. Some include constants like blank, empty, and nil to test against:

{% if articles == empty %}

Feature: Looping

Most languages can iterate over collections of objects.

<ul>
{% for article in articles %}
  <li>{{ article.title }}</li>
{% endif %}
</ul>

Some languages include extra iteration features like:

Feature: Inclusion

Like other code, templates tend to be repetitive and derivative, and it’s often that template code is re-used. Therefore, templates can often perform inclusion on two levels

Many templates will perform both types of inclusion:

Common Templating Systems

Given that templating is pan-application, most languages have a “favored” templating system:

Some other systems have achieved pan-language adoption, with implementations for multiple languages:

Very rarely will an application write a custom templating system. It’s much more common for a language to provide custom extensions to an existing language.

Extensibility

Most templating languages allow new functionality to be added via development in the implementing language. Common extension points:

These manifest as custom strings in template code that invoke code in the native application language and send return the results to the template context.

Practices for User Extensibility: Templating