104

Recently, I ran into mustache which is claimed to be Logic-less template.

However, there is no explaining why it is designed in Logic-less way. In another word, what's the advantage of Logic-less template?

Morgan Cheng
  • 66,562
  • 63
  • 166
  • 223

13 Answers13

110

In other words, it prevents you from shooting yourself in the foot. In the old JSP days, it was very common to have JSP files sprinkled with Java code, which made refactoring much harder, since you had your code scattered.

If you prevent logic in templates by design (like mustache does), you will be obliged to put the logic elsewhere, so your templates will end up uncluttered.

Another advantage is that you are forced to think in terms of separation of concerns: your controller or logic code will have to do the data massaging before sending data to the UI. If you later switch your template for another (let's say you start using a different templating engine), the transition would be easy because you only had to implement UI details (since there's no logic on the template, remember).

Miguel Ping
  • 17,442
  • 22
  • 82
  • 135
  • 30
    So, why is it a good thing that controller code HAS to massage data in exactly the form that is needed to present the data in a particular way? Why is it a good thing that changing the presentation often requires changing controller code? This seems like a bad thing to me. I thought one goal of a template language was to separate controller logic from presentation logic. A dumb template that can't make any decisions whatsoever forces presentation logic back into the controller code. In organizations where a different person works on presentation, they can't do their job by themself. – jfriend00 Sep 19 '14 at 17:35
  • 8
    You should not prepare data for the view in your controller. Controller is for controlling application flow. Instead what you should do is create a presenter class that transforms your model into a view model which is then consumed by the view. A view model is a model for the UI which is separate from the model which is part of the business logic. I recommend you to watch the "Clean Architecture and Design" talk by Robert "Uncle Bob" Martin: http://youtu.be/asLUTiJJqdE – ragol Oct 13 '14 at 13:14
  • 1
    It forces some presentation logic into the controller, but this helps mutliple various presentation layers. If you want similar data to be presented as JSON, HTML, or XML, you shouldn't twist the data 100% in the HTML template. That would leave the JSON and XML to have their own twisting display logic. You're centralizing 80% of the display logic in the controller, and embedding the other 20% in lambdas and filters. – chugadie Jul 26 '16 at 14:47
67

I get the feeling that I am nearly alone in my opinion, but I am firmly in the opposite camp. I don't believe that the possible mixing of business logic in your templates is enough reason not to use the full power of your programming language.

The usual argument for logic-less templates is that if you have full access to your programming language you might mix in logic that has no place being in a template. I find this akin to reasoning that you should use a spoon to slice meat because you could cut yourself if you use a knife. This is very true, and yet you will be far more productive if you use the latter, albeit carefully.

For instance, consider the following template snippet using mustache:

