Mustache is logic-less but the logic has to go somewhere

As the developer of mustache.java I get a lot of feature requests to break the mustache language and add real logic to the templates. In virtually every case the reason the developer wanted the functionality was because they were using mustache with a template backed with a model without an interposed view. Let me give you a common example. Developer has a user object with a few fields:

class User {
  String username;
  long createdAt;
}

And they want to show when the user joined in their template:

{{#user}}{{username}} joined on {{createdAt}}{{/user}}

They look at this and think, “I need to be able to format longs into dates in the template”. If you were in .erb or .jsp you might create a helper to do that and call it directly from the template. For mustache, someone will typically suggest changing the language to add filters so you might write the template like this:

{{#user}}{{username}} joined on {{createdAt | date}}{{/user}}

Then there would be a bunch of date formatters you could use, you might even go so far as to ask to parametrize it in the template because it isn’t flexible enough with just a name:

{{#user}}
  {{username}} joined on {{createdAt | date("DD/mm/YYYY")}}
{{/user}}

And you start going down this road where more and more of the view logic is going directly into your template making it hard to internationalize, harder to share between mustache implementations and generally making it harder to maintain and test. However, this isn’t the way you should use mustache. The best way is to add an additional layer of logic in your chosen host language that is responsible for the view. So for this case, what you would like end up with is something like this view:

class UserView {
  String username;
  String joined_date;
  UserView(User user) {
    username = user.username;
    joined_date = new SimpleDateFormat("DD/mm/YYYY")
        .format(new Date(user.createdAt));
  }
}

with a template much like the first one:

{{#user}}{{username}} joined on {{joined_date}}{{/user}}

This allows you in the future to add special internationalization, user specific date formats, maybe a relative timestamp, etc. All without ever changing the template. It is also easier to test since you can independently check that the formatting of the date is correct without having to execute it within the context of the template text.

This strategy worked great at Bagcheck where there was only myself and a designer and it works great at Twitter where we have tons of engineers and designers working in the code base. It has also made it possible to move between rendering on the client in Javascript to rendering on the server in Ruby to rendering on the server in Scala all with the same set of templates and basically standard mustache implementations.

This entry was posted in Technology. Bookmark the permalink.
  • http://twitter.com/gchapiewski Guilherme Chapiewski

    I often use PresentationModel patter for my views (http://martinfowler.com/eaaDev/PresentationModel.html), which is similar to what you are describing, helps remove all the logic from the templates and give you awesome flexibility (and testability) for complex views :)

  • http://twitter.com/gchapiewski Guilherme Chapiewski

    http://martinfowler.com/eaaDev/PresentationModel.html – The Disqus parser screwed up with my link :)

  • Hanson.S

    Please think of such scenario. I’ll use Mustache to write template for a Java code.

    {{#clazzes}}
    {{name | initialCapitalized}} {{name | initialUncapitalized}} = new {{name | initialCapitalized}}({{#constructorArgs}}{{type}} {{name}}, {{/constructorArgs}});
    {{/clazzes}}

    My expectation would be:

    Person person = new Person(String arg1, int arg2);
    Car car = new Car(long arg1, boolean arg2);

    Is it possible? Or is Mustache suitable for generating Java code? Thanks.

  • abuhr

    If you want to be able to render the same template on both the client (javascript) and on the server (e.g. java), you have to implement this ‘additional layer of logic’ (i.e. the UserView) in javascript and in java, right?

  • http://www.javarants.com spullara

    Yep, at Twitter they have been implemented in Javascript, Ruby and Scala.

  • Andreas

    Isn’t it {{#userview}}{{username}} joined on {{joined_date}}{{/userview}} in the last example?

  • http://www.javarants.com spullara

    There is no reason to name your mustache variables after your classes. I would still call it user.

  • http://www.javarants.com spullara

    I use it to generate Java code all the time. I would just put those things in the code itself. You can see this in my redis generator here:

    https://github.com/spullara/redis-protocol/blob/master/redisgen/src/main/java/redis/redisgen/Main.java