You're Doing It Wrong

In The Sad Tragedy of Micro-Optimization Theater we discussed the performance considerations of building a fragment of HTML.


This is a companion discussion topic for the original blog entry at: http://www.codinghorror.com/blog/2009/02/youre-doing-it-wrong.html

It’s called PHP and it sucks

I 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.

Mixing 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.

One 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.

@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…)

Funny, 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.

This 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.

not mentioning markaby here is a crime :slight_smile:
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.

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.

@Justin: I don’t think designers should be doing HTML, thats what CSS is for.

Jeff, 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.

I 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()

I 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#!

I’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…

@Sebastian - i noticed it too… i had to break out of my rss reader just confirm what i was seeing.

As 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.

ahem TeX ahem

Seriously, I think that TeX encapsulates a lot of what’s good and bad about this idea.

Having 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?