{{name}}:
<ul>
  {{#items}}
    <li>{{.}}</li>
  {{/items}}
</ul>

I can understand this, but I find the following (using underscore) to be much more simple and direct:

<%- name %>:
<ul>
<% _.each(items, function(i){ %>
  <li><%- i %></li>
<% }); %>
</ul>

That being said, I do understand that logicless templates have advantages (for instance, they can be used with multiple programming languages without changes). I think these other advantages are very important. I just don't think their logic-less nature is one of them.

Emile Bergeron
  • 14,368
  • 4
  • 66
  • 111
brad
  • 67,670
  • 21
  • 67
  • 84
  • 136
    I'm surprised you feel that the underscore template is simpler.. it looks a lot less readable to me. Just an opinion :-) – Ben Clayton May 16 '11 at 13:23
  • 9
    @ben-clayton I agree that the first syntax is prettier and perhaps more readable. However, its the complexity that I'm driving at when I say "simple". – brad May 17 '11 at 11:09
  • 2
    Sometimes using a ternary statement is appropriate in the template no matter what logic you have. Or what if I want to output the number of items in an array? I don't know how I could use mustache, it appears to lack things like that. – Paul Shapiro Apr 17 '12 at 21:20
  • 5
    @PaulShapiro You would generate the number of items in the array outside the template, and store it in a separate variable. – Seun Osewa Jun 19 '12 at 11:55
  • 4
    @brad, the underscore template introduced an XSS hole: `name` and `items` could contain JavaScript. – Matthew Apr 25 '13 at 23:48
  • 1
    @PaulShapiro, the Mustache view can provide a helper function which counts and returns the number of items. – Matthew Apr 25 '13 at 23:49
  • Other than the syntax, can you explain the difference between your two examples? They both look like a name followed by a loop of items in a list. I would consider a loop as logic, and seeing as {{mustache}} has loops I don't know how people can consider it a "logic-less" language. – chharvey Sep 03 '16 at 05:35
  • 1
    Regarding the comment from @Matthew: are we really sure here? I'm not particularly a security expert, but the – Vultaire Sep 09 '16 at 19:57
  • @Vultaire Looks like brad corrected the XSS flaw about 8 months after my comment. – Matthew Sep 12 '16 at 07:05
  • @chharvey formally, one is Turing Complete, and the other isn't. Loops alone don't constitute what's being meant by "logic", e.g. engines, jackhammers, and windmills all "loop", and a circular slide rule both loops and calculates, but none of them can _compute_. – Kache Mar 03 '19 at 15:30
29

Mustache is logic-less?

Isn't this:

{{#x}}
  foo
{{/x}}
{{^x}}
  bar
{{/x}}

Pretty similar to this?

if x
  "foo"
else
  "bar"
end

And isn't that pretty similar to (read: almost a definition of) presentation logic?

pje
  • 19,409
  • 9
  • 50
  • 67
  • 17
    Yes, if you are just evaluating the truthiness of an object, but trying to do anything more complicated isn't possible (`if x > 0 && x < 10`)... So, while it's possible to use Mustache with or without logic, it's up to you. After all, it's just a tool. – Tom Ashworth Oct 29 '12 at 13:08
  • 5
    You're looking at this the wrong way. Just because you can do a few things in a language that are not exactly of its general paradigm does not mean that the language is not of that paradigm. You can do write imperative code in Java or Haskell, yet you wouldn't say that makes Java not an OO language nor Haskell not a functional language. Look at what the language lets you do easily and what it leads you towards to see what kind of language it is. – cjs Jul 24 '15 at 05:59
  • @CurtJ.Sampson your analogy would make sense if Java sold itself as "functional-less" or if Haskell sold itself as "object-oriented-less". This answer is demonstrating that "logic-less" is at best a misnomer. – Corey Oct 22 '17 at 18:30
  • 1
    I think you agree with me that when we call a language "functional" we mean, "tending toward functional." The disagreement seems to be that I define "X-less" as "tending away from X" whereas you define it as "entirely unable to do X." – cjs Oct 23 '17 at 22:40
14

A logic-less template is a template that contains holes for you to fill, and not how you fill them. The logic is placed elsewhere and mapped directly to the template. This separation of concerns is ideal because then the template can easily be built with different logic, or even with a different programming language.

From the mustache manual:

We call it "logic-less" because there are no if statements, else clauses, or for loops. Instead there are only tags. Some tags are replaced with a value, some nothing, and others a series of values. This document explains the different types of Mustache tags.

Jeremy
  • 21,351
  • 4
  • 61
  • 77
  • 6
    The description is slightly sophistic, as the sections work rather like conditionals and loops, just very limited ones. The ability to refer to callables in the hash also lets you transform sections into a rudimentary programming language. Still, at least it makes it difficuly to go down that route, rather than encouraging it. – Tom Anderson Oct 17 '10 at 22:16
  • 1
    Sure, but a template system without blocks for conditions and iteration would be relatively useless. The template itself doesn't specify what the block is for, or how it's handled. – Jeremy Oct 17 '10 at 22:50
13

The flip side of the coin is that in a desperate attempt to keep business logic out of the presentation, you end up putting lots of presentation logic in the model. A common example might be that you want to put "odd" and "even" classes on alternating rows in a table, which could be done with a simple modulo operator in the view template. But if your view template doesn't allow you to do that, then in your model data you have to not only store which row is odd or even, but depending on how limited your template engine is, you may even need to pollute your model with the names of actual CSS classes. Views should be separate from Models, full-stop. But Models should also be View agnostic, and that's what many of these "no-logic" template engines make you forget. Logic goes in both places, but you have to be judicious about what the logic actually does to decide correctly where it goes. Is it a presentation concern, or a business/data concern? In an effort to have 100% pristine views, the pollution just lands in another less visible but equally inappropriate place.

There's a growing movement back in the other direction, and hopefully things will center somewhere in the more reasonable middle-ground.

mattmc3
  • 15,986
  • 5
  • 75
  • 96
  • 6
    Gotta disagree with you there. The presentation logic for logic-less templates doesn't go in the model, it goes in the view, where it belongs. The view takes the raw model data, and massages as necessary (by annotating odd/even rows, etc.) to prepare it for presentation. – acjay Nov 30 '12 at 22:25
  • 1
    Why cannot views be more than templates, and include code to massage data for a template? – Lee Goddard Jan 18 '13 at 12:47
  • 1
    acjohnson55 - I agree with you about where it should go (view), but logic-less templates prevent a lot of that. @LeeGee - I think there's a backlash against too much logic in views, but things have gone too far in the other direction to prevent even presentation-specific logic in views. – mattmc3 Jan 18 '13 at 16:07
  • 4
    I know I'm late to the party, but CSS nth-item(odd) should be used for alternating row colors. – DanRedux Jan 31 '14 at 14:37
  • 1
    Threre's nothing wrong with having an intermediate presentation object created by the view from models and collections, or any other data. In this way, views create presentation data which are merged with a template to render the view. – wprl Apr 21 '14 at 00:21
  • @wpf - All that does is move presentation logic into another place in the code farther away from where it's needed and useful. It's a commonly accepted practice, I'll grant you. That doesn't make it right. I'll agree to disagree on this one. My only point is that this is not a settled issue by any stretch and I'm happy to see the pendulum swinging back toward a more sane middle ground and away from ultra-restrictive templating (like Mustache). – mattmc3 Apr 21 '14 at 01:06
12

It makes your templates cleaner, and it forces you to keep logic in a place where it can be properly unit-tested.

blockhead
  • 9,317
  • 2
  • 41
  • 65
  • 2
    Can you explain it with more details? – Morgan Cheng Oct 11 '10 at 02:22
  • 29
    Spend three months working on a system using a logicful templating language, like JSP, with programmers who are not zealous about separating logic and presentation. You'll find you build a system which essentially has programming in the page - arithmetic for table layout, conditionals for what pricing information to show, and so on. Templating languages are extremely poor programming languages, so this makes for a development and maintenance nightmare. Something like Mustache doesn't let you get into that situation in the first place. – Tom Anderson Oct 17 '10 at 22:13
  • If the logic is in the form of a function, it can be used by a micro-templating system that supports embedded logic *and* unit-tested. The worst idea to me seems to be handlebars "helpers" (see http://spin.atomicobject.com/2011/07/14/introducing-icanhandlebarz-js-icanhaz-js-meet-handlebars-js/ "Advanced Usage") -- these would seem to be impossible to unit-test due to being within script/type/text tags rather than plain old script(/type/javascript) tags – Dexygen Jul 10 '13 at 19:17
9

This conversation feels like when the monks of the middle-ages would debate over how many angels can fit on the end of a pin. In other words its starting to feel religious, futile and incorrectly focused.

Mini-rant ensues (feel free to ignore):

If you don't want to continue reading.. My short response to the above topic is: I don't agree with logic-less templates. I think of it as a programming form of extremism. :-) :-)

Now my rant continues in full swing: :-)

I think when you take many ideas to the extreme, the outcome becomes ludicrous. And sometimes (ie this topic) the issue is that we take the "wrong" idea to the extreme.

Removing all logic from the view is "ludicroous" and the wrong idea.

Step back for a moment.

The question we need to ask ourselves is why remove the logic? The concept, obviously is separation of concerns. Keep the view processing as separate from the business logic as possible. Why do this? It allows us to swap out views (for different platforms: mobile,browser,desktop etc) and it allows us to more easily swap out the control-flow, page sequence, validation changes, model changes, security access etc. Also when logic is removed from the views (especially web views), it makes the views much more readable and therefore more maintainable. I get that and agree with that.

However the overriding focus should be on separation of concerns. Not 100% logic-less views. The logic within the views should relate to how to render the "model". As far as I'm concerned, logic in the views is perfectly fine. You can have view-logic that is not business-logic.

Yes, back in the day when we wrote JSPs, PHP or ASP pages with little or no separation of code logic and view logic, the maintenance of these web-apps was an absolute nightmare. Believe me I know, I created and then maintained some of these monstrosities. It was during that maintenance phase that I really understood (viscerally) the error of my and my colleagues ways. :-) :-)

