In The Sad Tragedy of Micro-Optimization Theater we discussed the performance considerations of building a fragment of HTML.
string s =
@"<div class=""action-time"">{0}{1}</div>
<div class=""gravatar32"">{2}</div>
<div class=""details"">{3}<br/>{4}</div>";
return String.Format(s, st(), st(), st(), st());
The second act of this particular theater was foreshadowed by Stephen Touset's comment:
The correct answer is that if you're concatenating HTML, you're doing it wrong in the first place. Use an HTML templating language. The people maintaining your code after you will thank you (currently, you risk anything from open mockery to significant property damage).
The performance characteristics of building small string fragments isn't just a red herring -- no, it's far, far worse. The entire question is wrong. This is one of my favorite lessons from The Pragmatic Programmer.
When faced with an impossible problem, identify the real constraints. Ask yourself: "Does it have to be done this way? Does it have to be done at all?"
If our ultimate conclusion was that performance is secondary to readability of code, that's exactly what we should have asked, before doing anything else.
Let's express the same code sample using the standard ASP.NET MVC templating engine. And yes, we render stuff like this all over the place in Stack Overflow. It's the default method of rendering for a reason.
<div class="action-time"><%= User.ActionTime %></div> <div class="gravatar32"><%= User.Gravatar %></div> <div class="details"><%= User.Details %><br/><%= User.Stuff %></div>
We have a HTML file, through which we poke some holes and insert the data. Simple enough, and conceptually similar to the String.Replace version. Templating works reasonably well in the trivial cases when you have an object with obvious, basic data types in fields that you spit out.
But beyond those simple cases, it's shocking how hairy HTML templating gets. What if you need do to a bit of formatting or processing to get that data into shape before displaying it? What if you need to make decisions and display things differently depending on the contents of those fields? Your once-simple page templates get progressively more and more complex.
<%foreach (var User in Users) { %>
<div class="action-time"><%= ActionSpan(User)%></div>
<% if (User.IsAnonymous) { %>
<div class="gravatar32"><%= RenderGravatar(User)%></div>
<div class="details"><%= RepSpan(User)%><br/><%= Flair(User)%></div>
<% } else { %>
<div class="anon">anonymous</div>
<% } %>
<% } %>
This is a fairly mild case, but you can see where templating naturally tends toward a frantic, unreadable mish-mash of code and template -- Web Development as Tag Soup. If your HTML templates can't be kept simple, they're not a heck of a lot better than the procedural string building code they're replacing. And this is not an easy thing to stay on top of, in my experience. The daily grind of struggling to keep the templates from devolving into tag soup starts to feel every bit as grotty as all that nasty string work we were theoretically replacing.
Now it's my turn to ask -- why?
I think existing templating solutions are going about this completely backwards. Rather than poking holes in HTML to insert code, we should simply treat HTML as code.
Like so:
foreach (var User in Users)
{
<div class="action-time">[ActionSpan(User)]</div>
if (User.IsAnonymous)
{
<div class="gravatar32">[RenderGravatar(User)]</div>
<div class="details">[UserRepSpan(User)]<br/>[UserFlairSpan(User)]</div>
}
else
{
<div class="anon">anonymous</div>
}
}
Seamlessly mixing code and HTML, using a minumum of those headache-inducing escape characters. Is this a programming language for a race of futuristic supermen? No. There are languages that can do this right now, today -- where you can stick HTML in the middle of your code. It's already possible using Visual Basic XML Literals, for example.
Even the hilariously maligned X# has the right core idea. Templating tends to break down because it forces you to treat code and markup as two different and fundamentally incompatible things. We spend all our time awkwardly switching between markup-land and code-land using escape sequences. They're always fighting each other -- and us.
Seeing HTML and code get equal treatment in my IDE makes me realize one thing:
We've all been doing it wrong.
Ever heard of it?
XSLT on February 5, 2009 7:11 AMMartin Fowler hates XSLT too
http://www.codinghorror.com/blog/archives/000333.html
Jeff Atwood on February 5, 2009 7:14 AM"In The Sad Tragedy of Micro-Optimation Theater we discussed"
Optimization you mean, Jeff? Sorry, didn't mean to nitpick, but I thought you'd might want to be aware of that one.
Mike on February 5, 2009 7:29 AMEver poked into coldfusion? It's the closest I've seen to treating html & code as the same thing- Actually, most CF commands are in the form of markup tags, so the way to assign "x = 4" is <cfset x=4>. Pulling variables within your HTML is as easy as adding surrounding pound signs (modified to square brackets): [h1]The value of x is #x#[/h1].
Alex on February 5, 2009 7:30 AMGenshi templates embed Python code into XML.
Example:
<py:for="User in Users">
<div class="action-time">${ActionSpan(User)}</div>
<py:choose test="User.IsAnonymous">
<py:when test="True">
<div class="gravatar32">${RenderGravatar()}</div>
<div class="details">${UserRepSpan()}<br/>${UserFlairSpan()}</div>
</py:when>
<py:otherwise>
<div class="anon">anonymous</div>
</py:otherwise>
</py:choose>
</py:for>
yeah I absolutely agree!
There just is no way to separate HTML and Code completely. It's an illusion. Everybody knows that.
Then people come up with crazy complicated template meta languages, which aren't really keeping thing simple. So yeah, mixing code and HTML, best thing to do. Producing code and classes that makes sence.. always better than obey Mr. You-CANT-do-that-Design-Pattern, just for the sake of it!
You can simply ignore HTML and do everything in code.
Have a look at Seaside (http://www.seaside.st) a mature web framework in Smalltalk. Its HTML generation is very elegant et very convenient.
Are you saying that HTML is wrong?
Josh Stodola on February 5, 2009 7:43 AMTAL seems to get close, as a templating language which is really just code (or really, it turns the template into code). http://wiki.zope.org/ZPT/TALSpecification14 - though the spec is somewhat cryptic as EBNF type specs tend to be. Its been implemented in a few different languages, like php http://phptal.motion-twin.com/
Anyway, instead of defining a wholely different syntax, it uses xml namespaces to provide programming structures - letting you write 100% valid XML. You can even insert 'placholder' text/elements which get replaced by the template, so the page will render full HTML without the templating engine.
There's currently a 'backlash' in the PHP community against templating engines - reason being, PHP is sort of a templating engine in itself, given the right setup. Most of the MVC frameworks make it so that you cant do too much 'dangerous' stuff in the templates because they're in a limited scope, but if you still don't trust the template writer (maybe because its part of some CMS), a template engine is needed just to protect the system from 'real' code. Template engines in PHP were mostly designed before MVC became possible (pre php4) to still give code/display separation.
Jystin on February 5, 2009 7:48 AMIsn't the idea to mix the HTML and code together just reinventing old style ASP? Wasn't that complained about precisely _BECAUSE_ of the mixing of code and markup?
There is no perfect answer other than to try to make your code and markup as clear and straightforward as possible.
Jeff Cuscutis on February 5, 2009 7:49 AMXSP[1] was doing that around a decade ago. For my money it's represents too little layering. I don't want code belonging to an application fiddling about with HTML tags.
[1] <a href="http://en.wikipedia.org/wiki/EXtensible_Server_Pages">http://en.wikipedia.org/wiki/EXtensible_Server_Pages</a>
Tom Hawtin on February 5, 2009 7:51 AMThe best (tm) way to render HTML within languages is to define functions, I think. Here an example in Perl (also possible in Ocaml, C, Python, Java...):
sub a {
my $url = shift;
return "<a href="$url">, @_ , "</a>";
}
..
#render it
render(
html(
head( ..#headoptions
),
body(
a( "http://codinghorror.com", $text ), #...
)
)
);
this approach works in nearly all languages and if the functions encapsulated in a generic html library, all is fine.
art1 on February 5, 2009 7:54 AMwhy not do everything you need to in code, then poke the data into the html?
John Ferguson on February 5, 2009 7:55 AMI absolutely hate embedded code in HTML. And XSLT is about as write-only as APL or bad perl.
Ruby on Rails has the delightful haml (with its CSS sister, Sass) which does a reasonable job of DRYing up some opf the nastiness. I believe there's a .Net equivalent (http://andrewpeters.net/2007/12/19/introducing-nhaml-an-aspnet-mvc-view-engine/) but I don't know how mature it is. OK, there's a need to accept Python-like (pythonical?) Significant White Space, but who doesn't indent these days?
It's the best solution I've seen so far, actually not a horrible experience, unlike the vanilla embedded alternative.
Mike Woodhouse on February 5, 2009 7:56 AMIf you're using ASP.NET MVC, then they have a cool feature where you can replace the default ASP.NET template engine with one of many alternate ones that are developed by third parties and Open Source project groups. They do much of what you think is the ideal. Some of the more notable ones are:
- <a href="http://dev.dejardin.org/trac/spark">Spark</a>
- <a href="http://code.google.com/p/nhaml/">NHaml</a>
- <a href="http://www.castleproject.org/MonoRail/documentation/trunk/viewengines/brail/index.html">Brail</a>
> It's already possible using Visual Basic XML Literals, for example.
The earliest web-specific programming languages like PHP embedded the code within the HTML, though this left you with entirely unstructured snippets of code scattered about. I guess we've come full circle to embed the HTML into the code.
Denton Gentry on February 5, 2009 8:00 AMOr use HAML. Took me some time to get used to it… now I love it!
http://haml.hamptoncatlin.com/
Or you could add your strings in as labels and use repeaters. You know, the way you're supposed to do it with .Net web forms. Your propsed solution brings back the horrors of the worst PHP and ASP designs.
bob on February 5, 2009 8:01 AMwicket is does something fairly similar to what you are talking about jeff if you can stomach java...
Wow i misspelled my name in the last post? Must be too early.
@art1 - defining functions that 'render' HTML is probably the most horrid thing ever. Its totally unmaintainable, and diverges so far from the actual representation that you're ensuring that nobody but you will ever really know whats going on. Plus, what happens when your function doesn't support all the attributes you want to use? How might you add XFN notation? Its just not viable. I'd go with string replace/concat WAY before thinking about functions like that.
Justin on February 5, 2009 8:02 AMIf you'll excuse me, I must make a comment about the following sentence "Templating tends to break down because it forces you to treat code and markup as two different and fundamentally incompatible things."
See, I feel that you are simply turning the tables here: Instead of breaking from HTML-land to code-land, this method would make you break from the code-land to HTML-land. Actually, if you add some quotes and braces and semicolon, and what you've got on your hands is the traditional way of producing a webpage in PHP.
I won't go into further details, but I have also objections concerning (X)HTML-validation and also parsing the whole thing (e.g. getting something that could be interpreted as code, output to the resulting document).
On the other hand, I'm always up for diversity. If someone implements this 'backwards templating' in a successful way, I might as well adopt it. It's a no-lose situation for me :)
Henrik Paul on February 5, 2009 8:07 AMI mostly agree with art1. You've already lost at the moment you start mixing HTML and logic or content. (exluding the wrapper functions)
Ideally though, enclosing HTML tags would be code blocks, rather than functions. That way, an error in a link doesn't report from body(). Each tag would have its own scope as well.
Actually, that sounds like something that would be interesting to try to implement myself...
Ryan Fox on February 5, 2009 8:08 AM@art1, you've just reinvented <a href="http://search.cpan.org/dist/CGI.pm/CGI.pm">CGI.pm</a>. eek.
Justin Mason on February 5, 2009 8:09 AMOne proofreading comment, you got the then and else blocks of User.IsAnonymous reversed (in both cases). As for the VB.NET example, could you change it to do the same as the previous examples?
Motti on February 5, 2009 8:09 AMheh. http://search.cpan.org/dist/CGI.pm/CGI.pm
Justin Mason on February 5, 2009 8:09 AMwhy not keep the HTML template simple and prepare your data for view before sending it to be rendered? then all you really need are simple to read iterate and placement tags. I primarily work with Java/Jsp and cringe each time i see a view with complex formatting logic.
BTW long time reader first time poster, great site thanks!
meatpopsci on February 5, 2009 8:11 AMNHaml clears up a lot of the ugliness of templating. While it doesn't fix everything, I think it clears up a lot.
And if you use ASP.NET MVC, using HtmlHelper extension methods + NHaml allows you to treat those tricky templating problems as code problems.
http://andrewpeters.net/2007/12/19/introducing-nhaml-an-aspnet-mvc-view-engine/
Brian Hartsock on February 5, 2009 8:12 AMAm I the only one who spotted what's really wrong with this picture?
if (User.IsAnonymous)
{
(render gravatar)
}
else
{
(print "anonymous")
}
Either User.IsAnonymous returns a counterintuitive result or the if/else cases are backward...
Sebastian on February 5, 2009 8:12 AMThis is the one thing that they actually got right in VB.NET and horribly wrong in C#. I don't understand why XLinq had to be so ridiculously cumbersome when they were able to take care of DLinq so beautifully.
Oh, and:
>> Jeff Cuscutis: "Isn't the idea to mix the HTML and code together just reinventing old style ASP? Wasn't that complained about precisely _BECAUSE_ of the mixing of code and markup?"
XML Literals in VB.NET actually compile into DOM objects, so many of the old problems like lack of type safety or escaping don't apply here. You can see what's under the sheets by looking at the useless way C# implements Linq to XML.
Also, the problem with classic ASP (or ASP.NET without code-behind) wasn't just related to separation of concerns. There's a subtle difference between mixing data into code and mixing code into data. Think of a layered drink - if you start with the heaviest ingredient, you get a perfect rainbow, but if you start with the lightest, you end up with a muddy mess.
Aaron G on February 5, 2009 8:13 AMI have a custom templating system I use with only the following commands:
output variable, foreach loop, if/else (with only if x and if x == y), and include file.
The way I see it, if you are using more than that in your template, you are doing something wrong in your code.
Furthermore, my code which lets you set template variables escapes all HTML sent to it, forcing me to actually stick to putting all the html in the template where it belongs.
Beats the hell out of every bizarre combination of code/html I've ever seen.
The reason for using templates is to allow designers (non-coders) to work and modify them.
There are several templating options that are parseable html with reasonable defaults.
Mako ( http://www.makotemplates.org/ ) also works that way, and is the best templating language I've ever used. It also has cool features like inheritance (that don't really make sense until you read up on them and use them, and then they're great) and "function" definitions within the templates.
-Max
Max Kanat-Alexander on February 5, 2009 8:15 AMFWIW, what little HTML generation I do these days, I do using Linq to Xml, producing XHTML. It works very well for me; and I don't think that the way C# implements it is "useless". My streams of data to be inserted are in the form of IEnumerable instances. The fact that what would otherwise be "repeaters" can be trivially abstracted as methods, and other familiar code-oriented idioms - including view inheritance - adds up to quite an advantage for the developer trying to produce some output.
Re designers, it's probably best to try and produce a well-defined hierarchy of divs etc. with appropriate classes and ids, and let the designer style them via CSS.
Barry Kelly on February 5, 2009 8:21 AMThat's taking a step backwards, surely?
Stage 1) Learn HTML. <p>hello world</p>
Stage 2) Stumble around in PHP. <p><?=$message;?></p>
Stage 3) Learn templating. <p>{VAR:message}</p> and strreplace()
Stage 4) Mix template and code?
Is stage 4 not identical to stage 2? What's the practical difference?
I have two types of markers in my home-brew templating system, one for variables and one for looping/switching. The template class is recursive, and I can do anything in the above examples without abandoning the principles that made me switch to stage 3 in the first place... ie, I can give the template only to the designers without them borking the code, and they can see it rendered in a browser without needing it to be parsed by the PHP. What am I missing?
(forgive any layout issues/missing examples - I'm assuming the big red 'no HTML' means that it'll be converted to HTML entities rather than removed and if I'm wrong, meh, read the text :) )
Schmoo on February 5, 2009 8:22 AMI think that one missing point is DRY: Having templates handling the HTML, even if it's a mess of spaghetti code, leaves the "html building" functions in just one place.
As for the "uglyness" of the logic/conditionals/iterations mixed with the HTML, I see the point there, one elegant solution is the one propose here, and implemented in Haml: http://haml.hamptoncatlin.com/
Angel on February 5, 2009 8:29 AMI'm not sure intermingling html with code is all that much better than intermingling code with html - even if it's native in the IDE. Most solutions seem to amount to some bastardized balance of the two - usually with an added syntax (new tags, comments for vars and loops, etc). Namespacing like TAL seems interesting, but there's still an entire set of added syntax.
It's always seemed to me that the most ideal HTML template would be entirely based on HTML itself, using classes and ids - or better yet, selectors a la jquery or prototype, where you would have something like:
<?php
$aOutput= array(
'employees' => array(
array(
'employee' => array(
'name' => 'Joe',
'age' => 30
)
),
array(
'employee' => array(
'name' => 'Sue',
'age' => 25
)
),
)
);
$oTemplate->load('employees.html', $aTemplate);
?>
And then your template would look something like:
<div class="employees">
<div class="employee first">
<b class="name"></b>
<span class="age"></span>
</div>
<div class="employee odd">
<b class="name"></b>
<span class="age"></span>
</div>
<div class="employee even">
<b class="name"></b>
<span class="age"></span>
</div>
<div class="employee last">
<b class="name"></b>
<span class="age"></span>
</div>
<div class="employee last even">
<b class="name"></b>
<span class="age"></span>
</div>
<div class="employee last odd">
<b class="name"></b>
<span class="age"></span>
</div>
</div>
The loops would be handled automatically. The extra classes (even, odd, first, last) would only show for meta information, so for the first iteration, it would show the "first" div, and so on. If "employees" were empty, it wouldn't parse the div. All conditions would be handled in the code that generates the $aTemplate array.
I started this endeavor a couple years ago and did alright using the horribly documented PHP DOM Objects, but never found the time to take it very far. At the very least I had the implied loops and meta conditions working.
Mark Armendariz on February 5, 2009 8:35 AMIf you are using css for all the styling then the html is just the data layout and so should be in code.
The objections to html in code are from back in the day, when you had to check through 1000s of lines of C++ to find out why a font was changing or call in the programmer to change a background color.
Jeff, if you've got ASP.NET code that looks like this:
<%= RepSpan(User)%><br/><%= Flair(User)%>
I think the real question is: why aren't you using ASP.NET custom controls? They're not terribly difficult to develop, and once you've got them they're a lot more consistent with the rest of your ASP.NET site:
<so:Flair runat="server" id="userFlair" />
Then during your databinding handler you simply assign the user to your userFlair object via a property. You could even databind it declaratively:
<so:Flair runat="server" id="userFlair" User='<%# Eval("User") as User %>' />
The same thing goes for the user's gravatar, action, reputation. Obviously, writing the custom control means you're going to have to write HTML procedurally. But the benefit of using an OO language behind ASP.NET is that you're going to be able to hide the details of it - once you've created your Flair control, you don't need to even acknowledge its presence except declaratively. There's no special call to a parent's RenderFlair() method. It's encapsulated inside of its own bubble of awesome. ;-)
Rob Paveza on February 5, 2009 8:35 AM(apologies for the typo, $aOutput should be $aTemplate)
Mark Armendariz on February 5, 2009 8:37 AMAgain, I think HAML is doing it wrong too. Why would you want to generate a language that looks NOTHING like the intended output if you can get away with it?
In 'real world' situations, you are likely going to work with a graphic designer, or 'UI' focused developer who doesn't know your backend language very well. They are NOT going to write HAML. They're going to write HTML (or generate it in goLive or something). HTML/XML based languages (wether its TAL or inserting language tags <% %> or <?php ?>) then becomes somewhat trivial. I guess there is the 'html2haml', but then you'll get a change from the designer and have to redo it.
Its sort of bugging me that just in this small discussion scope, there is a lot of solutions that are quite anti-diverse-team. If you're getting far enough from both the likely input and likely output that you need a translator, you're doing something wrong.
I don't expect the designers to learn to write HAML, or even much PHP other than simple things, and I'm not going to have the time to teach them. The quicker they get work done, the quicker I can get work done.
Justin on February 5, 2009 8:43 AM"Rather than poking holes in HTML to insert code, we should simply treat HTML as code."
No thank you.
asdf on February 5, 2009 8:46 AM@Mark Armendariz: Take a look at TAL - it is essentially doing exactly what you're talking about, without potentially mucking with intended output classes, etc.
I know I sound like a super-advocate of it, but I just find it the perfect blend of code and xml display - it forces you to write good XHTML too! Sadly, I've only used it in one of my personal projects, and never in a big site, so I can't tell you how it is 'at scale', but it does do template compilation and caching, so it'd be no worse than most of the other templating languages.
It came from the Zope project, and is available as modules for other languages. http://en.wikipedia.org/wiki/Template_Attribute_Language
Justin on February 5, 2009 8:47 AMAll code, including HTML, is just code. Using templates lets you refactor the HTML out of your main programming language. It also limits the amount of damage designers can do when they poke around.
The point isn't to use/don't use templates. The point is to use whatever works for you, preferably the simplest possible method.
BTW, while I can't be bothered to care about all the PHP-hating amongst proponents of lesser languages ;), it's worth noting, that it's by far the most popular server-side scripting language, and it's been so for many years now. Don't dis the language because _you_ suck at it :)
MichalT on February 5, 2009 8:48 AMOh God, several dozens of comments and no-one mentioned Lisp yet. Just look at how cl-who works and be enlightened.
rassie on February 5, 2009 8:50 AMThat it is a good idea not to distinguish code from data has been known for a very long time. Kind of way back to the Lisp-days...
JesperE on February 5, 2009 8:51 AMHow is your suggestion any different than what is currently accomplished with PHP? Is adding XML structural validation the only advantage?
php? on February 5, 2009 8:52 AMTemplating languages handle the important task formatting the output. For example, XSLT handles aspects such as encoding, content type, and indenting. While most templating languages focus on allows small manipulations in the content, the big win is having a reliable layer that translates the programming language data into actual content. As Americans, this is pretty tame since our programming languages are effectively English. But, when you consider other languages, a templating language and layer is the only way you can handle the disjoint between programming data and actual content.
Eric Larson on February 5, 2009 8:52 AMA lot of people have shown ways to include code in the markup. PTL ("Python Template Language") does what Jeff illustrated with Visual Basic XML Literals and puts the markup into the code. Not quite as slick as XML literals but pretty close, and it's been around since 2002.
http://quixote.python.ca/quixote.dev/doc/PTL.html
Another templating approach is taken by the Meld family, which injects Python code into an existing vanilla-HTML template in a way similar to javascript's DOM manipulation:
Ian Jones on February 5, 2009 8:55 AMThat's exactly what Seaside (www.seaside.st) does (indentation will probably be lost):
renderContentOn: html
html table
id: self ajaxId; class: 'report';
with: [ self renderTableOn: html ]
This generates:
<table id="theAjaxId" class="report">
...(the result of [self renderTableOn: html] goes here)...
</table>
Awesome awesome awesome. THATS exactly how it SHOULD be and I agree with the one commenter who mentioned coldfusion's been doing it right for a long time.
One of your best articles.
craig on February 5, 2009 8:57 AM@anonymous (08:13 AM):
Sounds like you are describing StringTemplate (http://stringtemplate.org/).
I recently reviewed my options for generating HTML in Haskell (http://blog.uncommons.org/2008/12/03/generating-html-with-haskell/). Haskell Server Pages does a good job of the HTML-as-code approach, but I ultimately dismissed it in favour of the Haskell port of StringTemplate.
Mixing logic and presentation mark-up in one place rarely ends well.
Dan on February 5, 2009 8:58 AMJeff, as others have said before, this is no different from the PHP/Jurassic ASP code-in-html soup which we've been struggling to get OUT of for the last so many years...
shash on February 5, 2009 8:59 AMExcellent post Jeff. This is a great observation that you've come up with that could make ASP.NET MVC at least somewhat palatable for me. The big problem though is the developer has to maintain all the state of the controls in MVC unlike ASP.NET web forms where its all maintained in the viewstate if I recall correctly. That's why I dislike MVC (plus no designer support) and because of at least one more reason:
"The three chief virtues of a programmer are: Laziness, Impatience and Hubris."
-Larry Wall
i agree
theman on February 5, 2009 9:03 AMWhen I start to run into problems like the one you've hit, it's usually a sign that I'm Doing it Wrong. Everything in a template needs to resolve to either:
* Another template
* A variable
* A function in code that spits out HTML (last resort, do not use without breaking glass)
Everything else is markup.
As soon as you start using JSP tags to do conditional statements, for example, you are creating a black hole that will shortly consume the sun.
asdf on February 5, 2009 9:14 AMIn Scala you can also mix HTML and code, just like in your example.
Joe on February 5, 2009 9:18 AMI hear that Asynchronous JavaScript and HTML is handy for this type of thing.
*takes tongue out of cheek*
Vance on February 5, 2009 9:35 AMI would agree that there is no way to separate code from html.
Code in html of html in code, there is still a problem.
The whole concept is a messy, unclean design.
If the criteria used to decide what belongs in what is how messy it looks (instead of higher level architecture or design), the technology is flawed.
Add here another layer (let's say localization, where you should have localizable stuff in a 3rd place) and you realize this is a junk technology held together with duck-tape (and this also applies to JSP, PHP, ColdFusion and all the other technologies in this family).
I must agree with the templating problem. After developing in “classic” ASP for what seems forever, using ASP.NET to seperate the content seemed nice. The main problem we had was that we work on a local government site in the UK which is inspected annually for various things (including markup and accessiblity). For us it is very important to pass this inspection, and as the standard .NET controls do not produce standard XHTML code, I went with XSLT to produce all of the markup.
I know that XSLT can make hard things easy, but can also make easy things hard (it not being procedural and all), so to solve this problem, I pass into the XSLT a compiled C# library with some common functions written in C# which can be called directly from the XSLT. And for any bespoke functions for a page, you can create C# functions directly in the XSLT.
Combine the above process with master pages, ASP.NET caching and the result is speedy, compliant pages.
1. execute code which calls db via sql
2. output into html
we're using an intermediary language to connect two completely different languages. does this make sense *at all*? the whole paradigm is broken and its not only the presentation layer.
Ivan on February 5, 2009 9:46 AMStringTemplate (http://stringtemplate.org/) is another approach aimed at avoiding a mix of code and target text - you effectively define the template as a mirror image of a parser and (behind the scenes) tell the template engine how to resolve names.
+1 for Haml. It's not for everyone, but it sounds like you are ready for it. Seriously. Check it out. It is available for many for many frameworks.
Daniel on February 5, 2009 9:50 AMGenerating HTML is like having a compiled language and then including assembler in the source code, yes you can do it, yes sometimes it is required, but you should not have to....
Either take a step away from HTML and use a language powerful enough so that you never have to see HTML ever again, and let the HTML generator in the language do the work .... or put up with one of the compromise solutions above
HTML is for laying out text, it had been stretched to do more and more and should now be either dumped for something better or hidden away as something people no longer look at (like machine code)
Jaster on February 5, 2009 9:55 AMAs wise commenters before me have said: A templating language is the answer.
Your examples are weak. There is no conceptual difference between your 1st tag based and your 2nd code based example. Lets replace the foreach loop with a... foreach loop!?
Your argument is the code based one is cleaner? Get a clean templating language then... there are plenty out there. XSLT is not one of them.
The point of of templating is division of labour, You don't want to give a designer/javascripter capable of writing simple templates with loops a whole programming language to shoot himself in the foot with. Also way easier to compile and give meaningful errors if you remove everything except looping constructs, and filter operators that do stuff with the data supplied to the template like... sanitize, enumerate, slice, paginate, translate, uppercase, lowecase, capitalize, date format, time format, unit conversion.
Are you both doing templates and back-end programming? Do whatever you want. Just make sure you charge enough to put a designer through programming school should you ever need one to work on your templates.
monowerker on February 5, 2009 10:10 AMMotti and Sebastian called it: You've got the then and else blocks reversed in both examples.
And, do please update the Visual Basic XML Literals example to do the same anonymous user display task as the previous examples.
Zack on February 5, 2009 10:21 AMCan you create custom MVC UI Helpers?
<%=Html.Image("~/images/baseball.jpg")%><br />
Would your Visual Basic XML Literals example match up to one of those?
Zack on February 5, 2009 10:22 AMTake a look at the Spark View Engine. Code + Html all in one.
www.sparkviewengine.com
Donn Felker on February 5, 2009 10:29 AMDo you really want to have to recompile the entire Web site when a designer just wants a class name diddled with?
I've always thought that building HTML strings directly in code is impractical for certain kinds of environments where you have a designer/developer split.
And I guess NHaml is cool, but I don't really see the point. If I'm outputting HTML, and I'm having to do all sorts of weird hacks to get things to render consistently in Firefox/Opera/Safari/IE6/IE7/IE8, why don't I just write HTML directly? The last thing that I want is to have to compile and run my template just to see what magical HTML it has output. Oh no--it spit out a line break after that tag, but IE6 renders an incorrect line-height if there's a space there--how do I get around that? I guess I'm just being old-fashioned, but people tout NHaml for its simplicity, but I just don't see how adding another level of indirection to HTML generation makes things simpler.
The processes that we invent just to emit a string to a browser is sometimes amazing.
Nicholas Piasecki on February 5, 2009 10:37 AMYou might dislike java, but JSP 2.0 w/ JSTL (when used in a proper MVC approach) is wonderful. For example:
<c:forEach items="${users}" var="user">
<div class="action-time">${user.actionTime}</div>
<div class="gravatar32"><${user.gravatar}</div>
<div class="details">${user.details}<br/>${user.stuff}</div>
</c:forEach>
It can get uglier when you start doing a lot of if/elses, but you can create your own tags (in a separate file) so you could have:
<c:choose>
<c:when test="${user.anonymous}">
anonymous
</c:when>
<c:otherwise>
<div>${user.details}</div>
</c:otherwise>
<c:choose>
and then just call <someLibrary:displayUser user="${user}" /> in the loop.
When set up properly, it'll even validate as XML.
Jason on February 5, 2009 10:43 AMAnd now, for the 378th way to skin the cat...
Practicality on February 5, 2009 10:44 AMThere are a few problems that I see with this idea of having no distinction between code and HTML:
1) Maintaining a good separation between view code and controller code requires more effort than slapping everything together. While I love me some PHP, that's one of its warts.
2) Web designers complicate the picture. If you've got a workflow where the web designers are expected to deal with the templates directly, then you want a very minimal amount of code in the template. In the example with the functions doing "helper" rendering, I don't see why you couldn't replace them with special read-only properties on the code-behind's class that does the dirty work there. That gets you back to the original ASP.net example.
3) I don't see how this is inherently better than ASP.net's templating. Again, my inclination is to try to keep the view code seperate, and doing that with your system still means doing something very much like ASP.net templating.
4) This would be a not-insurmountable implementation problem, but the idea of mixing server code with client HTML feels wrong from a security standpoint. It would have to be implemented in a way that there is still no ambiguity as to what is run on the server and what is run on the client. *That*, IMHO, is the main driver the current separation between code and HTML.
DEAR LORD NO.
Why do you separate HTML and CSS? Because document structure (HTML) should be separate from document style (CSS). For a lot of reasons I won't list here, because anyone reading this comment should already know them.
Many of the same things apply when you talk about keeping code and HTML separate. If you're finding that you're doing more than a few simple loops inside your template, then you're probably doing it wrong.
Example:
<%foreach (var User in Users) { %>
<div class="action-time"><%= ActionSpan(User)%></div>
<div class="<%= UserInfoClass(User) %>"><%= UserData(User) %></div>
<% } %>
You then have UserInfoClass() return the class needed, and UserData() return the needed *snippet* of markup to go in the DIV.
Ideally, you'd do this latter through simple nested template so that *no* HTML was in your code proper.
Darren on February 5, 2009 10:58 AMTreating HTML or XML as a big string or text stream or file or whatever is Doing It Wrong. It's an easy tree. Declare a bunch of objects, let them figure out how to output text to a TCP socket or to a file or whatever.
Reed on February 5, 2009 11:00 AMThe current version of ECMAScript also supports inline XML, almost identical to what you describe (they call it E4X); it works in Firefox 3, and also in ActionScript, the language used by the Flash player. For example, try this in Firefox 3:
<html>
<head> <script>
function gethtml(name) {
return <p>Hello, <b>{name}</b></p>
}
</script> </head>
<body>
<button onclick="document.write(gethtml('Jeff'))">click here</button>
</body>
</html>
I think the best circumstance is to just have the designers write html, since that's what they can handle, and then they can give it to you and you make it actually work.
The language you prefer to use to add the actual content is an issue of preference, a BIG preference, but the idea that any of them are the best is silly. They all have too many problems to be the best.
Practicality on February 5, 2009 11:06 AMYou're still "doing it wrong", since you are NOT ESCAPING THE GOD DAMN TEMPLATE SUBSTITUTIONS. Someone sticks a script in one of the input paths you forgot to validate and your users are fucked.
Ironically, XSLT solves this problem (unless you concatenate XML, too, instead of using DOM, XLinq or XmlTextWriter to write the "data" XML).
DMB on February 5, 2009 11:08 AM@Darren, Mike Mohearty
Both of yours' and just about everyone else's "solutions" I've seen so far still all look like the original tag soup Jeff started with. The thing is that Jeff's latest example eliminates the tag soup property but your solutions don't.
We (Python devs) have been there, tried that (with HTMLTemplate or ll-xist). This does not work, at least as expected. Having this knowledge, some smart persons invented extensible templating systems, like Jinja and Jinja2 and - of course - Django template language. Smart and to the point.
zgoda on February 5, 2009 11:27 AMWhat if you remove the gap between template engines and code?
What if your "template engine" actually was the code?
What if your database backed programs were so easy to build they would require almost no "real" code at all?
What if all of this could be done so easily it would take anyone with a fairly basic experience in HTML a 2 hour training to be able to extend an existing codebase?
Enter Makumba, a super cool JSP tag library that makes web development as easy as childs play: http://www.makumba.org/
----
The solution provided by Makumba is the one I personally enjoy the most. You have a really capable industry standard JSP-based system. Add on top of it a layer of database and query language abstraction with access through a few tags... And you can build a real working website in days, even hours.
Check it out or and/or contact me for more info :-).
HAML ftw =) Looks extremely strange to start off but once you start to use it, you'll soon discover the benefits. It'll make sure all the html code you want it to generate is semantic. +1
Nathan Bertram on February 5, 2009 11:34 AMThe only diff between the template approach and what you advocate is "<%, %>" and "{,}"
not much different really. Would be nice to drop the <% tags, but I don't think they are a big issue. Bigger issue is just being smart about keeping as little code in your templates as possible. Push complexity into your method/class calls.
I find the people who think you shouldn't have ANY code in your templates amusing. Usually they advocate special tags that map to code. So it's the same thing except the tags are limited in their use and have angle brackets around them. Waste of effort.
phil swenson on February 5, 2009 11:43 AMreminds me of the 'cityscript' language from citydesk.
work on the principle you have more text that markup, so instead of using markers for the text, use them for the markup..
wrote my own version of the language, since I wanted to do a few other bits for a report writing engine.
you end up with a simple template, and a recursive language to populate it.
the end user sees exactly what they wrote, and can add simple bits like {$publishdate$} etc.
oh and you can insert php etc as well.
very def 'meware' though
Claire Rand on February 5, 2009 11:57 AMGet rid of asp.net, use wicket
Oğuzhan on February 5, 2009 12:31 PMI find it interesting that nobody's mentioned XQuery yet. I've worked with numerous languages and technologies over the years, and when it comes to outputting HTML, or any type of *ML for that matter, I always seem to find myself wanting to work with the eXist database engine again. It always makes so much sense for the web:
- its document-centric from storage to output. You store an XML document in a directory-like structure. You can retrieve that document, a fragment of it, fragments of many documents, a collection of documents, all with a one-line query.
- optionally enforced structure. Your documents can follow a specific schema or they can be unstructured (as long as they're valid xml).
- you can link data from one document to many, in a way that fails gracefully, using XInclude. Think in terms of having a common T&Cs doc which you include into all your invoice docs.
- it has a great full-text indexing system that allows you to do fuzzy-text searches with ease. It also has a near-word search, eg: find "spam" within 20 words of "eggs"
- you can search a whole database, through all the collections, all the documents, and all the nodes, with a simple one-line XPath query.
- templating is handled automatically, and you have the power of XSL. And don't moan about XSL - if you don't like it that's probably because you're thinking procedurally and doing 10-times the work of everyone else since the recursive nature of it hasn't "clicked" with you yet. Yes, its not as terse as other systems, but its very powerful when you're working with what is essentially a tree. Its a paradigm shift, but a IMHO a worthy one.
- when you need some extra power, you can use XQuery, which is sort of a cross between SQL, Python, XPath, and XSL all wrapped-up with a functional flavour.
However, the main benefit of Xquery is that its *designed* to work with XML and its derivatives, so you get both programming and querying power along side in-line HTML. For example:
for $u in //users/user
return if ($u/@is-anonymous="yes")
then <div class="anon">anonymous</div>
else <div class="action-time">{$u/action-time}</div>
<div class="gravatar32">{$u/gravatar}</div>
<div class="details">{$u/details}<br/>{$u/stuff}</div>
I don't really know how much more terse you could get?
refactored on February 5, 2009 12:50 PMThe best HTML template engines I've seen is the Tapestry 5 (Java web framework) one. It is almost pure (X)HTML, with all the logic put into components (name and parameters passed as tag attributes) and classes. Quite elegant and way better than JSP or ASP.
One simple snippet:
<table>
<tr t:type="loop" source="items" value="item" class="${rowClass}">
<td>${item.id}</td>
<td>${item.name}</td>
<td>${item.quantity}</td>
</tr>
</table>
t:type says that we're using the Loop component. Source and value are parameters. ${something} are substituted by the corresponding page class property values.
The Common Lisp (etc.) folks are way ahead of you: http://www.franz.com/support/documentation/current/doc/aserve/htmlgen.html
It's called PHP and it sucks
Lee on February 5, 2009 1:01 PMI forgot to mention that Tapestry's templates are previewable: they can be viewed directly at a browser without a server and they render exaclty like they would when requested through a server. This way, web designers and programmers can easily work without messing with each other code/HTML/CSS/whatever.
Thiago on February 5, 2009 1:02 PMMixing HTML with code reminds me of a couple of things I've worked with in the past. One of them is PHP, another is JSP. I guess mixing code with HTML is where we're coming from, and it is really not where we should be going.
I've come to like component-based frameworks such as Tapestry 5 and Wicket very much. Their component model, IMO, is the first thing that really makes you want to write components - because unlike taglibs and templating engines and JSP and JSF and most other things, these things are actually useful for writing reusable bits that output HTML.
Henning on February 5, 2009 1:02 PMOne of the problems with NHaml or Spark is, AFAIK, you don't get compile time checking of your views, which I find really useful if I'm doing heavy refactoring. As more and more components like the Grid in MvcContrib are built, I think drawbacks to using the standard ASP.NET templating engine will be fewer and fewer.
Nick Gieschen on February 5, 2009 1:08 PM@Rob Paveza on February 5, 2009 08:35 AM :
This is ASP.NET MVC. You don't use a server-side managed form (i.e.: form runat="server"...)
Andrei Rinea on February 5, 2009 1:09 PMFunny, that almost exactly looks like how qpy works. See: http://www.mems-exchange.org/software/qpy/
Your example would look like this
def div:xml(klass, *stuff):
'<div class="%s">' % klass
'<br />'.join(stuff)
'</div>'
for user in users:
div("action-time", action_span(user))
if user.is_anonymous:
div("gravatar32", render_gravatar(user))
div("details", user_rep_span(user), user_flair_span(user))
else:
div("anon", "anonymous")
Highly recommended.
M-MZ on February 5, 2009 1:19 PMThis post made me recall some of the worst ASP Classic code I'd ever seen. I have no wish to return to those days.
There is something to be said for specialization. Most web developers I know are terrible at CSS and browser compatibility. Usually they are equally poor at T-SQL (myself included). Separating HTML from [language of choice] from [database of choice] gives you the ability to divide the labor amongst people qualified to manage it.
As soon as you try to merge these three paradigms (I am not fond of LINQ either) you end up shifting the bulk of programming responsibility on the server-side programmer, which tends to be the most expensive programmer in the group. You also dilute his/her knowledge of the stack they're working on, which creates its own problems.
HTML is a markup language, not a procedural language. Regardless of its original purpose, it is usually now tightly coupled to graphic design. Factor the HTML out and you produce better, more maintainable, reusable code. If you can't factor your HTML into something that an object instance could emit seamlessly, it's time to replace your HTML developer.
RickCabral on February 5, 2009 1:23 PMnot mentioning markaby here is a crime :)
http://markaby.rubyforge.org/
Adding another vote for Wicket. If you want to see templating done right, you should check it out. Actually calling it templating is taking it a bit too far. All the template are pure html pages and will render in a normal browser fine. There are no ifs or loops or variables. Instead you link id's in your html file with ids in your code.
It's very clean and very powerful.
Ståle Undheim on February 5, 2009 1:50 PM"But beyond those simple cases, it's shocking how hairy HTML templating gets. What if you need do to a bit of formatting or processing to get that data into shape before displaying it? What if you need to make decisions and display things differently depending on the contents of those fields? Your once-simple page templates get progressively more and more complex."
Maybe you don't hate PHP as much as you profess, Jeff.
Frank on February 5, 2009 2:05 PM@Justin: I don't think designers should be doing HTML, thats what CSS is for.
Angel on February 5, 2009 2:13 PMJeff, the only difference between your last two code examples are a few '<%' tags, and now you have to compile your html. Yet somehow, this is obviously better? I don't think so.
You want to keep things simpler? The solution isn't to fundamentally re-architect how data and html interact. The solution is to break up your templates into more manageable units. It's analogous to breaking a 100 line method up into 4 30 line methods...there might be a few more lines of overhead required for this, but individually they're much easier to understand because they have fewer responsibilities.
Use user controls, or server controls. That's what they're for.
Doug on February 5, 2009 2:31 PMI really like Groovy's MarkupBuilder - it's a really nice way to create HTML/XML in your code, like this (taken from the Groovy website, modified slightly):
def foo = false
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.records() {
car(name:'HSV Maloo', make:'Holden', year:2006) {
if (foo) {
country('Australia')
record(type:'speed', 'Production Pickup Truck with speed of 271kph')
}
}
car(name:'P50', make:'Peel', year:1962) {
country('Isle of Man')
record(type:'size', 'Smallest Street-Legal Car at 99cm wide and 59 kg in weight')
}
}
println writer.toString()
Josh Brown on February 5, 2009 2:37 PMI guess we need a LINX analog to LINQ. VB XML literals are a step in that direction, and I'm a little jealous that we don't yet have this in C#!
Daniel Fortunov on February 5, 2009 2:52 PMI've enjoyed the asp.net apps that override the Render and just issue lots of Response.Write statements to output all the strings that make up the web page...
Steve on February 5, 2009 2:52 PM@Sebastian - i noticed it too... i had to break out of my rss reader just confirm what i was seeing.
Jeff Martin on February 5, 2009 3:03 PMAs others have pointed out, Seaside's ( http://seaside.st/ ) Canvas API is very much along those lines. We came to the conclusion a number of years ago that templates just don't scale. As your application gets bigger and more composed and you go through several revisions, they just get messier and messier.
Seaside's strategy is to express all the html generation in code. The major benefits here are that you don't have to mentally "context-switch" between code and HTML all the time and that you can apply all of Smalltalk's refactoring tools to split parts of it into reusable methods and so on.
If you're generating a lot of very plain-jane static HTML, it can be slightly more verbose than the HTML it generates but as soon as you start throwing in dynamic IDs, callbacks, ajax, and so on it's really a beautiful way to work.
Julian Fitzell on February 5, 2009 3:11 PMBind an Object collection to a repeater...
Anon on February 5, 2009 3:12 PM*ahem* TeX *ahem*
Seriously, I think that TeX encapsulates a lot of what's good and bad about this idea.
Brooks Moses on February 5, 2009 3:19 PMHaving been through CGI, JSP, ASP (arrggg)/ COM (double arrggggg), XSLT (better than all ASP soup), WebForms from 1.0, now looking at MVC.... have come to the point of just hacking together my own methods of least resistance, abusing any of the above if I need to.
2 questions that beg asking:
- WTF is the one true way going to be next week?
- Is it just me, or are we going in circles here?
Yes. We are going in circles.
Andrew on February 5, 2009 3:37 PMI'm starting to wonder if it's not better just put everything in javascript and make server calls only to get content. Leave the javascript to build all the html (presentation of the content) and put the content in place. This way you are basically putting most of the effort in the client instead of the server. By caching the javascript you are also saving bandwidth/time and of making your website more responsive.
Hoffmann on February 5, 2009 4:07 PMI was gonna say something about HAML (it's great, try it) but it looks like other people got there and I already posted it on the Tag Soup post from last year... I do have something to say regarding Justin's criticisms: "In 'real world' situations, you are likely going to work with a graphic designer...They are NOT going to write HAML"
@Justin Actually, HAML was written with graphic designers (CSS aware graphic designers, that is) in mind. It was released to the public after Hampton had gave it to designers and found it to be successful and more productive.
You might that HAML doesn't solve the problem that Jeff sees but I think that it does take care of some of the big tensions - the templates look nice, they are easy to read, they highlight the most important part of pages (the DOM) and they don't feel "wrong" when you are writing them.
NotHampton on February 5, 2009 4:38 PMAdmittedly I don't do a lot of Web work these days. But isn't the whole idea to separate the UI from the business logic? If we're just talking about presentation-layer code, I can understand the need for this discussion to an extent. Still, I've seen very limited need for code in the presentation layer of Windows Forms applications.
Bill Sorensen on February 5, 2009 6:32 PMThere's nothing wrong with templating if you have good tools. Strong tags libraries and an expression language are all you need.
http://en.wikipedia.org/wiki/JSTL
Mike on February 5, 2009 6:48 PMMay be Element Construction Set (java) will get some respect.
BuggyFunBunny on February 5, 2009 6:57 PMwhat's so wrong with PHP that people hate it so much. Can anyone explain why PHP is bad? it is so flexible that you can use it as templates if you really want to but you have the option to mix the code with html or even keep everything as code... it is up to the programmer to decide.
Pawel on February 5, 2009 8:40 PMFor HTML templating in Lua I've developed Tempel:
http://code.google.com/p/tempel/
I came to the conclusion recently that for templates to be powerful enough to be really usefully they need to bound closely both to HTML and to a programming language. The goal of the project is to create a DSL powerful enough to do all presentation related manipulation of data inside the template itself rather than the code calling the template.
nrich on February 5, 2009 10:38 PMI think you're doing this example wrong:
<%foreach (var User in Users) { %>
<div class="action-time"><%= ActionSpan(User)%></div>
<% if (User.IsAnonymous) { %>
<div class="gravatar32"><%= RenderGravatar(User)%></div>
<div class="details"><%= RepSpan(User)%><br/><%= Flair(User)%></div>
<% } else { %>
<div class="anon">anonymous</div>
<% } %>
<% } %>
In proper "enterprise" ASP.net that should be:
[ascx]
<asp:repeater id="rpt_users" databind=blah>
<div class="action-time"><%= ActionSpan(User)%></div>
<asp:panel id="pnlLoggedIn" visible="false">
<uc1:gravatar id="myGravatar" ... />
<div class="details">....<br/><uc2:flair id="myFlair" .../></div>
</asp:panel>
<asp:panel id="pnlAnonymous" visible="false">
<div class="anon">anonymous</div>
</asp:panel>
</asp:repeater>
The repeater databind code should then ipck the correct panel to display and stick in the correct values.
You could take this one step further by creating your own UserDisplayPanel control which will do the thinking and render the avatar and flare correctly for a user, anon or not.
That would mean your final code will be nothing more than a repeater around a control which renders user banners or whatever.
I've never been a huge fan of using <%= %> syntax.
Someone suggested to let javascript retrieve all HTML. I don't think that is a good idea, at least not if you want your pages to be indexed.
Ferdy on February 5, 2009 11:39 PM@Daniel Fortunov
LINX already exists, it is called Linq2Xml. {{using System.Xml.Linq;}}
Velocity does this.
wlievens on February 6, 2009 12:51 AM@Jaster:
> HTML is for laying out text, it had been stretched to do more and more
HTML is NOT for laying out text, that is CSS' job. HTML is for Marking Up text, giving it semantics. This piece of text is a heading, that piece is a paragraph. Here's a list containing some items.
HTML and "code" are NOT the same thing. It's unfortunate that HTML is called a language, even though that is a correct use of the word. HTML is a _markup_ language, not a _programming_ language (it's not turing complete). It sort-of has data structures, but no variables, no flow control, etc. (It's really the page that's the data structure)
The text is the data, the HTML is the meta-data, but how do you vary that data? Templating is one way. I agree it can quickly get ugly. I try to keep all decision making in code, then make just the data available to the template. Tables and lists require a loop over a dataset, maybe filling in a templated row in the larger page template. Anything more complex than that I want to keep out of the template language.
Doing this, I can hand the template off to actual graphic design and layout experts, and my ${year} or #year# just appear as sample data or placeholders. This was, I believe, an original goal of templating.
If you have to recompile/redeploy to change a color, or fix a spelling error, or move a box to a different place on the page, you've failed. I won't put HTML in code again.
+1 to RickCabral who already said essentially the same and was roundly ignored.
Stephen P. on February 6, 2009 1:22 AMI too was thinking XSLT matches your admittedly very nice example that follows your statement "Rather than poking holes in HTML to insert code, we should simply treat HTML as code."
I personally find XSLT quite a natural fit to HTML generation and allows non-programmers (e.g. CSS/HTML/JS developers) to get in on the act too without having to learn a more complex language such as Java, C# etc
That being said, XSLT is definitely not for everyone. I think it works nicely for web sites, even rich ones. For web apps (thinking more like the WebForms side of things in .NET) it is another beast because if you go down the XSLT route there, while (X)HTML generation is much more productive (IMO), on the server side you almost need to end up creating something close to ViewState and the rest to keep the desktop like interactions going...
Anup on February 6, 2009 1:50 AMVanja O.
You also have to add references/namespaces/assembly's to the controls, you get XXkb viewstate, your html gets raped, stupid postback and so on. I cant see how creating new controls (typically with code behind file) seperates code and html?
Why are people so afraid of mixing html and code? Why not worry about separating UI and business logic?
Peter Palludan on February 6, 2009 2:01 AM"Rather than poking holes in HTML to insert code, we should simply treat HTML as code."
Or you could treat the code as HTML. AKA JSTL.
Phil Mander on February 6, 2009 2:22 AMAwesome post.
goatslayer on February 6, 2009 2:28 AMAgree with Stephen P and RickCabral.
The programming language should handle the business logic - get the stuff out of the database, make some decisions about it based on the other known factors, and end up with the data you want to display, described in a way which is comprehensible and reusable to the programming language, retaining the metadata obtained through the business logic. (for instance, pageTitle = "You're Doing It Wrong"; bunchOfArrays = commentID, commentText, userID, userName, commentDate, gravatarID, gravatarCategory) There should be no HTML here (other than perhaps any originally embedded in commentText itself) because *at this stage you don't even know whether you want to output it as HTML*. Here you are deciding on the data to output and how to describe it.
The data and its descriptors should then be handed over to a module which is capable of transforming it into the output language. Usually for our purposes, this is HTML, but it could easily be a CSV download, an RSS feed, or a bunch of emails. (well, why not?) This can be a templating engine which has templates for different output types, and the only logic it should really engage in is looping through arrays provided to it, i.e. foreach, and what to do when data has not been provided (e.g. a null gravatarID should mean that no img tag is output). There should be no decision making because your first stage has already provided you with all the information needed. If you are a template and are given a single variable, you output it once within the template definition. If you are given an array, you output it several times within the template definition. Here you get to define the order in which the data should be displayed, and the method (markup) you're using to describe it. (for instance, whether it is *semantically* better to output the userName before or after the commentText, regardless of how you want it to be visually displayed.)
The final stage is presentational, usually in the form of CSS, and takes the structured markup and tells the device how to display it. Here you get to choose the color of the text, whether the userName should visually appear before or after the commentText (not the best example: think of a sidebar and body text; far too many developers output the sidebar and then the body text because the sidebar is being displayed on the left, when it is more accessible to output the body text then the sidebar, and style it so that they're the other way round) and so on.
The first stage is defined by business logic and turns raw data into parsed data. (database -> decisions -> data+metadata)
The second stage is defined by semantic rules and usability-led, accessibility-led, platform-specific definitions and turns parsed data into structured data. (data+metadata -> output definition -> structured data)
The third stage is defined by presentational rules (design) and turns structured data into "displayed" data. (structured data -> style definition -> output data)
With embedded HTML all this is too difficult so you only offer one output stream, severely limiting your own options in the future. Also, with well designed output, the designer should never need to come back to "ask for another class". The structured data should already contain enough semantic information in the form of the tag used and the id/class provided, to be able to hang any design elements off a set of CSS selectors.
If you are not designing your application in such a discrete way that a new "corporate image" or a print stylesheet decision only affect the presentational stage, or that a new usability issue only affects the second stage, or that a business decision only affects the first stage, then you are always going to run into trouble.
Alistair Knock on February 6, 2009 2:42 AMIt's not about removing the code from the HTML, it's about separation of concerns. It's no different from any other MVC pattern out there.
Andy on February 6, 2009 3:52 AMJeff -
Apparently there as many solutions to this problem as there are browsers. And for some reason, which I don't understand, people become as enamored of their favorite development environments and belabor very similar competing environments as they advocate very similar browsers (or operating systems for that matter). Another Dart v. Valiant argument is unlikely to help anything (for non-US readers, Dart and Valiant were almost identical cars made by two divisions of the same company).
I don't claim to have an answer but would like to point out code comments (sorely, sorely lacking in most of the html and sql I've been forced to read) and maintainability have really not been addressed in the commentary I've read. Perhaps we need a quadrivium of code, comment, description, and data. Knuth's ideas about literate programming may point the way forward.
- Lepto
Lepto Spirosis on February 6, 2009 4:13 AMMy 2 cents...
Working in a team where we have specialists we have a graphics designer (excellent at photoshop), a web designer (better than everybody else at making multi-browser compatible HTML and css) and programmers.
Separating the HTML from the code means that our web designer can improve / tweak the layout without having to know a single line of c#- this is the way it should be...
Our entire society is based around specialisation -having a team of "jacks of all traits, masters of none" results in a purely mediocre end result. Having specialists who are good in their own area and allowing them to work (mostly) independently of one another means that you are using the right tool for each job and working in parallel on the the same problems.
Obviously both sides have to make compromises (the web designer has to learn how the asp.net tags work and the programmers have to consciously keep the template simple) but it works.
Peter
Peter Stephenson on February 6, 2009 4:23 AM"You also have to add references/namespaces/assembly's to the controls, you get XXkb viewstate, your html gets raped, stupid postback and so on. I cant see how creating new controls (typically with code behind file) seperates code and html?"
What's wrong with adding references and namespaces to the controls?
Viewstate can be tweaked, but the current sizes are hardly anything to write home about. The benefit of my solution was in the use of <asp:repeater> and <asp:label> tags which would completely separate the code from the HTML. Its hard to give a good example in a comment box with no code highlighting and formatting.
Earlier in the replies I asked "what am I missing?", but, having read through this several times I'm now convinced you're either joking or you've fallen into the mire that is change for the sake of change.
The difference between the two examples is nothing but the escaping tags... yet you seem to be under the illusion that this changes something more than forcing the parser to be impossibly smart*. It doesn't, you've not changed a single piece of methodology. A methodology that is outdated and widely scorned for very good reason.
In the end it boils down to this quote, IMHO: "If your HTML templates can't be kept simple, they're not a heck of a lot better than the procedural string building code they're replacing."
True enough, but moot - they can be kept simple with just two types of markers in your template:
{SECTION:user}
<div class="action-time">{VAR:user}</div>
{SECTION:userNotAnon}
<div class="gravatar32">{VAR:userGravatar}</div>
<div class="details">{VAR:userRep}<br/>{VAR:userSpan}</div>
{/SECTION}
{SECTION:userAnon}
<div class="anon">anonymous</div>
{/SECTION}
{/SECTION}
Your template class merely needs to replace each section with a placeholder, and recurse the section itself into a new instance of the class. These sections can then be repeated, left out, alternated, whatever. The templating class just parses the variables in, then parses the resulting code into the parent template, before the placeholder as often as required. At the final parsing, the placeholders are removed, et voila.
So, where's the rub? What's wrong with this system that retains separation? Or is separation not a good idea any more, even when it can be kept simple?
Like I said, I think you're either taking the piss or you've lost sight of some fundamentals in the pursuit of shiny new things :)
Please, someone, explain what I'm missing...
--
*Is "a<b" a comparison or an unclosed deprecated tag? does "class='blah'" mean use the CSS class blah, or does it mean the CSS name stored in the blah variable?
Schmoo on February 6, 2009 4:46 AMI've never seen so many different claiming everyone else is "Doing It Wrong" (love the capitalization to Emphasize Your Opinion there) and touting their own Best Way Of Doing Things.
We're using XSLT and it works fine.
The odd page can get quite messy but if you indent it's not unreadable. Sometimes vanilla source code ends up like that too.
But I'd say it depends what you want to do really. Use the best tool for the job.
Dave on February 6, 2009 5:14 AMCheck out Java, JSP with STL (Standard Tag Library) and custom tags. You have suggested to treat html as code. and JSP+STL doing oposite, they treat code as html/xml.
http://java.sun.com/javaee/5/docs/tutorial/doc/bnakc.html
Example:
<x:forEach var="book"
select="$applicationScope:booklist/books/*">
<tr>
<c:set var="bookId">
<x:out select="$book/@id"/>
</c:set>=
<td bgcolor="#ffffaa">
<c:url var="url"
value="/bookdetails" >
<c:param name="bookId" value="${bookId}" />
<c:param name="Clear" value="0" />
</c:url>
<a href="${url}">
<strong><x:out select="$book/title"/>
</strong></a></td>
<td bgcolor="#ffffaa" rowspan=2>
<c:set var="price">
<x:out select="$book/price"/>
</c:set>
<fmt:formatNumber value="${price}" type="currency"/>
</td>
<td bgcolor="#ffffaa" rowspan=2>
<c:url var="url" value="/catalog" >
<c:param name="Add" value="${bookId}" />
</c:url>
<p><strong><a href="${url}">
<fmt:message key="CartAdd"/> </a>
</td>
</tr>
<tr>
<td bgcolor="#ffffff">
<fmt:message key="By"/> <em>
<x:out select="$book/firstname"/>
<x:out select="$book/surname"/></em></td></tr>
</x:forEach>
Take a look at boo meta-programming (see the macro keyword). It's not directly related to HTML but the idea is the same except for generating code. In Boo meta-programming you interleave your generated code in with the real code a lot like the VB XML literals.
But honestly, I think embedding XML or HTML in a language is a huge mistake. It completely muddies the language and forever ties it into something that could be out moded in less time than it's lifespan would have been otherwise.
Justin Chase on February 6, 2009 6:08 AM1. PHP allows you to use <?=Foo($User)?>. Jeff, you're at the starting point of PHP's original development. You seem to hate the language that resulted, though.
2. Encapsulate. If you're rendering a page, why should it contain more than a few method calls? Everything else in SO is encapsulated, right? Right?
<?php
include('SOLib.php');
$getdata=CleanGetData($_GET);
$User = new SO::User($getdata["user"]);
$Page = new SO::Page($User);
$Question = new SO::Question($getdata["question"]);
$Question->ProcessAnswer($getdata["answer"]);
$Page->WriteSOHeader();
$Page->WriteBodyForQuestion($Question);
$Page->WriteFooter();
?>
3. Profit! Or, Who Has Too Much Spaghetti?
Where am I wrong here?
Phil H on February 6, 2009 6:41 AMAnother templating system nobody's mentioned yet is ClearSilver <http://www.clearsilver.net/>.
And if you're seriously worried about the performance of string concatenation, write a C program to do your page generation over CGI. You're not going to get better performance any other way. Just watch out for buffer overflows.
Adam on February 6, 2009 7:27 AMMaybe I just don't know enough about templating engines, but aren't they just doing string functions behind the scenes?
Daniel on February 6, 2009 7:40 AMThat's what usercontrols are for.
The designer designs the forms, sets their id and runat-Attribute, and the programmer fills the template.
Your solution mixes wildly programming and design/layout.
This solution is longer, but in my eyes more mantainable.
<%
// main-template
divUserList.InnerText = "";
foreach (var loUser in Users)
{
UserItemControl loUserDiv = UserItemControl.GetControl(loUser);
divUserList.Controls.Add(loUserDiv);
}
%>
<div runat="server" id="divUserList">
List of users
</div>
<%
// user control
public static void GetControl(Page voPage, User voUser)
{
UserItemControl loControl = voPage.LoadControl("/c/UserItem.ascx") as UserItemControl;
loControl.Init(voUser);
return loControl;
}
public void Init(User voUser)
{
divActionTime.InnerHtml = voUser.ActionSpan.ToHtml();
if (voUser.IsAnonymous)
{
divAnonymous.Visible = true;
}
else
{
divGravatar.Visible = true;
divGravatar.InnerHtml = voUser.Gravatar.ToHtml();
divUser.InnerHtml = voUser.Reputation.ToHtml();
divFlairUser.InnerHtml = voUser.Flair.ToHtml();
}
}
%>
<!-- user control -->
<div id="divUserKnown" runat="server" visible="false">
<div id="divActionTime" runat="server" class="action-time">
2009-02-06T15:51:00
</div>
<div id="divGravatar" runat="server" class="gravatar32">
Gravatar
</div>
<div class="details">
<div id="divUser" runat="server">
Reputation of User
</div>
<span id="divFlairUser" runat="server">
Flair of User
</span>
</div>
</div>
<div id="divUserAnonymous" runat="server" visible="false" class="anon">
anonymous
</div>
Could the User object return a valid user that is 'anonymous'?
anonymous on February 6, 2009 7:59 AMCode embedded in HTML is difficult to test and maintain. HTML embedded in code is difficult to read, understand and maintain. Pure code is easier to maintain, and with pure HTML at least you can view it in a variety of HTML editors; you have to keep code and HTML separate if you want to avoid creating an unholy mess -- but most web frameworks don't give you the power to work that way.
In fact, I know of only two frameworks that let you create HTML-based web applications without mixing HTML and code: Tapestry and Wicket.
They use Java and HTML/CSS but keep them in separate files. Fragments of web pages are built by assembling and embedding panels, with separate HTML/CSS and Java files for each panel.
Wicket gives you a bit more flexibility in that you have the panel to swap out panels in a dynamic fashion, and it has lots of AJAX support using pre-written but easily extended AJAXified page components (the Javascript is already written for you).
Wicket's users are very enthusiastic about it. It has become a lot easier to learn Wicket now that Manning's _Wicket_in_Action_ has been published.
Frank Silbermann on February 6, 2009 8:13 AMTemplating languages are popular -- thus they'll be misused far beyond their original intent. But nothing beats this:
When I was doing a gig with core group of Yahoo properties, all of which are written in PHP, they were developing a templating language written in PHP.
I am not making this up. It's way too ridiculous for that. They'd all been working in PHP (including PHP 5's hacky class mechanisms) for so long that it looked nothing like a template language. In fact, it was common to see stuff like
<?php
// various procedural code
echo "<div class='" + $foo + "'>" + $bar->html + "</div>";
// and so on
?>
Yes. *IN PHP*. So then developers clamored for a template language and they started to write one. *IN PHP*. So, yes, it can help to step back every once in a while and take a look at the forest you're in.
Wow, I think this is the biggest variety of opinions I've ever seen on a subject. This is a hot topic, because there is no perfect solution.
I think the best solution would be to picture a world where HTML doesn't exist, design an ideal code/template system, then make it backwards compatible with HTML. Then we'll have a good system going forward.
Regis on February 6, 2009 8:51 AMSo we should mix html into code instead of mixing code into html?
I don't get it. It seems like the same thing to me. Personally I wouldn't mix code and markup again at all. It's not necessary anymore. It's the dark side, seemingly simple but treacherous. :)
Keeping code and markup separate makes your solution flexible, easy to maintain, easy to read, easy to change.
The first example with the user and gravatar in MVC is fine. The second one with the if-statement is not. But I can see no reason why the "if" should be in the markup like that, instead of the code? Have a class that generates the appropriate output for both normal users and anonymous users.
Console on February 6, 2009 9:15 AMThank you Jeff, for having the balls to post this entry today risk being a lightning rod for criticisms. Really good arguments here, from all sides.
Charles on February 6, 2009 9:39 AMI'm a little surprised that people act like WebControls/UserControls are off limits in MVC. They just go by slightly different rules now.
You can write your own templating functions inside a control and at the very least hide some of the mess of normal <% %> junk.
HB on February 6, 2009 10:05 AMYour second example is just bad code a straw man if you will. A repeater is what should be used. The second example should be:
<asp:Repeater runat="server" id="whatever">
<ItemTemplate>
<div class="action-time"><%# ActionSpan((User)Container.DataItem)%></div>
<div class="gravatar32" runat="server" visible="<%#((User)Container.DataItem).IsAnonymous%>"><%# RenderGravatar((User)Container.DataItem)%></div>
<div class="details" runat="server" visible="<%#((User)Container.DataItem).IsAnonymous%>"><%# RepSpan((User)Container.DataItem)%><br/><%= Flair((User)Container.DataItem)%></div>
<div class="anon" runat="server" visible="<%#!((User)Container.DataItem).IsAnonymous%>">anonymous</div>
</ItemTemplate>
</asp:Repeater>
Even better would be to encapsulate that chunk of HTML into a user control. Then bind the user object to that control. The markup would look like:
<asp:Repeater runat="server" id="whatever">
<ItemTemplate>
<uc:UserDetail runat="server" id="userdetail" User="<%#(User)Container.DataItem%>" />
</ItemTemplate>
</asp:Repeater>
Good principles like SRP (single responsibility principle) have been identified for a reason, the help improve your code quality.
monkey on February 6, 2009 11:13 AMJeff, you've got to at least reference this image:
http://img6.imageshack.us/img6/4281/youredoingitwrongwt0.jpg
Zack on February 6, 2009 11:35 AMThe fact that every single commenter already has a perfect yet totally different solution to the problem reveals that there is no problem, it's just a matter of style, taste or discipline in formatting.
This reminds me an amazingly good way to generate XML documents (in general): Prolog (http://www.swi-prolog.org/)
I don't remember exactly the syntax, but, basically, an element or an attribute was a plain object. Sure, this can be done in any 'scripting' language. What is unique to Prolog was how easy it is to write transformations, since the Prolog equivalent to function invocations is based on pattern matching.
Maybe a little off-topic, but interesting!
-gael
Gael Fraiteur on February 6, 2009 1:21 PMI find the comments that act as if this is a webforms project ammusing.
I'm just wrestling with making an ajax ui right now, and I find myself thinking "is Jeff going far enough with his questioning?" The more I wrestle with having my application smashed into HTML, CSS, Javascript, and heaven help us, server-generated html, server-generated javascript and javascript-generated html, the more I think that we have run off the rails completely.
Listening to the Objective-J guys talk about this, I'm inclined to agree --- just put the whole bloody thing into the code.
Now, when we were just marking up content, the whole HTML(XML) + CSS made sense. But now that we're making applications, it's time for a complete rethink....
Robert Goldman on February 6, 2009 2:23 PMIf there is any such thing as a programmer's bikeshed topic, templating will have to be it.
What I find interesting, Jeff, is the schism between what you're saying here and what you say here (for example):
http://www.codinghorror.com/blog/archives/001119.html
If there is any language/platform that treats HTML like code it's PHP.
I say this as a long-time (10+ years) Java developer. I've done the whole n-tier multi-layer Web application and it's incredibly painful. If my DAO wants to interrogate $_SERVER['REMOTE_ADDR'], is it really that bad that it can (in PHP)? More to the point, is it any better in Java/.Net that I then have write a whole bunch of boilerplate code through all my layers to get this from the Web tier down to the persistence layer?
Some will say "yes" but honestly I think some forget that these kinds of architectural principles are a means to an end and they're often being treated as an end in themselves.
(And FYI I totally agree PHP has problems like it's API, naming standards and parameter conventions are a complete mess).
I do however agree with you that templating frameworks (much like any sort of framework) tend to be overused in that people go looking for a framework before really seeing if they needed one. I wrote some pretty decent form binding/validation in PHP the other day. Took me an afternoon and now applies to all my forms. Sure I could've used Zend Form/Symfony/CakePHP or something else but I just see tutorials on Symfony that say "after you code these 11 files you'll have a 'Hello World' script!" and run screaming.
But, getting back to the point, in spite of all the criticisms of PHP (some valid, many not), PHP is most like what you're describing and it works because it's designed for this task.
While I can agree with some of the underlying concepts in this post, I disagree with your conclusion, Jeff. Uninhibited mixing of code and HTML seems to be contrary to the many concepts of separation that programmers and web developers uphold as the pillars of their craft. Whether it's content/presentation/behavior or model/view/controller, drawing lines between them improves cohesiveness and reduces coupling.
I think separation between code and HTML is something we should continue to strive for. I try my best to not generate HTML in my code, but sometimes it can't be avoided. In those situations, I try to delay adding HTML as along as possible, though I suspect that's having a negative impact on performance (how much impact is anybody's guess).
Readability is first and foremost, and I feel that mixing code and HTML flies in the face of this too. Whenever possible, I put my <% and %> (or <? and ?>) on their own dedicated lines. (Unless I'm outputting a single variable. <%= whatever %> belongs together.)
Scott on February 6, 2009 10:28 PM<p>Wow. Only two people mentioned Lisp. And even then only briefly. The relevant thing in Lisp is that code IS data. Which makes this an easy problem to solve.</p>
<p>The funny thing is that not only can you mix HTML with code in Lisp but you can also mix <a href="http://www.cl-user.net/asp/qPjl1/sdataQ0XhWNSGcySfDQ3W8GMX8yBX8yBXnMq=/sdataQu3F$sSHnB==">CSS</a> and <a href="http://common-lisp.net/project/parenscript/">Javascript</a> and <a href="http://common-lisp.net/project/cl-json/">JSON</a> too.</p>
<p>It doesn't stop there either. You can use Lisp's space age macro features (circa 1960s) to create code that creates code. I know, I've done it. All in all it's possible to create rich, interactive, fully specified in one file, web applications in only a few 100 lines of code.</p>
Steve Knight on February 6, 2009 10:55 PM@Mark Armendariz
> It's always seemed to me that the most ideal HTML template would be entirely based on HTML itself,
> using classes and ids - or better yet, selectors a la jquery or prototype
Such engine exists, it uses extended jQuery API. It's PHP based, although it can generate code in other languages (JS for today).
You can check it out at http://code.google.com/p/querytemplates/
Using load-traverse-modify approach, HTML markup is always separated, clean and easily previewable/editable.
Tobiasz Cudnik on February 7, 2009 3:18 AMUninhibited mixing of code and HTML seems to be contrary to the many concepts of separation that programmers and web developers uphold as the pillars of their craft.
Separation of concerns is not the same as separation of technologies.
I think an ideal system would be in a single language, with some kind of package structure. Then you (well, the system architect) would declare exactly which language features were allowed in which packages. Then all of these would be would be a declarative statement, not a consequence of other choices:
'no HTML literals in the business logic'
'no conditionals in the presentation template'
'the client layer may not be synchronously called from the server layer'
'system code is compiled to machine instructions, presentation layer purely interpreted'
...
Cue someone saying 'LISP can do this since 1975'...
@Justin
I don't understand why you put so much weight into "generator code" looking similar to the "output". Would you prefer we all write binary code instead of some high-level language, just to make debugging a bit more straightforward? Much like programs compiled in debug-mode, generated HTML can contain comment markers to make it easier to find the corresponding code, in the rare case you have to do that. E.g. the debug-compiled HTML could look like this:
<!-- gen_data.foo, line 23: html.link("http://foo.bar", foo) -->
<a href="http://foo.bar">text that was stored in foo-variable..</a>
>> Its totally unmaintainable, and diverges so far from the actual representation that you're ensuring that nobody but you will ever really know whats going on.
On the contrary, when your code is composed of high-level constructs, it's much easier for everyone to know what's going on. The meaning is conveyed by function names and documentation. In HTML you need so much boilerplate that the real meaning is hidden within the noise.
>> Plus, what happens when your function doesn't support all the attributes you want to use?
Duh; Make the basic functions support all the attributes defined in the HTML specs. Perhaps you're thinking in terms of Java, or a similar language that doesn't support named parameters. With named parameters, you can leave out those that you don't need: html.a("hello", href="...", whatever="...").
plau on February 7, 2009 7:27 AMMy first thought was that your sample code looks like XQuery. (an earlier commenter mentioned that as well.)
My second thought is that XML Builder keeps the damn angle brackets out of your code. Which looks like it was backwards.
for (user in users) do
xml.div(class => "action-time") do
xml.text(action_span(user))
end
if (user.is_anonymous?) then
xml.div(class => "anon") do
xml.text("anonymous")
end
else
xml.div(class => "gavatar32") do
xml.text(render_gravtar(user))
end
xml.div(class => "details") do
xml.text(rep_span(user))
xml.br
xml.text(flair(user))
end
end
end
Alistair Knock:
You mention a templating engine which has templates for different output types, and you say
"the only logic it should really engage in is looping through arrays provided to it, i.e. foreach, and what to do when data has not been provided (e.g. a null gravatarID should mean that no img tag is output)"
Then you say
"There should be no decision making because your first stage has already provided you with all the information needed."
If there is no decision making, then how does the template output no img tag, if gravatarID is null?
glengarry on February 7, 2009 10:17 AMLets recap the methods for dynamically mixing your data with tags :
1. String concat (i.e. code with embedded tags)
- hard to read
- I find this approach unpleasant to type for some reason - probably all the extra concat chars and quotes within quotes etc.
2. tags with embedded code (with varying amounts of control structures)
- can prevent validation of templates (whereas a fully xml/html compliant template can be validated which can make quick work of finding bad markup)
3. Builders & DSLs
- need to learn more syntax but IDEs can help minimize this
- ends up long, ugly and procedural even though small examples can look neat
4. Declarative Templates / Data Binding.
- keep logic out of template and instead bind results from your conditional as data which is used when processing the template
- template nodes can define whether to be processed or skipped based on this data
- business logic can target nodes for population with data (like one might do with js on the client side - "insert data into tag with id of 'blah' ")
I prefer option 4 when the template conventions are simple - and that means a declarative approach which is NOT XSLT (yes there are declarative solutions beyond XSLT). XSLT is powerful and I even enjoy writing in it but I always feel that it is more mentally taxing to use than it should be and therefore tend to work with alternatives or a homegrown template parser.
Option 2 is generally fine also - but only if you (and your colleagues) are aware of the basic strategies for avoiding unnecessary logic in your templates. Of course you have the flexibility of breaking into script should the need arise. (BTW. Whilst PHP is a template language itself I often use Savant to ensure I avoid polluting the global scope when taking this approach).
With the advent of server-side javascript I expect the trend to adapt further with greater use of powerful query engines and dom manipulation APIs to bind our data to the template and to hide/show relevant parts of the tree.
wioota on February 7, 2009 10:44 AMHi, I was just looking at old posts, and wanted to comment on the "unfinished game".
It looked like a lot of the responses, and yours, were changing the problem.
The original question says "the parent tells you that one of the childeren is a girl". It seems like people that are saying the answer is 2/3, have changed the problem to read "one of the children is a girl". And fail to enumerate the observer, the parent, into the list of possibilities.
ie. if we divide parents into two groups, ones that will tell you the sex of the first child, and ones that are going to tell you the sex of the second child. the list of possibilities are:
first:, second:, parent says I have one of these:
G G G
G B G
B G B
B B B
then for the other set of parents
G G G
G B B
B G G
B B B
so when parent say I have one G, there are 4 possibilites
GG -parent was talking about first child
GB -parent was talking about first child
BG -parent was taling about second child
GG -parent was tlking about second child
which works out to 50% chance that the other child is a girl. Of course parents could be divided up other ways. but as long as you assume there is a 50% chance of having a girl and a 50% chance that the parent falls into one of the two categories that you have chosen then the probability that the other child is a girl is 50%.
If the problem makes use of "someone making an oberservation", or "someone making a statement about an observation", those possibilities need to be enumerated!
Steve P on February 7, 2009 5:44 PMJeff,
you deserve a medal (erm, badge) for bringing out the best (in) code jock(ey)s.
Hasn't this topic been beaten to death over the past 15 years or so?
BugFree on February 7, 2009 11:34 PMIt doesn't matter how you slice it. Html is a document. Code is a program.
You're creating documents on the fly, and it doesn't matter what the document is, or what your code is. You're never going to have everything fit just so. You're marrying the two concepts, but the reality is it's all the same problem.
Maybe the real answer is another layer of indirection between the two. Something that isn't a black box, and something that can be programmed against and isn't a total nightmare to maintain.
For all the bitching, web forms is pretty good, but some of the implementation details left big gaping holes to fill, created ugly and bloated markup, and it wasn't a seamless fit (like having to call FindControl to get a text box in a repeater, etc).
The MVC default markup model is atrocious, going back to classic asp days. Yuck.
A lot of talk of HAML, but no example. Here's what it would look like, most likely. (I'm a Rails guy, but I did not change the code to ruby.) I hope the formatting is preserved...
- foreach (var User in Users)
.action-time= ActionSpan(User)
- if (User.IsAnonymous)
.gravatar32= RenderGravatar(User)
.details= RepSpan(User)
%br
= Flair(User
- else
.anon anonymous
@Steve P: It's quite fitting that you'd answer an entirely unrelated question here, given the abandonment of separation being advocated :)
You're wrong though. You say we "fail to enumerate the observer, the parent, into the list of possibilities" - that'll be because the question is the gender of the children. The parents' gender doesn't affect the children's gender, and so is irrelevant.
Schmoo on February 9, 2009 5:50 AMAfter reading more of the comments I've come to the conclusion that its more helpful that if you do have a template language that it be declarative and not imperative so the logic code in the presentation layer can be concise and simple to maintain.
o.s. on February 9, 2009 7:48 AMI agree with the first poster. XSLT. I don't care if Martin Fowler hates it. It works, I've used it on big sites, and the syntax and grammar are quite good. There wasn't anything I couldn't do with it, and I had a friggin' form-templating engine with a javascript calculating engine and formulas coming from a database being transformed into HTML via XSLT. Worked perfectly.
That being said, MVC's model is the same as ASP, which sucked. WebForms work very well, just about totally avoiding the need for a templating architecture at all, IMO.
Robert C Barth on February 9, 2009 1:39 PM
sorry about posting in the wrong spot about the unfinished game.
Schmoo,
I didn't make any mention about the gender of the parents, so not sure why you are bringing that up?
I was just saying that the way the problem was posed was that the parent says one of the children is a girl. So when a parent has a boy-girl combination, 1/2 the time they could have said "1 child is a girl" and 1/2 the time they could have said "1 child is a boy". So once you add up all the possible cases where the parent has said "1 child is a girl", 50% of the time it's a 2 girl family, and 50% of the time its a 1 girl family.
glengarry:
"'There should be no decision making because your first stage has already provided you with all the information needed.'
If there is no decision making, then how does the template output no img tag, if gravatarID is null?"
I know, it's a kludge. I probably should've said "There should be no decision making related to business logic". Admittedly the structure/presentation layer may at times need apply certain rules in order to preserve its integrity, but these are still discrete from the business logic which is all handled in the first stage. Different output modules will also behave differently - in this empty gravatar example, a CSV templater won't need to do the test since it's imperative that the empty element is captured in the CSV. The opposite is true for well-formed HTML, hence the need for the rules.
Even so, at no point is the templater saying "if Jeff Atwood is posting this comment, make it bright orange and flash insanely quickly". It should just receive the comment and appropriate class ("owner") to use, which is then styled.
Alistair Knock on February 11, 2009 4:02 AMI can only agree with Mark Armendariz: jQuery gets it right. It allows object-oriented programming in the way Alan Kay envisioned it, but selector-based (instead of class-based), which is more flexible.
This is so powerful as a code organization mechanism that I wouldn't be surprised to see web apps appear for which the complete UI is defined and executed in jQuery, with HTTP just being used to obtain application-level data (in JSON, SOAP or whatever) instead of UI elements (HTML).
Reinier on February 12, 2009 6:11 AMI tend to be an OO purist, and I do enjoy working with Wicket. Unit testing Wicket applications is easier, too:
http://www.ibm.com/developerworks/web/library/wa-aj-wicket/index.html#unitTesting
Steven Farley on February 12, 2009 6:30 AMAlistair Knock hit the nail on the head. The reason that HTML should not be embedded in the Application Logic (the C# portion in this case) is that it isn't Application Logic.
The argument that code embedded into HTML is a crude method of producing structure output is valid, though. However, the solution is not to consolidate. Instead, separation of concerns should be preserved. Solutions such as HAML or XLST preserve the separation of concerns and provide a more elegant method of creating structure data.
Derek Hammer on February 16, 2009 1:01 PMSeperation of duties. Templates are an acceptable way to generate a view - so long as that's _ALL_ they are doing. I prefer the MVC model to a strictly component model. Most template engines I've seen will let you use components anyway, it's just your design decision. But I do -not- put HTML or generate it directly from the controller. If I have to have a second or third template to enforce that, I will happily do so.
I use Template Toolkit (and am eagerly awaiting the python version), which generally only has very simple logic in a template. If I'm rendering different major things, I'm probably going to have different templates, maybe embeddable if there's a lot of repeating.
ThatPerlGuy on February 16, 2009 5:03 PMMaybe we're looking at the entire process from the wrong perspective. Think of it from a workflow perspective, I'm going to use a concrete example so I can make it clear exactly what I'm talking about as I go, let's say something like ebay.
It starts from a concept of what you actually want to accomplish, from there you get base sketches of how the interface works in principle, it is then handed over to a designer and they whip up a base layer in photoshop which represents the back of the page and proceed from there adding elements from that environment by means of palette based technology, clipart and colourwheels and all that delightful non developer stuff.
Once the "design" is complete, either the designer or the coder or some outsource shop will take the design and translate it into XHTML / CSS based layout code that can then be handed to the coder and they work within that framework to get a working application that actually allows a user to manipulate a database of real world objects for sale by way of a bunch of operations.
So, where are the pain points? idea -> sketch -> photoshop -> xhtml/css -> logic / db design -> melding logic + db design with xhtml/css -> finished product. Templating attempts to address the last step in this particular process, allowing concurrent activity between developers and designers with as little interruption as possible.
It falls down because html generators in code are not that hot (and even if they were, so you have a finished HTML/CSS design and you now have to reimplement it by calling a bunch of html generation methods on a pseudo DOM object? kind of wasteful / labour intensive), and string concatenation / mishmashing code and layout result in finished products that are not well understood either by the developer or the designer, each from the opposite perspective.
Common solution is to hybridise the skills between the two schools as much as is necessary in order to effectively collaborate, my designer doesn't necessarily understand how to construct an object relational model, but can probably understand an if statement embedded within a html string concatenation call easily enough, and even if not can easily be taught these abilities. But this fails to get at the fact that this is a hack.
Why do we even *HAVE* html? Why don't we just take the PSD's and script them with language X so that users can use them like an application, and if anything needs to be changed, the designer just changes it within photoshop and hey presto the entire site changes? Because we all know that the technology doesn't work that way, even what I just said makes me wince because I am thinking of the crazyness of transferring complete PSD files for every page / element with no compression etc. It just isn't a good fit for the media. We have html / css and all the things that it allows us to do because they "effectively" (and I use the term loosely) break down the contents of a finished design into simplistically defined elements which can then be rapidly manipulated within code and transferred over an unreliable network medium to the end user.
So how to address these issues from this thousand foot view of the entire workflow? How about writing a photoshop clone within the browser that uses the DOM to layout the designer's work as they go and does clean XHTML/CSS right from the beginning, maintaining the entire semantic information from start to finish for the entire workflow. You start with your sketches and then put them into photoshop clone and as you go along it generates the necessary elements to display the content as designed and also allows direct work on these same elements but in a different context by developers, so if the designer changes a class name on an element that the developer is currently working on the change is transparent because the system actually understands what is happening, rather than has an imperfect abstraction of the process with much information removed from the equation resulting in messy hacks like html string concatenation or code based html generation?
Instead of the framework cutting in at the "ok I have an HTML / CSS based design now" phase, it cuts in at the "lets build this" phase and gets all the richness and syntax of that phase embedded within it's internal processes and can thus effectively abstract that process into the multiple spheres which it actually entails rather than pretending like everyone is a hybrid developer / designer?
The obvious and immediate answer is that doing this would be very hard, this answer is correct. But it might be a pretty interesting project, and shortcuts may be taken, who knows, some kind of photoshop plugin that actually ties into the framework to see what is happening meaning all that effort duplicating photoshop like functionality could be skipped? Anything along these lines? Maybe someone else has already thought this up and there are solutions out there that do pieces of this already.
I think in the end, the initial point of this article is the heart of the problem, string concatenation for html generation implies not an incorrect answer, but an incorrect question. But maybe template languages and html generation libraries do, also.
Anybody here heard of XML/SQL?
Since most parts of a website are repetitive and can be broken down to smaller sections. Create the template using XHTML/CSS, store the content in XML/SQL and use PHP to generate the dynamic HTML parts based on the HTML prototype.
Then create a simplified CMS to edit the XML/SQL on the back-end.
It's really simple to implement. The only hard part is, learning the languages and specifying the HTML/CSS template (Not really that hard).
BTW... I hate XSLT too.
Evan Plaice on March 3, 2009 9:50 PMI can't say this clearly enough.
ColdFusion!
Free, open source, elegant and fast. Feature rich or as minimal as you want.
Don't believe the myths about ColdFusion. It's a very versatile language.
Michael Pumo on April 3, 2009 7:56 AM| Content (c) 2009 Jeff Atwood. Logo image used with permission of the author. (c) 1993 Steven C. McConnell. All Rights Reserved. |