Terence Parr is creator of StringTemplate, a Java-based template engine that aims to enforce a strict separation of model and view. Artima spoke with Parr about the newly released StringTemplate 3, and what it means to cleanly separate model from view.
Last month, Terence Parr released StringTemplate 3, the latest incarnation of the Java template engine that aims to strictly enforce the separation of model and view.
While many template engines claim such a separation, StringTemplate is informed by Parr's rigorous research into proving the degree of "entanglement" between model and view in templating systems. Parr is currently a professor of computer science at the University of San Francisco, but as founder and chief architect of the popular JGuru developer site, Parr is no stranger to developers' day-to-day problems.
In an interview with Artima, Parr noted that the need for StringTemplate arose while building the JGuru site:
When we were building JGuru, we went down the JSP path like everybody else, and quickly discovered that we ended up with a [mess]... Some of my developers were putting SQL in the middle of JSP pages, there was nothing but cut and paste, no subclassing, just a hideous Cobol programmer's view of the world. We found nothing but trouble with the JSP templates—we couldn't get separate skins; we couldn't isolate the graphics person from our programmers.
When we threw out that thing and [started over], we went down the opposite extreme, and came up with something very simple—a document with holes in it. As needs dictated, I would gradually increase the power [of those documents] while sticking to my principle of absolutely enforcing strict model-view separation.
I've since talked to a lot of developers, and realized that that's everybody's mantra: thou shalt separate model from view. Unfortunately, it doesn't seem like everybody enforces that, at least in a system capable of generating dynamic Web pages...
Encouraging something is infinitely inferior to enforcing [that thing]. If someone is in a hurry, all of a sudden someone can [do] something in the wrong way. If there is any way to enforce something, then you should do it...
At that time, we feared that [enforcing that] separation would emasculate the power of the template engine. I thought about that for a long time, and realized that it was sufficient to show a direct mapping from the hierarchy of nested templates that would, say, generate an HTML page, show a relationship between that and a parse tree or derivation tree from language theory.
It was then a fairly easy thing to show for me that I can generate any XML file that is describable by a DTD. Aside from all the empirical evidence I have, that gives me an indication that the theoretical argument that you can enforce the separation without emasculating the power of the template engine.
Parr noted some of the rules StringTemplate follows in enforcing a strict model-view separation:
You can compute anything you want [in the view], as long as it's not a function, directly or indirectly, of data that's coming from the model. You can't test the user object to see if that user [is part of the admin group]. You have to compute that in the model. The view only looks at the results of computations. But you can compute everything else in the view - sine waves of the length of an attribute, but not its value. And you can do all kinds of weird stuff in the template, just not [compute] the value of anything.
There is a lot evidence that you don't need [to do] that much stuff in the view. In some cases it's clear, but there are many other cases where I'd argue that that computation needs to go into the model... You can't just multiply things in the view, you can't do array indexing, because that assumes that's something is an integer. What if an ID turns into a String next time? You want to try to isolate as much as you can.
Also, you can't have literals in your code... and you can't have any logic in your templates, like HTML in your code that is then passed in as String to the template... I had to make certain allowances for some convenience. For instance, if you pass in a map, you want to be able to do a key-based lookup... I also allow you to test one value, which is to check if the type is Boolean, because it would be weird to not allow that.
Part of performing view-related computations involves formatting data values, something that StringTemplate supports via renderers:
You can register types and renderers. You can say, render every date object using this other object. Every time StringTemplate is about to convert something to a String, it checks to see if there is a renderer. If there is one, it doesn't call just plain toString(), it passes it off to this object to get a translation.
StringTemplate also allows passing in an object, and accessing properties of that object from the template:
It turns out that if you pass in a user object, being able to access the fields, [while] not essential, is so much more convenient and efficient that I allow you to get properties or fields on an object. That doesn't enforce a particular type, [but] uses reflection to find out if you have the named [the property]. If you don't have one, it just gives you a blank string.
Parr pointed out that an important difference between StringTemplate and other template engines is that StringTemplate enforces the "push" relationship with the model, while other template engines allow a "pull" relationship as well:
My rule is, you must compute everything a priori, and then push the values in [the template], and the template merely operates on those values. In the pull model, by contrast, you're actually pulling something from the model, and that's much more of a programming model than a view.
On some level, everything really is a pull. Even if you give me an integer object, I've got to call toString(). If you made a dependency between the toString() method of any of your other objects [and some other object], then in fact you have created an ordering problem...
If order matters in your template, it's a program. If I can go backwards, and [get] the same values, that's cool. But if the order matters, then clearly you're specifying something as a program. If the view can modify the model, then it's got to be part of the program. If I can insert something into the database, then that's clearly got to be part of the program. The rule is that I generally cannot open up the [the template] for doing computations, otherwise ... when it's three in the morning and people try to get things done by the next day, they're going to do the expedient thing, and all of a sudden all the enforcement goes out the window, and you get a fully entangled spec.
The same thing is true with properties. But when you look at simple properties, it's obvious to the reasonable programmer if you're doing something that's not cool, such as, for instance, inserting something in the database when you call, say, getName(). I'm trying to make it inconvenient, but I can't make it impossible for you to shoot yourself. You can call any method, as long as it has no side-effects, as long as it's just a property.
Parr noted that many characteristics of side effect-free templates were also typical of functional programming:
It turns out that... the need to follow this good programming principle of enforcing separation, leads us to this functional model: the relationship to a parse tree and grammar, the document with holes in it that can reference other documents. In functional languages, the order doesn't really matter. And you can't have side-effects, just as you can't modify the model in a template.. That has a very functional flavor.
Parr admitted that developers coming to StringTemplate from other template engines will need to get used to the new rules:
The biggest difference is you can't do too much logic in the template... There are no for loops, for instance. If you have a list of user objects, or a list of book objects, you just apply the book template, and you get back a list of stuff. It's like a cookie cutter, it pumps out the various elements. But [StringTemplate] handles recursion, so if you pass in a tree data structure, you can walk it using tail recursion, or just recursion in general. You can do hierarchical menus.
StringTemplate Version 3 includes the following new features:
In a previous version, we had something called a StringTemplate group. Groups are an analogue of a grammar. You have a set of templates that mutually depend on each other, recurse, and so forth. So I have a group called Java that specifies how to generate Java from ANTLR, and we have a Python group, and that kind of stuff. Developers kept asking the question of what templates to implement. I borrowed the interface idea from Java, or the protocols from Objective-C, and we realized that we need to have a group interface to enforce the contract [of depending on a set of templates].
There is also a notion of a template region, which is a finer-grained alternative to template inheritance. Instead of having to stick a bunch of holes everywhere just in case you want to override that in a sub-group, it's a way to mark a snippet of a large template, and allow overriding a region in a subgroup.
The other neat thing is automatic line wrapping. With an argument on an expression, you can tell it to wrap, and you can even specify what the wrap character is. You can handle really nasty things like quoting strings in the middle, and still align it, I can do Fortran line wrapping, which has that weird caret continuation character.
To what extent do you agree with Parr's notion that, where possible, it's better to enforce something than just encourage it? And what do you think of StringTemplate's model-view separation?
Another approach is needed that does not involve html, but rather code: the designer should design the web pages in an IDE, the IDE produces the view code (which when it runs, it produces html), and the programmer ties the view code with the model.
I had a look at StringTemplate. It seems to be edging closer to "reality": the Model and Controller are manifest in the database, from which a tool generates the View code.
Ah the View; that fungible, and thus irrelevant, part of the application. The View is supposed to be replacable without affecting, or being affected by, the Model or Control. Kind of the lipstick on the pig. Why Do so many coders get it backwards?
> Ah the View; that fungible, and thus irrelevant, part of > the application. The View is supposed to be replacable > without affecting, or being affected by, the Model or > Control. Kind of the lipstick on the pig. Why Do so many > coders get it backwards?
My theory is 1. They don't really understand what it means to separate the view from the model. They agree that it should be done but they don't understand what they are agreeing to. 2. They don't know how to separate the view from the model.
In reality, I don't think it's possible to 100% completely separate the model from the view. Suppose I said "Create a view. I'll supply the model next week." What are you going to create?
What people need to shoot for is making the model completely ignorant of the view, as you allude to in your post and the view mostly ignorant of the model. I find that the Builder patter (GoF) is the best way to do this. I have used it to create a number of GUIs for the same model (after the model was finished) with little or no modification to the model. It's a little strange for most people to work with but it's much cleaner (no getters and setters.)
<p>To what extent do you agree with Parr's notion that, where possible, it's better to enforce something than just encourage it? And what do you think of StringTemplate's model-view separation?</p>
I think the idea of "enforce" miss the point. You CAN'T enforce anything for a machine I own. You can only make things inconvenient for me - the only "enforce" you get is to make it so inconvenient that doing what you want me to is easier.
I believe in making people do things I want them to by making those things easy for them, and making "bad things" obvious as "bad things". If somebody decide that the tradeoff of doing the "bad thing" is OK with them, then that's THEIR decision. They are the ones on the spot, they are the ones with knowledge about what is going on. What's appropriate for me as infrastructure developer is, in my opinion, to make the things I think will be good for them easy, and the things I think will be bad for them obvious - and possibly slightly more inconvenient for them to write because I want it to be obvious what they are doing.
However, "enforcing" that they don't do "bad things" presumes that my judgment is much better than their judgement - so much better that I, sitting a thousand miles away and not having any idea of their specific situation, should decide what they "can" and "can't" do. I'm not quite that conceited...
.... I'm totally in love with the line wrapping feature. Finally, there is a template language that allows me to generate code that looks like I've coded it myself. It may not make any difference once its compiled, but it just feels so much better....
> James, I'm interested in your experiences with the Builder > pattern. Was your approach influenced by Allan Holub's > articles? e.g. >
Invoking the name of My Hero. I read the CF article, but he makes the same "error" that all (so far) the objecters make: the assumption that Beans are the point of design. If one takes the Beans Are The Way point of view, then getter/setter becomes a circular argument among folks shooting past each other.
Read Holub's series on the Bank of Allen, also in javaworld IIRC. The most cogent short essay on OO I've ever seen. Given what has happened to java/OO since then, the impedence mismatch, and desire to get along in the coding world may make designing in that way impossible. But such doesn't change the truth of what he says. Kind of like WMD.