So the edict from on high (the industry pundits) became, thou must structure your web-apps using something like a front-view controller (that dispatched to handlers or actions [pick your web-framework]) and thy views must contain no code. The views were to become dumb templates.

So I agree in general with the above sentiment, not for the specifics of the items of the edict, but rather the motivation behind the edict - which is the desire for separations of concerns between view and business logic.

In one project that I was involved in, we tried to follow the logic-less view idea to the ludicrous extreme. We had a home-grown template engine that would allow us to render model objects in html. It was a simple token based system. It was terrible for one very simple reason. Sometimes in a view we had to decide, should I display this little snippet of HTML .. or not.. The decision is usually based on some value in the model. When you have absolutely no logic in the view, how do you do that? Well you can't . I had some major arguments with our architect about this. The front-end HTML people writing our views were completely hamstrung when they were faced with this and were very stressed because they could not achieve their otherwise simple objectives. So I introduced the concept of a simple IF-statement within our templating engine. I cannot describe to you the relief and the calm that ensued. Problem was solved with a simple IF-Statement concept in our templates! Suddenly our templating engine became good.

So how did we get into this silly stressful situation? We focused on the wrong objective. We followed the rule, you must not have any logic in your views. That was wrong. I think the "rule-of-thumb" should be, minimize that amount of logic in your views. Because if you don't you could inadvertently allow business logic to creep into the view - which violates separation of concerns.

I understand that when you declare that "You must have no logic in the views", it becomes easy to know when you are being a "good" programmer. (If that is your measure of goodness). Now try implementing a web-app of even medium complexity with the above rule. Its not so easily done.

For me, the rule of logic in the views is not so clear cut and frankly that's where I want it to be.

When I see lots of logic in the views, I detect a code-smell and try to eliminate most of the logic from the views - I try to ensure business logic lives elsewhere - I try to separate the concerns. But when I start chatting with people who say we must remove all logic from the view, well, to me, that just smacks of fanaticism as I know you can end up in situations like I described above.

I'm done with my rant. :-)

Cheers,

David

David Balme
  • 165
  • 2
  • 9
  • great answer, it's all about good programming practices.. and by the way, reusing logic-less templates in server and client isn't DRY because you will have to duplicate logic in both.. – mateusmaso Apr 13 '13 at 18:34
6

The best argument I've come up with for logicless templates is then you can use the exact same templates on both the client and server. However you don't really need logicless, just one that has it's own "language". I agree with the people who complain that mustache is pointlessly limiting. Thanks, but I'm a big boy and I can keep my templates clean without your help.

Another option is to just find a templating syntax that uses a language that is supported on both client and server, namely javascript on the server either by using node.js or you can use a js interpreter and json via something like therubyracer.

Then you could use something like haml.js which is much cleaner than any of the examples provided so far and works great.

eagspoo
  • 1,946
  • 2
  • 19
  • 28
  • I completely agree. After some reading, I've come to the conclusion that the ability to template in JS on both the client and server side meets my needs better than a bunch of specific templating languages – christofr Aug 30 '13 at 08:44
5

In one sentence: Logic-less means the template engine itself is less complex and therefore has a smaller footprint and there are less ways for it to behave unexpectedly.

Kernel James
  • 2,830
  • 18
  • 17
4

The main advantages of using logic-less templates are:

  • Strictly enforces model-view separation, see this paper for details (highly recommended)
  • Very easy to understand and use, because no programming logic (and knowledge!) is needed and the syntax is minimal
  • (particular Mustache) highly portable and language independent, can be used without modification in almost all programming environments
rmuller
  • 10,058
  • 3
  • 50
  • 80
4

Even though the question is old and answered, I'd like to add my 2¢ (which may sound like a rant, but it isn't, it's about limitations and when they become unacceptable).

The goal of a template is to render out something, not to perform business logic. Now there's a thin line between not being able to do what you need to do in a template and having "business logic" in them. Even though I was really positive towards Mustache and tried to use it, I ended up not being able to do what I need in pretty simple cases.

The "massaging" of the data (to use the words in the accepted answer) can become a real problem - not even simple paths are supported (something which Handlebars.js addresses). If I have view data and I need to tweak that every time I want to render something because my template engine is too limiting, then this is not helpful in the end. And it defeats part of the platform-independence that mustache claims for itself; I have to duplicate the massaging logic everywhere.

That said, after some frustration and after trying other template engines we ended up creating our own (...yet another...), which uses a syntax inspired by the .NET Razor templates. It is parsed and compiled on the server and generats a simple, self-contained JS function (actually as RequireJS module) which can be invoked to "execute" the template, returning a string as the result. The sample given by brad would look like this when using our engine (which I personally find far superior in readabily compared to both Mustache and Underscore):

@name:
<ul>
@for (items) {
  <li>@.</li>
}
</ul>

Another logic-free limitation hit us when calling into partials with Mustache. While partials are supported by Mustache, there is no possibility to customize the data to be passed in first. So instead of being able to create a modular template and reuse small blocks I'll end up doing templates with repeated code in them.

We solved that by implementing a query language inspired by XPath, which we called JPath. Basically, instead of using / for traversing to children we use dots, and not only string, number and boolean literals are supported but also objects and arrays (just like JSON). The language is side-effect-free (which is a must for templating) but allows "massaging" data as needed by creating new literal objects.

Let's say we want to render a "data grid" table with cusomizable headers and links to actions on the rows, and later dynamically add rows using jQuery. The rows therefore need to be in a partial if I don't want to duplicate the code. And that's where the trouble begins if some additional information such as what columns shall be rendered are part of the viewmodel, and just the same for those actions on each row. Here's some actual working code using our template and query engine:

Table template:

<table>
    <thead>
        <tr>
            @for (columns) {
                <th>@title</th>
            }
            @if (actions) {
                <th>Actions</th>
            }
        </tr>
    </thead>
    <tbody>
        @for (rows) {
            @partial Row({ row: ., actions: $.actions, columns: $.columns })
        }
    </tbody>
</table>

Row template:

<tr id="@(row.id)">
    @for (var $col in columns) {
        <td>@row.*[name()=$col.property]</td>
    }
    @if (actions) {     
        <td>
        @for (actions) {
            <button class="btn @(id)" value="@(id)">@(name)...</button>
        }
        </td>
    }
</tr>

Invocation from JS code:

var html = table({
    columns: [
        { title: "Username", property: "username" },
        { title: "E-Mail", property: "email" }
    ],
    actions: [
        { id: "delete", name: "Delete" }
    ],
    rows: GetAjaxRows()
})

It does not have any business logic in it, yet it is reusable and configurable, and it also is side-effect free.

Lucero
  • 56,592
  • 6
  • 112
  • 151
  • 13
    I honestly do not see the point of this answer, it doesn't answer the question at all. You say there are limitations without actually describing what they are or how they occur. Finally you launch into a discussion of your own system which isn't available to anyone else, in reality it could suck and might end up one day on thedailywtf but we'd never know. Open source it, link to it and let us decide! – mattmanser Feb 10 '12 at 10:36
  • 1
    @mattmanser, I do write about the limitations that led to not using Mustache (and Handlebars): missing support for paths, predicates, variables, data transformation for invoking partials. Those were all important for us. We'll probably open-source the code some day, but since it is a server-side (or compile-time if you want) solution which compiles the templates to JS code it's not going to have the same big audience as Mustache. If you want to get into touch, feel free to contact me - I'm also the author of bsn GoldParser on Google code (where you can find my email easily in the readme file). – Lucero Feb 10 '12 at 18:39
  • I like the idea of your razor like engine... is it open source? – Cracker Oct 17 '12 at 21:23
  • @Cracker, no, it's not (yet) - the "problem" with it is that currently the templates are compiled to JS code on the server running ASP.NET MVC, and thus the target audience is not as big as with other templating engines. In addition to that, it is part of a bigger library that we first have to take apart for open sourcing it. – Lucero Oct 18 '12 at 00:30
  • Hi, I am wondering what is the ultimate result of `@row.*[name()=$col.property]`? – Esailija Apr 24 '13 at 12:44
  • 1
    @Esailija It allows to dynamically specify property names to be taken from the `row` object, instead of using static names. E.g. if `$col.property == 'Something'` then this would yield the content of `row.Something`. – Lucero Apr 25 '13 at 12:01
  • @Lucero I see, why not have `@row[$col.property]` then though? The reason I am asking is that I am creating similar templating language myself and need to see if I'm missing out on some essential functionality like dynamic property access. – Esailija Apr 25 '13 at 12:21
  • @Esailija, because XPath semantics are followed. The advantage of this is that every variable is seen as a set - it doesn't matter if it is nothing (undefined/null), a single instance, or an array - it always deals with sets. The `[]` is used for predicates (e.g. filtering the set). This makes the query language much less verbose than writing loops, checking values against null/undefined, transforming data, etc. with JS syntax - but a few constructs do get more complicated, the dynamic name property access is one of them. – Lucero Apr 27 '13 at 14:29
3

Here are 3 ways of rendering a list, with character counts. All but the first and shortest one are in logic-less templating languages..

CoffeeScript (with Reactive Coffee builder DSL) - 37 chars

"#{name}"
ul items.map (i) ->
  li i

Knockout - 100 chars

<span data-bind="value: name"/>
<ul data-bind="foreach: items">
   <li data-bind="value: i"/>
</ul>

Handlebars/Mustache - 66 chars

{{name}}:
<ul>
  {{#items}}
    <li>{{.}}</li>
  {{/items}}
</ul>

Underscore - 87 chars

<%- name %>:
<ul>
<% _.each(items, function(i){ %>
  <li><%- i %></li>
<% }); %>
</ul>

The promise of logic-less templates was, I suppose, that people with broader skillsets would be able to manage logic-less templates without shooting themselves in the foot. However, what you see in the above examples is that when you add a minimal-logic language to string-based markup, the result is more complex, not less. Also, you look like you're doing old-school PHP.

Clearly I don't object to keeping "business logic" (extensive computation) out of templates. But I think that by giving them a pseudo-language for display logic instead of a first class language, the price is paid. Not just more to type, but a heinous mix of context-switching somebody needs to read it.

In conclusion, I fail to see the logic of logic-less templates, so I'd say their advantage is nil to me, but I respect that many in the community see it differently :)

Dean Radcliffe
  • 2,154
  • 20
  • 28
2

I agree with Brad: the underscore style is easier to understand. But I must admit the syntactic sugar may not please to everybody. If _.each is somewhat confusing, you can use a traditional for loop.

  <% for(var i = 0; i < items.length; i++) { %>
    <%= items[i] %>
  <% } %>

It is always nice if you can fallback to standard constructs such as for or if. Just use <% if() %> or <% for() %> while Mustache use somewhat neologism for if-then-else (and confusing if you didn't read the documentation):

{{#x}}
  foo
{{/x}}
{{^x}}
  bar
{{/x}}

Template engine is great when you can achieve nested templates easily (underscore style):

<script id="items-tmpl" type="text/template">
    <ul>
        <% for(var i = 0; i < obj.items.length; i++) { %>
            <%= innerTmpl(obj.items[i]) %>
        <% } %>
    </ul>
</script>

<script id="item-tmpl" type="text/template">
    <li>
        <%= name %>
    </li>
</script>

var tmplFn = function(outerTmpl, innerTmpl) {
    return function(obj) {
        return outerTmpl({obj: obj, innerTmpl: innerTmpl});
    };
};

var tmpl = tmplFn($('#items-tmpl').html(), $('#item-tmpl').html());
var context = { items: [{name:'A',{name:'B'}}] };
tmpl(context);

Basically you pass your inner tmpl as a property of your context. And call it accordingly. Sweet :)

By the way, if the only stuff you are interested in is the template engine, use the standalone template implementation. It is only 900 characters when minified (4 long lines):

https://gist.github.com/marlun78/2701678

roland
  • 7,135
  • 6
  • 42
  • 60