As we work with ASP.NET MVC on Stack Overflow, I find myself violently thrust back into the bad old days of tag soup that I remember from my tenure as a classic ASP developer in the late 90's. If you're not careful bordering on manically fastidious in constructing your Views, you'll end up with a giant mish-mash of HTML, Javascript, and server-side code. Classic tag soup; difficult to read, difficult to maintain.
I don't mean tag soup in the sense of badly formed HTML, or the malformed world we live in. I mean tag soup in the sense of mixing HTML markup and server-side code. Now you can double your pleasure: badly formed HTML, meet badly written code.
The tag soup problem seems to be endemic to all modern web development stacks. I see that Ruby on Rails apps have the same problem; here's a slice of representative RHTML from Typo, a Ruby blogging engine.
Do you find this readable? Can you see where the code begins and the markup ends? Are you confident you could change the code structure without breaking the HTML, or change the HTML structure without breaking the code?
Sometimes editing this stuff makes me feel like I'm playing Operation. I have to ever so carefully maneuver my metal tweezers into one tiny slice of code or HTML and make my changes without touching the edges and setting off that blasted electrical buzzer.
I'm not trying to single out Rails or Typo here; I could easily show you a ASP.NET MVC view that's just as confusing (or as "clear", if you think that's perfectly readable, I guess). Tag soup is everywhere; take a look at the Python Django framework templates:
<h1>Archive for {{ year }}</h1>
{% for date in days %}
{% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
<a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
{% endfor %}
Perhaps when it comes to mixing HTML and server-side code, some form of soup is unavoidable, a necessary evil. The soup can be quite palatable; maybe even delicious. It's certainly possible to write good tag soup and bad tag soup.
But I have to wonder: is there a better way? Is there something beyond RHTML, Views, and Templates? What examples would you point to of web development stacks that avoided degenerating into yet more hazardous, difficult to maintain tag soup? Is there anything truly better on the horizon?
Or is this year's newer, fancier, even-more-delicious iteration of tag soup as good as it ever gets for web development?
| [advertisement] Read the largest case study ever published about lightweight peer code review in Best Kept Secrets of Peer Code Review. Free book, free shipping. |
Posted by Jeff Atwood View blog reactions
« Dealing With Bad Apples Building Tiny, Ultra Low Power PCs »
Shouldn't tag soup in MVC be less of a problem/excusable because we have server side controls ?
In ASP.NET Forms there is still the possibility of making up a batch of tag soup but we don't because we use controls.
Or am I missing something important about MVC here?
Kev on July 21, 2008 04:14 AMI think there are two answers here:
1) Write better markup. In the typo example you could move lots of that code to a model or helper, especially the URL concats, date format, etc. If you move all that to the model it is much more readable.
2) Get rid of the HTML part. I love a simple markup technology called HAML. It started on Ruby but there is a NHaml as well. Here is an example from my MVC app using HAML:
#roomdetails
-foreach(Model.Vip vip in room.Vips)
#roomdetail
%a{href=vip.Url,class="borderit"}
%img{src=Network.Current.StaticPublisherAddress + vip.Image, class="left"}
.viptitle
%a{href=vip.Url}
= vip.Title
.vipdesc
= vip.Bio
.clearleft
HAML has to be indented correctly btw, the spaces/tabs were removed from my comment though, you can see it properly here:
http://infozerk.com/averyblog/new-lounge-front-end-now-with-asp-net-mvc-and-nhaml/
James Avery on July 21, 2008 04:27 AMpersonally, I'm a PHP developer when it comes to webstuff and my (terrible) solution to this problem is to write a pure block of PHP code which outputs the page without using the (convenient) functionality of writing HTML with PHP interspersed. It makes the HTML harder to read in the PHP code file, but all I need to do is view the page source with a browser or other tool once the page is up if I need to see the HTML. I generally insert tabs and new lines to help this... although I will admit I am a bit lazy as doing a "view source" on the pages on my website will reveal.
So from my perspective, tag soup is a problem the developer makes for himself... at least for PHP. I'd actually need to know something about ASP to comment on it though....
jheriko on July 21, 2008 04:29 AMI've been working on an internal web application for a client for some time now in php.
I've found the easiest way to remove tag soup is write each page entirely in php, using functions like:
property("one", "Email", element_input_text("email", $inspector->email))
This function returns all the html tags required to display a nice input for entering an inspector's email address.
I string all these functions inside functions together inside the function template(), which creates all the html for the basic framework of each page (title, breadcrumbs, menus, header, footer, and buttons).
I indent these functions in much the same way as I use to indent html so it's easy to see how "deep" in the html I am.
No tag soup and parenthesis matching in my IDE ensures I don't leave out close tags.
This is one place I think shows a great strength of using an MVC pattern. If you put your data in a presentation model, you can put most of your view logic in there, then (using ASP.NET MVC syntax here) the only thing you have in your HTML is <%= ViewData.Model.SomeProperty %> and perhaps an if using a boolean property of the model or a loop using an IEnumerable<T> property of the model.
John Meyer on July 21, 2008 04:30 AMIf we have a ton of logic mixed in with an html (or rhtml or phtml or whatever) file, it might be time to start thinking about giving some of that logic back to the controller and splitting some of your potential view options into separate files, instead of trying to make one template file the do-all for a particular part of your site. If you have a bunch of conditionals in your template file, maybe you need multiple template files, and the code that they have in common can be put into one reusable file. Many times, it seems like we do the opposite.
Brian Warshaw on July 21, 2008 04:31 AMDitto on HAML. It's HTMLegant! ;-)
Ted on July 21, 2008 04:34 AMTo the PHP guys suggesting that you let your PHP spit out your markup:
This is fine if you're the only person who's ever going to adjust the view, but it makes the web developer the bottleneck, and it turns something that should be a fairly simple, mostly-static operation into a task for your application instead of a simple import.
Brian Warshaw on July 21, 2008 04:35 AMNormally to get around the tag soup I use literals and programmatically add the code there, you can then easily add a literal to a panel and presto, properly structured code without having to inject html in your code behind or inject code in your html.
Mauro on July 21, 2008 04:37 AMA lot of tag soup can be eliminated by using functions instead of coding every last thing onto every last HTML element/attribute.
Matt on July 21, 2008 04:38 AMEver since I read it, I've sworn by 4 Layers of Separation (http://particletree.com/features/4-layers-of-separation/) - Now I put all my content in XHTML files, headers, footers and the like in XSLT files, transformation code in PHP, and JavaScript / CSS in separate files. It's extremely flexible.
Victor Engmark on July 21, 2008 04:38 AMWhen it comes to messy mixes of markup and template code, HTML forms can be about the worst case.
In our codebase at work, we write forms in pure XHTML - with little or no template code in them. Then in the controller code, we "extract" the form from the view output and parse it into a form-centric DOM-like structure. From there, the request parameters can be loaded into the form, the DOM can be freely altered to change input values, add select options etc, and validation rules can be attached to fields. The resulting DOM is then serialized back into HTML and injected into the view - with validation errors when relevant.
I find this is an excellent way to deal with some of the worst culprits of the kind of tag/code soup you're talking about. It's pretty much the reverse of the more common "form builder" approach, which I've never found fun or productive to work with.
Paul Annesley on July 21, 2008 04:42 AMTwo things which work better than the tag soup tools you mention:
GWT -- create your UI programatically, rather as you would with a GUI toolkit, getting all the type safety, reuse and refactoring support you expect.
Tapestry -- You still have HTML templates with expressions in an expression language embedded into them, but the emphasis on creating reusable, parameterised components, and the matching of view components in your HTML to model components in your server side actions makes your pages much cleaner (http://tapestry.apache.org)
Tom Davies on July 21, 2008 04:43 AMJeff,
I feel you with the tag soup, especially in classic ASP. However, I just do not run into that in .NET 2.0 and later. I find that after combining user-controls, web custom controls, and judicious use of the render method that I've eliminated most server code from my HTML.
I'm so adamant about server code being mixed with my HTML that I've gone on a mission to make my teammates abandon the practice. Overall, our project may contain more user-controls but ever since we've found better ways to utilize web custom controls these multi-filed pieces have been removed.
The only time I'm finding myself using server-side code is when I'm working with JavaScript. Even now, though, I'm coming up with ways to build a set of best practices for our team to eliminate this server tagging.
I think you just need to revisit why you are needing these tags. If you're building a list or table, would this not be better done using XSL and XSLT (hopefully on the client; offload that work to the browser!)?
Mike G on July 21, 2008 04:43 AMIt does seem that the two approaches are to either output html with functions, or to intersperse it. I generally use PHP or perl at work, which means for the most part I do the interspersing.
Moving everything into functions will make the view look cleaner, but I've found that you can still end up with a situation where making the markup valid requires knowledge of what is inside those functions, so that ends up making the problem more difficult in the end, or it can.
Reducing it to just loops and printing helps.
I do find the lisp approach interesting though:
(dashes mean spaces)
(yaclml:with-yaclml-output-to-string
--(<:html (<:head (<:title "Hello, world"))
----(<:body (<:h1 "Hello, world")
------(<:p "Hello, world!!!!!!")))
It's not possible to get the nesting incorrect, but it's also very, very similar to what the output will actually be, so it's not just confusing things by requiring the use of helper functions that aren't immediately clear. You could manipulate or generate this with the same general utilities used to make other lists.
I haven't used it in production myself, so maybe it's terrible in practice. I find it interesting.
A small amount of tag soup is unavoidable (but done right, it *is* delicious soup!)
My solution when it comes to things like a CMS is to write a simple (although fairly crude) scripting language within the HTML that is the page content - this way the PHP/HTML soup is minimal, elegant and stupid and the logic is folded into the data.
To some extent, I do this in other areas, such as a navigation menu with sub menus displayed as a list. I will create a simple (not XML!!!) way to store the menu items in a plain text file, and parse that with PHP. An entry might look like:
# text | tooltip | url | sub-menu filename | rule
Home | Return to home page | ./ | index.nav | group = any
Admin | Administer the website | ./admin/ | admin.nav | group >= admin
And in the end, as long as you are clever with your CSS, tag soup is really only a few small a/ul/li/p/div elements here and there - if you're overwhelmed by messy code, it's probably a sign that your HTML is to blame.
Ben on July 21, 2008 04:51 AMHi guys, here is what your're looking for : TinyButStrong PHP template engine system. The best template system i've ever know.
Look at the article "Doing PHP templates of the 3rd kind" : http://www.tinybutstrong.com/article_3rd_kind.html
The syntax is clear and powerful, it really SEPARATE the program (php) from the view (html+tbs syntax).
It's under GPL, and way faster than smarty. Powerful modules, great help, ... a must have.
Take a look at the "Examples" and "Why use it?" and "5 Golden Rules" (http://www.tinybutstrong.com/support.php#goldenrules) and of course "Manual".
I'm actually writing a tuto about PHP 5 Objects with TBS, stay tuned !
(structured website)
And I've recently receive my CodingHorror Tee-shirt, sweet !
TiTi from FRANCE.
XML+XSLT /could/ be an answer to this tag soup stuff. Or some XML-based template engine.
Still, I think formatting your templates correctly will help a lot, even if you put in snippets of PHP/ASP/whatever.
That HAML stuff is scary. Is it supposed to be readable? =)
Jani Hartikainen on July 21, 2008 04:54 AMI second the comment on GWT...it truly is the best way I've seen to do a non-trivial web application developed by a team. You can brute force any framework/style on a trivial application and we've all written code that you're the only one who's ever going to see. GWT forces you to abandon all the bad behavior that we somehow accepted when we switched over to the web back in the old days. Traditional "heavy" GUI application development has all the right implementations, but the web forced us all to bail on them. Interestingly, I've seen very, very strong web developers struggle with GWT since it forces a rigor and style of thinking that they've never been accustomed to. If you've written apps in Swing, SWT or any of the traditional Microsoft UI tools, it's the way to go.
Mike Shaffer on July 21, 2008 04:55 AMThis is exactly why I've been so keen on placing as much of my code in the code behind files as possible while developing ASP.NET applications. For example, even though you can insert tags that show what value a control should be bound to, or what method should be called when I click a button, I want those declarations done in C# (or VB.NET) to provide clearer separation, and in my opinion easier reading.
There still is a code behind file for the view in MVC isn't there? It's been a while since I've taken a look at it. Couldn't that provide a way to ease some of this pain?
John Chapman on July 21, 2008 04:58 AMOne of the more elegant-looking solutions to this problem that I've found is PhpSprockets (http://code.google.com/p/phpsprockets/). It generates valid X/HTML in PHP so it becomes much easier to write your entire page in PHP. I haven't used it, though, so I can't say how good it is in practice.
Ian Potter on July 21, 2008 04:58 AMThe StringTemplate library (http://www.stringtemplate.org/about.html) aims to enforce strict model-view separation between model and text (of which HTML is a subset) generation.
StringTemplate (as I understand it) is a 'parser-in-reverse' generator - you specify rules as you would in a parser, but you generate, rather than parse, text with those rules.
Disclaimer: I've never tried StringTemplate, but Terence Parr also wrote the Antlr parser generator, which is splendid! And having seen that there's a Python port of StringTemplate, I may well have a quick go with it...
Stuart Dootson on July 21, 2008 05:05 AMThere are also TAL markups ( http://www.zope.org/Documentation/Books/ZopeBook/2_6Edition/AppendixC.stx, http://phptal.motion-twin.com/introduction.html) wich make the xhtml code to look like real xhtml.
PiotrN on July 21, 2008 05:09 AMAt a Microsoft Roadshow event I attended earlier this year, the presenters of ASP.NET MVC themselves mentioned that it wasn't for everyone; that half of the room would say "what's the point?", and they weren't far off. I was in the undecided crowd, because on the one hand I could see the value in not having everything as a WebControl, but there was a lot to lose in not using the WebForms approach, too.
I guess it's a matter of which aspects of the code you want to focus on. "Traditional" WebForms deals with each area independently, breaks it all up into manageable chunks and provides the IDE to edit each, whereas MVC, PHP, Rails etc throw you into personally dealing with all aspects yourself. They are all leaky abstractions, and to this end I can only conclude that until the language fully understands the problem, just like LINQ is starting to do with ORM, we can never have the web development grail.
As the Html namespace in MVC and the programmatic-markup approach in dynamic languages go some way to the required solution, I think the ultimate answer is for the language to truly understand your HTML, CSS and scripts. With such a tool, you could implement generic controls in the order you wanted and your markup (and where relevant, CSS) could be auto-generated to match. Yes, we do kind of have this with some templated .NET controls, but not in the sense that the language actually "knows" what it's doing as it follows commands.
I'm sure it's possible, but jeez if that isn't a formidable project.
Andrew Cameron on July 21, 2008 05:10 AMI found Amrita (http://amrita.sourceforge.jp/docs/QuickStart.html) to be quite interesting approach. Didn't try it yet though.
Miika on July 21, 2008 05:15 AMI use jquery's taconite plugin to avoid getting code into the presentation layer.
Goran on July 21, 2008 05:17 AMHave a look at smalltalk seaside. I don't know if it's a better way, but it's at least a different way.
Philippe on July 21, 2008 05:18 AMHmm... Java lets me easily define my own custom tags (parameterized and all) which cleanly separates the code out of the way. No need to mix tags and code (the older versions were doing this since they copied the MS ASP approach, thankfully that is no longer the case).
JL on July 21, 2008 05:19 AMLook, it's programming 101. Break up the routine into smaller, saner chunks. Partials and user controls work fine.
Matt on July 21, 2008 05:21 AMOn the java side, have a look at Wicket (wicket.apache.org).
Cleanly separated view template from code, small reusable visual/logical components, no tag soup at all.
Dave on July 21, 2008 05:21 AMWe've extended our PHP5 framework to auto-generate XML output. It also expects processing instructions and apply the linked XSL docs accordingly.
We've found it greatly reduced the amount of code we had to write - its now down to some form-processing logic, a bit of SQL, and XSL.
Using XSL as the templating language has other benefits too - we can "call back" to the framework and grab rendered XML for other pages (shopping carts and tag-clouds, for example), we can use the XPath doc() function to request page fragments from other sites, and we can easily switch output from HTML to JSON by switching the stylesheet.
Phillip Oldham on July 21, 2008 05:24 AMJeff, you may be interested by the TAL or Kid/Genshi approaches: instead of creating a new template language mixed in with the markup (or putting raw code directly as RHTML or JSPs do), they augment existing markup with custom attributes.
This has the following advantages:
* Usually, they mandate xml well-formedness, which means your output should always be well-formed
* Browsers ignore custom attributes (usually), which means you can preview the raw template code... most other template languages don't allow that
* They have access to existing XMLy technologies (e.g. Genshi uses XInclude for fragment inclusion)
I do prefer Django's approach though (a very restricted template language, forcing the logic either in custom template tags or in the controller/view code)
Masklinn on July 21, 2008 05:24 AMThere is also "Java annotation based HTML template system" which uses 100% clean html templates. It ensures the same separation between code and template as the StringTemplate system by Terence Parr.
http://jabhts.org
The binding between the html and the java code is done using java annotations, so the "coding overhead" is minimal. It's not fundamentalistic, so you can still output raw html if you want to.
It uses inner-classes in Java for providing extra scopes so your code doesn't end up as one huge class, but enables dragging in sub-modules by creating derived inner-classes.
I second the nomination for TAL: it's a very elegant templating language. But, as others have pointed out, the problem with your example isn't the templating language (it almost never is) but rather a failure to enforce a separation of concerns by overloading the view.
James on July 21, 2008 05:29 AMI have used PHP (awful for this problem) and Common Lisp, using a couple of different libraries (see http://www.weitz.de/ and Parenscript). The Lisp method as mentioned previously is much cleaner than any other tool I've seen used.
Taliesyn on July 21, 2008 05:29 AMHi Jeff,
Apparently the ASP.net MVC is working on cleaning up the views, so you're stuck with the poor templating code for now.
Have you seen what Genshi (http://genshi.edgewall.org/) are doing in comparison? They extend the HTML namespace with their custom attributes for for-loops, if-statements, etc. It's python based though.
It reads like a charm and is easy to work with in an XML IDE.
Ciao,
Shaun
Apache Wicket (and from what I understand, Tapestry and JavaServer Faces) avoids this problem pretty well:
Most of the HTML is loadable without any server running, and special tags in the HTML represent server-side components that have their own markup that is also loadable without a server.
Jim on July 21, 2008 05:30 AMThis is why I'm a fan of attribute based templating such as with TAL, where you can do things like:
<h1 tal:content="view/title">Title goes here</h1>
<ul>
<li tal:repeat="item view/items" tal:content="item/name">item name</li>
</ul>
You always end up with valid html and you're somwhat enforced to have a strict model/view/controller separation - you simply can't do anything fancy in the template and are forced to embed it in a view class (which is plain code)
I second (or third?) NHaml.
We're using the NHaml view engine with the MVC framework on a very large website and it's an absolute dream to work with compared to the default webforms view engine.
- JD
John-Daniel Trask on July 21, 2008 05:31 AMJSF can really help minimize this in java. I've written JSF pages with little to no regular HTML at all in them using pure JSF tags instead and using CSS to take care of the look and feel. GWT also seems like a good solution, though I've not had much experience with it yet.
If you do have to embed code into a page, really try to move as much of it as possible out to utility methods that can be unit tested outside of the page.
Alb on July 21, 2008 05:31 AMI think the bigger a project gets, the more important it becomes to strictly separate code and presentation. Mixing code and markup is fine for smaller web applications, but it get messy soon.
Java's JSF with Facelets (https://facelets.dev.java.net/nonav/docs/dev/docbook.html) is another MVC framework that uses plain XHTML for view construction. The only code is in the EL-expressions that bind page components to the model.
Daniel on July 21, 2008 05:32 AMI'd second the call for Seaside. It's a whole new way of working!
Rob on July 21, 2008 05:32 AMTag soup is indeed a big problem and you can find examples of it in every language and framework but the Rails code you posted seems absolutely amateurish to me, and I'm an amateur! All of the loop logic can be removed by using a partial with a collection, Rails *has* a method (cycle) to accomplish the even/odd row magic, and those absurd link_to calls can be cleaned up by a few lines in the routes file. These aren't advanced expert tricks either, these are the things pretty much any introductory Rails book teaches.
Personally I hate seeing variable declarations or any other script tags in my view code. I try to write my views with a complete non-programmer in mind; someone who doesn't even understand simple decisions or loops. Your views become a lot easier to read and it forces you to truly separate view from controller.
devonrtucker on July 21, 2008 05:34 AMWhat amazes me about Tag Soup as a problem is its longevity. Everyone knows it's a problem. There were some kick ass holy wars over the past decade in the JSP community surrounding it. The decision trended towards, avoid as much as possible and move the logic into HTML-like tags.
Of course, this didn't actually solve the problem, it just made it more readable....or so they said. It's obvious this wasn't the "solution". If it was, PHP, Ruby, etc. wouldn't be making the same "mistakes" trying to solve the same problem years later.
This makes me wonder how much of a "problem" it actually is. Certainly move your logic outside of the tags whenever possible. But:
<c:if test="blah"> is really not much better than <% if (blah) { %>
The solution chosen will gravitate towards the familiarity of the programmer. An HTML designer may gravitate towards <c:if> while a Java programmer would pick the pure Java construct.
Mike Cornell on July 21, 2008 05:35 AMI should make clear i meant outputting the HTML with "printf" type functions (echo) and not using the functions like the "property" one recommended above. (Although this may be a good idea for some)
My HTML is still inside my PHP, its just well enough wrapped to not be confusing... at least for me. Comments help too. :)
After looking at it a bit, ASP allows a similar method of writing a code module... it all comes down to personal preference at the end of the day, and there are a number of ways to make this "problem" manageable judging from the comments.
Jheriko on July 21, 2008 05:37 AMJani, XSLT is also a mess. It's a bit more readable because you use the same kind of markup to write html as well as to write xslt xml. The benefit here is that this setups really separates view from business logic. But it's still hardly readable:
<code>
<xsl:template match="article">
<div class="article">
<h2>
<xsl:attribute name="class"><xsl:value-of select="category" /></xsl:attribute>
<xsl:value-of select="title"/>
</h2>
<div class="body">
<xsl:value-of select="body" disable-output-escaping="yes" />
</div>
<div class="info">
<span class="comment">Sent: <xsl:value-of select="created" /></span>
<xsl:if test="string-length(updated)"><br /><span class="comment">Updated: <xsl:value-of select="updated" /></span></xsl:if>
</div>
<div class="options">
<a><xsl:attribute name="href"><xsl:text>index.php?m=articles&a=view&id=</xsl:text><xsl:value-of select="@id"/></xsl:attribute>komentarze</a>,
<a><xsl:attribute name="href"><xsl:text>index.php?m=articles&a=edit&id=</xsl:text><xsl:value-of select="@id"/></xsl:attribute>edytuj</a>
</div>
</div>
</xsl:template>
</code>
Dear. God. WTF?!
Tag soup is Eeeeeevil. This is the whole reason I switched to .NET, to get away from that crap. Now you're telling me tag soup is back in action on ASP.NET MVC? I guess I'll be skipping THAT beta test program.
Ivan on July 21, 2008 05:48 AMAnother vote for looking at HAML here. Just being able to lose closing tags is a boon for readability.
Another idea that Rails has (quite possibly borrowed/copied from somewhere else) is the "helper" function, where logic can be extracted to a "proper" code location.
With a few "pretend" helper functions thrown in (and there are other obvious ones left as an exercise for the student) I translate, the Typo Coding Horror above something like this:
- c, f = 1, 1
- for page in @pages
%tr{:class=>tr_class_for(page)}
%td.first_col= page.created_at.strftime('%d %b, %Y) #
%td= title_link_for(page)
%td= truncate(Post.strip_html(page.body), 50)
%td= page.permalink
%td.del_col= destroy_link_for(page)
- c = (c == 1 ? c + 1 : c = 1)
- f += 1
-unless @pages.length > 0
%tr.header
%th{:colspan => "5"}
.pagination
.prev
- if @page_pages.current.previous
=link_to '« Previous page', { :sort => params[:sort], :page => @page_pages.current.previous }
.next
- if @page_pages.current.next
=link__to 'Next page »', { :sort => params[:sort], :page =? @page_pages.current.next }
(If the spacing doesn't come out, then it's better-indented here: http://pastie.org/237819 )
Now I'm no Rails or HAML expert. Honest. But that looks a hell of a lot better to me, and I'd bet the effect would be similar in an ASP.NET environment. I'd like to see it, anyway.
Mike Woodhouse on July 21, 2008 05:54 AMXML + XSLT certainly helps, but if done naively you still wind up with XSLT code sprinkled throughout your HTML which can be hard to read. We eventually built lots of XSLT templates for the most common HTML that we produce, which at least localises the problem. See https://dev.youdevise.com/YDBlog/index.php?title=hiding_xslt_tag_soup for more details.
Douglas Squirrel on July 21, 2008 06:00 AMOne solution to the problem is to write your own HTML preproccess markup which will be changed into html before the page is being outputed to the client.
For example:
[row]
HTML_ROW
[field_one] [field_two] [field_three]
END_HTML_ROW
[/row]
The [row] tag represents a fictionall row object which will be edited and modified before the html is being loaded, then coverted to html and then insereted into the template.
I've started to use the nvelocity: http://www.castleproject.org/others/nvelocity/index.html for my MVC views, it's pretty quick to pick up and get working with.
Here is a link to an article explaining how to use it with MVC that i found interesting: http://www.chadmyers.com/Blog/archive/2007/11/28/testing-scottgu-alternate-view-engines-with-asp.net-mvc-nvelocity.aspx
Jeff,
I'm not that familiar with .Net web technologies, but this is one area where I love Java (and I assume .Net has something similar). Use XSLT as your primary view technology. You can add "custom tags" by defining a new namespace in your stylesheet.
Process the whole thing with the SAX api (SAX Source and Result on your XSLT). That way all of your logic can be in your .Net/Java code, and you can develop tags that are at the correct level of abstraction for your application. As a bonus, no tag soup in your XHTML output.
This is not as trendy as the current frameworks, but for programmers very flexible.
GWT seems like a good answer for programmers too, but I think there questions about accessibility. And of course 100K of Javascript is not always the first thing that comes to mind when people talk about REST.
Mark on July 21, 2008 06:08 AMJeeze, replace those <% XXX %> with <?PHP XXX ?> and that looks just like my crappy php.
LOL
Allen on July 21, 2008 06:12 AMRails solves this problem with partials to put logic as close to the beginning and end of the content (eg, wrapping the content in just a slightly different kind of tag, so as not to clutter up the actual content), the whole thing then gets placed into a larger template.
The downside to this, of course, is that you have to constantly be rendering multiple partials and that can be slow. But hopefully you're caching stuff anyway.
dude on July 21, 2008 06:15 AMI'm a j2ee dev that works on a form fill enterprise app. as such its pretty hard not to have tag soup but its generally in the form of <%= bean.getVar()%>
not exactly tag soup.
for all of our complex stuff we use taglibs which output the html. Is it confusing refactoring the taglibs? kinda, but once they are stable its not too bad.
At home i do some cakePHP, and i stuff all my server side code in an "element".
<?php echo $this->element('helpbox',array("helptext" => "Oh, this text is very helpful.")); ?>
that doesn't seem too much like tagsoup to me.
Yes it is just transferring the problem to a different area, but if i start editing the navbar element im likely to only see code that is relevant to the navbar, so i can focus on the relevant portion.
Tristan on July 21, 2008 06:19 AMNormal ASP.NET controls and web forms?
chakrit on July 21, 2008 06:22 AMIsn't this why templates were invented? What's all this fuzz I'm hearing about MVC in web programming? Are people just talking about it and not actually doing it? That code you posted looks like my PHP hacks from the early 2000s.
Anders Sandvig on July 21, 2008 06:24 AMJust echoing what others have said about .NET 2.0
I really have not experienced tag soup on this platform. User controls and such nicely seperate most complications and still allow our designers to edit the markup with relatively little stress.
Also as someone pointed out, in that example the HTML markup isn't great. It's a lot easier to have nice clean front end code with server side code interlaced when the HTML is simple and semantic.
Chris James on July 21, 2008 06:24 AMI'm a big fan of XSLT to add a further layer of separation. Conversion to XML from an object model is frequently trivial, and XSLT makes proper nesting much more verifiable than ASP/JSP/PHP etc. tag soup.
I really wish a few big players would jump on XSLT2, however, since a slightly simpler-to-use transform stage could really help.
Eamon Nerbonne on July 21, 2008 06:24 AMhow about Markaby ?
Trev on July 21, 2008 06:27 AMNo real clean way around it. No matter the "fix" as many have suggested, it causes other problems. Tag soup is an unavoidable problem of web development and it stems from the fact that in this unique environment you get to use several languages in one environment.
All sever-side scripting has this unfortunate drawback. However, I have noticed that's why companies would rather hire people with experience than those fresh out of college who probably cannot read mish mashed code very well. An experienced programmer can read the sometimes convoluted code. College kids have a much more difficult time in doing so.
If done properly, Jeff is right. You can write good tag soup. Too often though, I see bad tag soup. And as others have mentioned, when writing the code yourself that only you maintain its not that bad. You know your style of doing things. However, the problem comes when maintaining someone elses code and that is where things can get tricky.
Adam on July 21, 2008 06:33 AMI see someone mentioned Velocity for .net. That's kind of what I meant. With Velocity and or XML/XSLT with custom tags in Java you create your own (hopefully consistent) template syntax and you don't have to make such a big "soup". I guess I already assumed that's the kind of frameworks people were using (but then again, assumption, etc..)
Anders Sandvig on July 21, 2008 06:34 AMSeveral commenters have said it above. You should be doing as much logic as possible in the controller. That way it's testable that comments that are unmodded appear in red, as the logic for this isn't embedded in a page but are in the controller.
If your HTML page has too many <% if (... 's, its a smell that your controller isn't doing enough controlling.
Will Sullivan on July 21, 2008 06:34 AMGoogle is open-sourcing GXP, their (full disclosure: our) template language that has as one of its goals "strong restrictions against imperative code attempt to force separation of application logic and templates." There will be a presentation at OSCON about it:
http://en.oreilly.com/oscon2008/public/schedule/detail/3501
Mihai Parparita on July 21, 2008 06:35 AMCan I read the Typo soup?
Yes. Though, I'm not sure that's good. ;)
A few have mentioned custom tags; one example from VLDR:
item name
By the way...isn't this still tag soup?!
So far, everyone that's celebrated custom tags has had this tone that implied they escaped the soup. No, you didn't.
Personally, I've never understood the advent of custom tags, let alone custom attributes. Don't get me wrong, I understand what they can do. But, I don't need code that's trying to be incognito and hiding from me.
Seriously, code highlighting should not be a requirement to read the code.
Jon L. on July 21, 2008 06:37 AMThe example you gave is really ugly, but could be cleaned up. In a world where search engines and rich javascript are important, then control over the generated html matters. When you don't care, then using an abstraction layer like asp.net web forms is fine.
Part of the reason for the seperation of concerns is to allow developers and designers to work independently. So any templating solution needs to work with tools designers use and not require them to be developers to develop templates.
The ruby on rails way is nice, because of ruby's dsl abilities you can create a language just for templating and have the full power of a programming language.
I am a .net developer so until IronRuby comes out, I have been working on a django inspired template engine for my asp.net mvc project.
Mike on July 21, 2008 06:38 AMThe rails sample isn't that bad i think, althoug it could be better indented and some of the code had been moved where it belong.
For instance this line: (ignoring angle brackets)
% link_to (page.title == '' ? '[Untitled' :page.title), Site.full_url + '/admin/pages/edit/' + page.id.to_s %
should have ben simplyfied to something like this:
% link_to page.get_pretty_title, edit_admin_pages_url(page) %
and adding this to the page model
def get_pretty_title
return '[Untitled]' if self.title.empty?
self.title
end
Using MVC helps the tagsoup problem a lot...
The examples above look like rather bad examples. In "normal" code, you'd refactor and split it up in several methods; in the first example e.g. get_row_class, next_page_link, etc. This is possible (most) in HTML/code-combinations as well. In Java, one of the ways to do this is by introducing custom tags, in Rails you can user helper methods, include partials, etc. I'm sure there's something in ASP.NET MVC too.
(In fact one of the great advantages of Rails IMO is that there is a low entry barrier for cleaning up the tag soup - much lower than in Java.)
Jeroen on July 21, 2008 06:40 AM"item name" ?!?!
Ok...well, there was supposed to be more to that.
Try this again...
<li tal:repeat="item view/items" tal:content="item/name">item name</li>
Anyway the real reason its better to have soup is that a CSS developer makes the templates and decides how to get the page working, if it was just up to the severside dev then everything would look dogshit because they don't understand that hacks involved to create things they just know their drag and drop in many cases and that makes one thing… bullshit
Trev on July 21, 2008 06:42 AMI just use standard VB.NET / ASP.NET. With code-behind pages and ASP controls, there is very little tag soup. The worst of it comes with using Repeaters, and even then it's not too bad.
In my opinion, ASP.NET already took a large step towards solving this problem.
Sean on July 21, 2008 06:48 AMOn the Java side, I have used Struts along with Tiles. All the tiles deals with is the data (only logic as needed, for building tables, etc). The more the view only shows data the better, it makes it easier when the front end needs to change or if I want to reuse components.
Alex on July 21, 2008 06:48 AMFlex.
I'm serious. It solves the tag problem, as it separates the client side from the server side and provides quite reach UI.
Whether you want to use it here or not is another matter.
Pawel Rygielski on July 21, 2008 06:49 AMShameless plug on this topic: http://rassie.org/archives/178 , Lisp has the power to make this bearable.
Brevé is worth a look: http://breve.twisty-industries.com/ if you are writing Python.
Nikolai on July 21, 2008 06:49 AMSo basically to code in sane looking HTML, you have to abandon HTML. Great.
JMJ on July 21, 2008 06:52 AMDjango templates are very restrictive when it comes to adding logic and other functions. You have just as much in the templates as needed for the presentation.
I'm a bit puzzled that you present it as tag soup on the same level as other templates...
Now this takes me back. The good ol' days.
funbytebitstop on July 21, 2008 06:56 AMOne technique I've seen and like is Ruby's stock CGI library. For each supported HTML element, there's a trivial function:
CGI.HTML {
CGI.HEAD {
CGI.TITLE { print "Pagetitle" }
}
CGI.BODY {
#output page stuff
}
}
The only problem I saw with it (other than the naming) was that It needed badly to be updated to support cleaner, nicer HTML 4. (As it is, I think it outputs some ugly HTML 3.2 transitional.) I thought it was a really cool idea, as it basically just outputs a new open/close tag pair with each block. Of course, this can result in nesting getting arbitrarily deep, but that can be mitigated somewhat.
greyfade on July 21, 2008 06:56 AMSeriously, why are you mixing up the code like this. Testability goes right out the window, readability is thrown out with the bath water and maintainability is completely AWOL.
If you are expecting to go back to your code at anytime AND understand what is going on, then you have to eliminate that sort of mess. Code reviews are a great way to highlight these sort of problems. If you can't stand up explain this code clearly and concisely, then rewrite it.
I'm a keen advocate of the Presenter First (MVP) pattern; it gives you testability right up to edges of your application and removes a great deal of complexity from your UI layer.
The MVC pattern mixed with the ASP.Net model is not a good enough fit to work well, so I avoid that using that.
A little bit of architecture goes a long way. One complaint about Presenter First (MVP) is that is means masses of extra code - not true.
Try it, you might like it.
I don't get it. You're using ASP.NET. Why would you ever use <%= %>? That's just unnecessary. Any modern web framework should allow for the pages to be nothing but markup, using custom tags to replace all of that "tag soup" mix-and-match. There were several popular frameworks that allowed for custom tags all the way back in 2000, maybe earlier.
Emitting HTML from pure code, with no markup pages, feels nice to a software engineer, but it's useless in the real world, where designers (who can actually make your UI not suck) need something that looks like HTML to open with their own development tools.
ASPX + ASCX (+ Composite Controls, used very sparingly) give you everything you need to avoid tag soup, if you're using MSFT products.
Eric on July 21, 2008 07:16 AMAs someone admittedly way behind the web-dev curve, I just try and think about what I need beforehand and put as much in one place (in this case the server side ASP.NET code as possible.
If I have to use some tag/soupiness on the HTML side, I make sure I comment it clearly, and perhaps even document that in the code behind file of the page.
N on July 21, 2008 07:16 AMWow, I guess you must be really used to it... all the examples people showed here for code that is "more readable" seems even less readable to me :LOL:
I think the idea to do it all diagrammatically is not a good idea. Why would I want to have a program *DYNAMICALLY* create a *STATIC* piece of HTML? This makes little sense to me. That is like writing a Word (or OpenOffice) document, where you have static text, you just type and dynamic macros (inserting names, dates, page numbers, headlines, whatever). Why would I want all text to be such a macro? How does this make things any better to read.
I rather want the opposite, having everything static, but having everything static means no dynamic pages. Not a way to go either. I never did much else than PHP, that is when intermixing HTML and code (never used ASP or JSP or Ruby, ...) and here I can only add some tips:
1. Make as much static as possible. The page should not be a big PHP script with some tiny HTML elements inside. It should be a webpage (HTML) with some tiny PHP elements inside. Most parts of a webpage are pretty static, keep them static (this also speeds up processing enormously and keeps server load low).
2. Re-use your code. Don't put that the same PHP code that generates a menu on top of every PHP page. Instead create a script that only renders the menu and use it from everywhere. That way the menu is totally dynamically, but it won't break tip one, as including it makes it look like a static piece of code.
3. Only place PHP code interleaved between HTML code, that really renders the page. If you need functions, declare them in an external PHP (that is pure PHP only).
4. When you switch to PHP, make this PHP block self-contained. That is, don't use static HTML to open a <table> tag, then a <tr> tag and now have PHP code create a line of data (TD tags). If you remove the HTML code around (e.g. the table tag), your PHP code produces garbage! And if you remove the PHP code, the page is broken (okay, not in this case, I guess HTML spec allows a table to contain zero TD elements). If you have a dynamically generated table, for that you need PHP code, let PHP generate the whole table (even if this contradicts tip 1). That way you can easily alter all HTML code surrounding the PHP code (the code generated by the PHP will always be valid) and you can easily kick out the whole PHP block, the rest of HTML left over will stay valid (there simple won't be a table any longer on the page).
Mecki on July 21, 2008 07:22 AMI don't write tag soup.
Probably the best explanation of a the helper & partials concept, as used in a language which is well-matched to the web but not particularly hi-tech is the manual for the symfony framework in PHP:
http://www.symfony-project.org/book/1_0/07-Inside-the-View-Layer
When I code PHP I don't normally use symfony, but I do use an internal templating system which is remarkably similar.
ASP.NET, at the fundamental level, has one of the best systems for generating HTML. Microsoft has hobbled it with bad ideas and bad implementations (such as tying events to buttons, the specific implementation of the web controls, etc.)
The helper and partial concept can be brought to ASP.NET by creating user-defined controls. Start by defining a 'master template' that describes the HTML shell (the exterior chrome) of your application. The master template should have a few placeholders in it: at least one for the title of the page, and another for the 'body'; perhaps you have slots for sidebars, menus, and other variable concepts.
Your ASP.NET 'controller' then is responsible for selecting user controls that get fill in these placeholders. Ultimately you follow the same strategy all the way down.
Looping isn't bad, but conditionals are generally a 'bad smell' in template code. Some can be pushed into the model/controller (called entirely before the template code.) If it involves something really small, like the date handling code, it should get pushed into a helper (a function that draws a date.) If a conditional involves a significant chunk of HTML, the branches of the conditionals should be pushed into partials and the conditional logic restricted to the selection of which partial gets displayed. If a conditional involves most of the template, there should be more than one template, and the template should be chosen by the controller.
As for the web controls, the basic idea and interface of them is pretty cool. All this guff about attaching event handlers has got to go: that makes people all too confused about what happens on the server and what happens on the client. It ought to be possible to build something similar that uses hidden form variables to keep state instead of the broken 'viewstate' mechanism. (Lots of vendors tried that back around 1997... It didn't work back then... Why did Microsoft revive it?)
Paul Houle on July 21, 2008 07:25 AMI found the RHTML (html.erb now) syntax to be easy to read. What I find funny is that the MVC paradigm is touted as the best way to do web applications, but MVC lends itself to "tag soup" by its very existence and how it separates things.
I much prefer the old WebForms model of designing applications because there is no tag soup involved, its all tags (well, controls) and any "soup" happens behinds the scenes, so you don't have to worry about it. Honestly I never got why WebForms was seen as so bad, provided you used something like Model-View-Presenter.
I'm not knocking MVC, as I find it very useful, just that ASP.NET was supposed to get AWAY from tag soup and mixing HTML and code, and now it's going back to that because of MVC.
Wayne M on July 21, 2008 07:27 AMHi Jeff,
I actually started when I saw that rails, beig touted as really hi-tech and quite rocking *still* had a finger up its nose. The server-side templating was a major reason I never really took up rails, after fiddling with it a bit.
Server-side templating is an anti-pattern. The only way to get a clean web based application is to realize that there is a client. It's in the browser. It's suppsoed to communicate with the server through a well-defined protocol. End of story.
That way you get a way simpler server-side, and you need no magic or bizzare canned logic from xml files or what have you, to create a dynamic client.
I call it "Thin Server Architecture", but it's nothing new, in principle. A friend of mine has a similar concept called SOFEA (Service Oriented Front End Architecture).
And as how to write a client in JavaScript, well, it's 2008, you know. Quite a lot has happened to Dojo, for example, with data stores, message buses, offline storeage (with gears support), client side Django Templating and RPC stubs autogenerated from SMD (SImple MEthod Description) files.
Cheers,
PS
Yes. I can.
But it's harder to read than code that comes from a better design.
Practicality on July 21, 2008 07:34 AMusing HAML, that code is: (http://pastie.textmate.org/private/khz08x2rwnmqawsoncrmmq)
Still needs more refactoring, but better than erb.
- @pages.each do |page|
- css_class = cycle('', 'alt_row')
- css_class += ' inactive' unless page.is_active
- css_class += ' first_row' if page == @pages.first
%tr{ :class => css_class.strip }
%td.first_col= page.created_at.strftime('%d %b, %Y')
%td= link_to (page.title == '' ? '[Untitled]' : page.title), Site.full_url + '/admin/pages/edit/' + page.id.to_s
%td= truncate(Post.strip_html(page.body), 50)
%td.del_col= link_to 'X', Site.full_url + '/admin/pages/destroy/' +page.id.to_s, :confirm => "You are about to delete this page. This is permanent.\n\nAre you ABSOLUTELY sure?"
- unless pages.length > 0
%tr.first_row
%td.first_col{:colspan => 5}
%span.gray There are no pages at this time
- if @page_pages
%tr.header
%th{:colspan => 5}
.pagination
.prev
= link_to '« Previous page', { :sort => params[:sort], :page => @page_pages.current.previous } if @page_pages.current.previous
.next
= link_to '» Next page', { :sort => params[:sort], :page => @page_pages.current.next } if @page_pages.current.next
Jeff, others having tag soup does not mean that you have to have it as well. Using helpers instead of embedded logic can take away all the soup, and leave just the tags.
Your example below can be rewritten like this: (with haml and helpers)
http://pastie.org/237861
The point is not really to use HAML instead of HTML, but the main point is to have enough helpers that you can re-use in your code that having that soup is no longer a requirement. And I don't think that it ever was a requirement ... some people just don't know better.
And yes, you can write an article showing bad-code, there is enough of that on thedailywtf.com. When you post something like this, it would be nice if you could show some alternatives - and not just drop a piece of code that you don't like and expect miracles. (just imho)
I'm going to have to side with the folks that mention server-side asp.net controls. I realize this doesn't help standard Ruby or other languages/technologies that allow for mixing code and mark-up but addresses the problem well. I wonder if ReSharper will ever add a "Move to Code-Behind" option :-)
JMinadeo on July 21, 2008 07:40 AMThere have been a few mentions of Seaside (http://www.seaside.st/) which completely (and deliberately) eschews standard templates and relies on coded html builders and CSS.
There is a very good tutorial showing this in action - see: http://www.swa.hpi.uni-potsdam.de/seaside/tutorial and read the section on components - essentially you create code like the following:
renderContentOn: html
html heading: 'ToDo-List'.
html div
class: 'menu';
with: self menuComponent.
html div
class: 'list';
with: self listComponent.
Notice how there is a deliberate component model going on which allows for great refactoring and representing the problem in code.
For more UI things, there is Scriptaculous (and other UI tools) support which essentially spits out the relevant javascript from the builder.
This feels a bit like GWT - but with the power of the Smalltalk environment they do some very cool things that keep your model very straight.
I'm sure other frameworks could borrow some of the ideas from this - (e.g. its a shame that Groovy and Grails doesn't lift some of these ideas instead of adding to the soup with their GSP's) although the clever things done elegantly in Smalltalk might be hard to replicate exactly.
There is also some other neat things happening in Smalltalk on the back of Cincom's webvelocity: http://www.cincomsmalltalk.com/userblogs/mls/blogView?showComments=true&printTitle=WebVelocity_Behind_the_scenes_of_the_enhanced_Debugger,_Inspector_and_Code_Editor&entry=3392858654
Tim
TimM on July 21, 2008 07:40 AMThis seems a little risky using ASP.NET MVC at this stage. Its not even in beta1 yet and your using it for a major project. I can see some major re-writes down the road.
Now speaking of tag soup. I hated...hated the classic ASP way of doing that. It drove me crazy. I just don't believe any logic belongs in the presentation tier. If you do need some logic, that's what javascript is for.
Donny on July 21, 2008 07:41 AMIn Java you have a pretty rich JSTL tag library. If you don't find the specific tag you need, you can write your own in Java and reference in HTML with a simple tag. It keeps the code out of the markup nicely.
However, you can also go completely to the dark side and embed all the java code you want in your JSP (HTML) markup. JSPs will allow it, but no one really does that anymore. Tags are the way to go for cleaner markup.
Charles on July 21, 2008 07:46 AMHi Jeff,
If you have a chance check out GWT. You basically abstract out all the html and Javascript.
The short version is that you write a Java application (much like a desktop application in Swing) and it will convert the application to server code, Javascript, etc. for you.
Very very handy because the code is completely written in one language, it's all statically typed, and you get the full benefits of the IDE tools!!!
Stephane Grenier on July 21, 2008 07:46 AMHere's another vote for better attention to architecture. Fix the problem where it begins rather than obscuring the real issue with abstracted markup that destroys HTML's ease of use.
As a JavaScript/CSS/HTML/JSP developer whose's ramping up on Ruby on Rails, I, too, find the tag soup of ERB to be annoying. But it's silly to eliminate all the HTML from your ERB templates just so the code looks cleaner to Ruby developers.
In most shared development environments, you're going to have view-layer experts for whom coding in HTML and CSS is second nature. Forcing them to work with code in which their native languages have been replaced by obtuse helper methods is counterproductive.
Brian Dillard on July 21, 2008 07:50 AMThough my experience is limited to PHP and Django (and a bit ASP .NET), I really like the Django approach. It's a bit difficult to get used to it (the template language doesn't really allow much "code"; so basically everything has to be calculated in the Python View file, and the template only accesses the created data structure, mainly using for-each loops). The primitiveness of the template language forces separation of Python and HTML.
Also, I think having a template that is basically HTML has the advantage that non-developers can edit it. I suppose HTML-based templates could even be edited with WYSIWYG editors like Dreamweaver (this is probably difficult when using HAML).
Oliver on July 21, 2008 07:59 AMIn "webforms" asp.net I break up most pages into user controls. Each control is pretty "dumb", with a number of events and properties that are handled and set by the "parent" aspx page(s).
When you get this right you end up with a set of user controls that contain a lot of clean html and very little code, combined with an aspx that contains very little html and a lot of clean code (separated in the codebehind of course).
So I basically consider the problem solved for asp.net, at least since asp.net 2.0. It's more a matter of dicipline than anything else.
Back in Javaland, JSTL enforced some discipline -- if you restrict yourself solely to property access and control structures, it'll look pretty clean, and if you start pressing the % key, it's a sign you're doing something wrong.
In Microsoftland, just use WebForms already. This ASP.NET MVC stuff is just ridiculously undercooked at this point.
Mike Kozlowski on July 21, 2008 08:09 AMIsn't this just another case of "You Can Write FORTRAN in any Language"? You can create an unmaintainable mess in WebForms, ASPNET MVC, Rails, whatever. People that either don't know how or don't care to write maintainable code will take any framework you give them and build a shanty town.
No framework is a silver bullet. You just have to pick the one whose drawbacks cause you the least amount of problems.
Sean Scally on July 21, 2008 08:15 AMWhat Miika said. Check out Amrita for Ruby (http://amrita.sourceforge.jp/). I've used it on the job with great success. It's not the most polished library in the world, but it definitely does separate the model from the view in a way that the example you show does not.
Amrita does things the way a template engine should. It is very smart about a lot of stuff, too. Like you can put elements in your HTML template, and if there is no corresponding element in your data model, the HTML element gets zapped. It will automatically expand lists which is great for building out tabular data dynamically.
I found that occasionally I'd want to build a little "widget" in my code and plop that into the template, but in general you get a very clean, complete template that can be previewed directly in a browser with no data or server processing. You also get a very clean way to build up the data separate from the template.
Michael on July 21, 2008 08:17 AMBack in the 90's - classic ASP was supposed to be "better than CGI because MS uses threads" We quickly scrapped this mix of code and devised a template for new development that broke up a page into HTML, server scripts and client javascript sections. Oh - the horror whenever somebody has to dive into some old "mix-style" code that is still in use <s>
john on July 21, 2008 08:23 AMPsst...here's a hint - switch to Java - use custom tags -- use struts - it comes with everything you need to make clean, elegant web apps...
.NET has this idea of custom server side components, but they aren't generalized enough to defeat code-soup.....they're neat if you have simple problems to solve (kinda' like RoR)....but if you need to do anything half-way innovative - they're going to be trouble...
yes - soon .NET MVC will be available -- though, this stuff has been around in the java environment for a number of years -- if you can manage to switch to java...you would do much better. :)
Funny you mention Django, since the template language is very restrictive just to avoid the tag soup. The default Django kinda _forces_ you to write code in your code, not in the templates. Always a Good Thing.
tabo on July 21, 2008 08:32 AMWow, talk about a coding horror. And I should know, I use Typo. :-/
(N)Haml is your answer. It makes it very painful (not impossible) to put any code in your view. It's excellent at content structure, and mixes very very well with css and jQuery in a very web 2.0 fashion. You can call helper functions for coded web output instead of trying to put server-side code in your view.
Kevin on July 21, 2008 08:41 AMTAL ftw.
dnm on July 21, 2008 08:45 AMDump the ASP.NET MVC. Stick to ASP.NET Web Forms. It works and there is a separation of business logic and presentation. Done.. easy.
Steven Rogers on July 21, 2008 08:48 AMI think "tag soup" will always a problem with web-based development. The problem lies in the fact that, fundamentally, we are only allowed a few markup tags to express the visual panoply that is a well-functioning web app. The only real answer to the tag soup question at this time is to go back to client-server desktop-app programming. That's the only place that the presentation layer was configurable enough to be truly divorced from the rest of an app's structure, and still provide WYSIWYG screen layout. Flash and Silverlight seem to echo this functionality, but I think we haven't seen either platform provide a compelling enough solution for all the markup gurus to give up their < and > signs and make the jump en masse. I don't know if we ever will, given the current web standards and protocols.
Kelly on July 21, 2008 08:51 AMJust add a Tag Soup Nazi on your team.
Robert S. Robbins on July 21, 2008 08:53 AM@Ted
HTMLegance is the best pun I've heard in awhile. I must use it.
@James Avery
HAML seems to fit with YAML/Python very nicely. I love the indentation based markup. It does amazing things for readability and I must try it now.
@Jeff
I was a bit worried about you when you left Vertigo. More specifically I was worried about the content on your blog. When people make changes in their life it often biases their perspective. In your case, you seem to have separated Coding Horror and Stack Overflow for a wonderful effect. All of your posts are well researched and thought provoking and I go away feeling like I have a less biased perspective.
Thank you for your continued intelligent comments and please keep the posts coming.
There is something fundamentally better.
It's called Drupal.
I've never ever written tag soup like this when using Drupal. All your logic contains virtually no HTML. Whenever code generates output, you write a "theme function" for it, which contains the actual HTML. This function is overridable on a theme-by-theme basis.
This means your HTML is nicely separated and can easily be changed. The only "logic" you'll find there is for zebra striping.
See http://drupal.org/node/171188.
The most painful thing in web sites/applications, by far, is creating and maintaining forms. I'm sure most of you would agree with that. It's often one of the places where the most distasteful tag soup of your web app lives.
Drupal solves that too.
It has, by far, the most comprehensive Forms API there is. It allows modules to alter each other's forms, makes it easy to keep your forms secure, allows you to create your own (reusable) widgets, and so on.
And then you've only scratched the awesomeness of Drupal.
I'm obviously biased. But really, give it a try.
Wim Leers on July 21, 2008 09:06 AMI'm doing PHP. I write classes for most of the HTML controls that I would need and reuse. So, most of the time, I'll be using my own classes only.
On some minor cases, I'll let PHP to print out the HTML codes.
As for the header, footer or other files without much programming, I'll write them in separate files, then "include" into the files with lots of programming. I think separating them is good to make your programming source code readable.
Eng Lee on July 21, 2008 09:09 AMThe indentation could be better, but at the risk of sounding blasphemous, I think that this is perfectly fine. It isn't doing any real complicated business logic, just iterating over, escaping, and echoing out some variables. The Django example looks especially sane to me.
If I need to re-format this page 5 months from now, this representation is going to be a lot clearer to me than some control or function which generates HTML behind the scenes. It is amazing to me the complexity that we reach to in the effort to simply output a string to a browser.
There is nothing wrong with mixing code and HTML as long as that code is presentation-oriented, not business-oriented. ("Separating" presentation code from HTML through some other templating system or control framework isn't really separating it all, just obfuscating it IMHO.)
Nicholas Piasecki on July 21, 2008 09:10 AMIf MVC is so fugly, why not just use plain-old asp.net. No tag soup. And you still get the URL rewriting thanks to MVC in 3.5. I don't see a need for MVC at this point other than for Microsoft to compete for developers who are stuck in the Rails mindset. A decently architected n-tier asp.net solution is sufficiently sparse in page markup that the asp.net pages should be pretty easy to modify without messing anything up. At least there shouldn't be much (if any) server-client code co-mingling on the page (if you're using code-behind).
Robert Barth on July 21, 2008 09:16 AMASP.Net Webforms!
I know asp.net webforms has its own set of issues (large viewstate, less than optimal html markup, some others...), but I think these things can be improved on. I have been working on a large asp.net web application for a couple of years now and don’t really have a problem with tag soup.
One of my concerns with the asp.net MVC is this very problem of tag soup. The MVC pattern helps to separate your project into a model view controller pattern. Shouldn’t we also be trying to separate the html markup from any code?
Just my two cents.
Assuming you need to "home grow" these things, what about...
1. Creating a row generator method that returns a string with the proper <tr> code for your css class and such. I'd say have it generate your cell data as well, but that looks a little more complex and it might be nice to have each cell rendered with a different method.
2. This is where my ignorance of .NET MVC is at, but aren't ListView objects pretty flexible under MVC? You can use your databinding event to render all your code on the back end page, but don't have the weighty DataGrid object to work with.
Just a couple of thoughts. I've been seeing more and more online examples of fancy datagrid work lately where they are escaping the code as opposed to using some of code behind binding/rendering methods. I'm wondering if there is some kind of "programming shift" going on...
Sean Patterson on July 21, 2008 09:23 AMI know you probably consider your StackOverflow code to be private, but I wish you had just posted your ASP.NET MVC example page with the tag soup in it. The reason is because you've misled everyone into thinking that ASP.NET MVC forces you to write garbage like your example Typo code. And that just isn't true. A well-written ASP.NET MVC view will not have a lot of conditional logic in it, that will be in the controller or the services backing up the controller. The view should really only have some iteration code and variable echoes. You're going a long way to fuel people's misunderstanding and fears about ASP.NET MVC here with this post. But seeing some of your other comments and posts about working with ASP.NET MVC, I think maybe you are in the learning stage and havent figured out how to write a clean view yet. There are other examples out there, you should study them before you spend a lot of effort creating bad code.
Jon on July 21, 2008 09:27 AMThis really is more a question of good development practices.
The danger in getting too "soupy" in your templates, comes from putting too much logic into your templates. More logic = more soup = more for a developer to decipher and parse and understand. To that end, it really doesn't matter what templating language or MVC framework is being used -- if your developers don't understand (and execute) the concept behind keeping concerns separated, you're going to end up with a hunk of unmaintainable spaghetti.
I like the approach the Django developers have taken -- they *deliberately* kept their templating language simple, to encourage developers to keep the presentation free of all but the essential logic needed to display the content. Templates can output variables (with some filtering), do equality tests, for-loops... and that's about it. Anything beyond that, and the developer ought to be asking himself if it's really necessary to do in the template.
Matt Howell on July 21, 2008 09:27 AMThough I haven't had a chance to play with it yet, I think Paul Graham's ARC might get it right by integrating the html generation right into the language.
http://arcfn.com/doc/html.html
Jeff T. on July 21, 2008 09:29 AM<quote>
Welcome to Apache Wicket
With proper mark-up/logic separation, a POJO data model, and a refreshing lack of XML, Apache Wicket makes developing web-apps simple and enjoyable again. Swap the boilerplate, complex debugging and brittle code for powerful, reusable components written with plain Java and HTML.
</quote>
I think this is closely linked to the question of still representing everything in text. In doing so, there's no hard boundry between the view and control contexts.
James L on July 21, 2008 09:39 AMAbout five and a half years ago, I found an interesting alternative to tag soup in the wt (Web Templates) module of the jonpy package (short for "Jon's Python modules"). You can find documentation here:
Too bad this package doesn't seem to be maintained anymore.
Matt on July 21, 2008 09:41 AMThe key, as other commenters have pointed out, is to use a templating system that deliberately limits what you can put in your views/HTML templates. For me using Perl, that's HTML::Template, which can do only four things: include a variable, include another template, if/then/else logic, and looping over a list. Anything else belongs in the controller.
Mark Gardner on July 21, 2008 09:46 AMhttp://code.whytheluckystiff.net/markaby/
luke on July 21, 2008 09:53 AMThere is some religion that says mixing HTML and code is bad, ostensibly so we can separate the work of developers from the work of graphic designers, but after taking various approaches over the years I'd say mixing HTML and code can actually be a lot more straigtforward an productive. If I can have something like this pseudocode:
<% if show_list %>
<table>
<% for each list_item %>
<tr>...</tr>
<% /for %>
</table>
<% /if %>
I'd take that any day over having to tease out the logic into a code-behind and then figure out when to run as we basically do with ASP.NET.
The idea that we need to separate tasks between designers and developers is a bit of a red herring. Maybe it's a real concern for some people, but I've never worked on a project where there was someone responsible for creating production-quality HTML for a web application that wasn't a developer, so I don't that's a real end in itself. The goal is to have well-structured code and HTML in the appropriate places to support the application; some people may be more UI-focused than other but everyone working on production UI code (procedural or markup) ultimately needs to work together.
Marc on July 21, 2008 09:57 AMI'm using asp.net, and the aspx-Pages are clean from code.
You have to use runat="server" intensively, though.
<div id="divShow1" runat="server">
show this or not?
</div>
...
divShow1.Visible = loDocument.IsVisible;
or
<a id="divLink1" runat="server"></a>
...
divLink1.Href = "....";
divLink1.Title = sLang("translate_this");
And of course, massive use of Controls and self-written grids or other data-consuming elements.
Only in some seldom cases:
<span id="xx" runat="server"></span>
...
xx.InnerHtml = string.Format("you have [0} points", lnPoints.ToString("n0"));
you could live with code-free templates, but it's not an very easy way. But it pays off for multinational sites, where every sentence has to be translated and some content is country- or market-dependant.
tittrat on July 21, 2008 09:58 AMtype code =
string * attrib list *
the asp.net model allows for quite nice separation, if people just actually learned how to use it...
Eber Irigoyen on July 21, 2008 10:09 AMPersonally, I've been using template systems for the last few years.
Sure, you'd still need to battle the template language but I find it to be the lesser of two evils.
There is another option many have forgotten, ColdFusion. Now in version 8 with Adobe set to release version 9 sometime in 2009. CF has always embraced the tag syntax and yet does allow the traditional script approach if desired. So the tag soup disappears making the markup code within the view layer much easier to read. E.g.
<cfloop from=1 to=10 index=i>
<div>do something....</div>
</cfloop>
And now there are 2 open source engines for those who stayed away from using it previously due to the cost.
Just some food for thought...
The way your code is presented (that is, with syntac colourization) it looks fine, if a little busy. If I were pressed to make it easier to read, I would add vertical whitespace (uh, blank lines) to delineate the different languages, and I'd also keep tags on one line (the span tag, for example, below).
<% end -%>
<% unless @pages.length > 0 -%>
<tr class="first_row"><td class="first_col" rows="5">
<span class="gray">There are no pages at this time</span>
</td></tr>
<% end- %>
<% if @pages_pages -%>
Great column, keep up the good work.
Alex / talexb
In order to put data into the output format you have to have some form of tag soup because that's the only way to put information and display logic into HTML.
The question in my mind is more, are you a developer or web sites or a developer of tools.
Something like .net components or JSP taglibs allows the developer to off load data/widget to a tool developer by just calling a widget.
The two problems I see with that a) historically the people building a lot of those widgets produced markup that _sucked_ b) it's kinda inflexible
Tom Hughes-Croucher on July 21, 2008 10:33 AMJeff, I'm a little surprised at you on this one. You complained similarly about "tag soup" on the stackoverflow podcast, but it was you who recently championed "languages inside languages" (http://www.codinghorror.com/blog/archives/000989.html) and isn't that exactly what rhtml is??
The example you threw up on this post is horrendous, leaving WAY too much processing to the template (I think another of your readers mentioned that more could be done in the model to clean this up) I think it would be very very easy to write something that looked almost as ugly in plain old html.
Also just to throw my 2 cents out there, I think django templates are a particularly clean way of doing this code-embedded-html. (The django snippet you included in the post is clean and readable, isn't it??)
Justin Standard on July 21, 2008 10:43 AMI generally use a server-side language such as PHP for the entire implementation side of a web project and XSLT for the user interface. Simply use your server-side language to manipulate data, set up an XML structure of any data you wish to display, and send it off to your friendly XSL processor to create some XHTML for your users' browsers.
nutbar on July 21, 2008 10:49 AMYour tag soup example could be rewritten to be a lot more palatable. Just a few small refactorings would go a long way:
1) Change 'for page in @pages' to '@pages.each_with_index do |page, row|' and use the row index instead of f and c.
2) Change that strftime to 'page.created_at(:short_date)' -- with :short_date defined in ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS)
3) 'unless @pages.length > 0' could just be 'if @pages.empty?'
4) Extract the tr class code into a helper method: css_class(page, index)
5) Extract the edit & delete URL code into a separate helper method. I think you could further clean this up by changing it to something like 'page_url(:page => page, :action => 'edit', :host => Site.host)'
You chose a horrible sample RHTML file, perhaps on purpose?
1) Rails 2.1 RESTful link helpers clean up some of the tag soup
2) Using counter variables in the views? Not the right way to alternation.
3) The example used no partials.
4) The example used table layouts rather than table-less semantic CSS.
And if, with all that, it's still too soupy, you can always learn HAML, but that introduces a new level of abstraction. I prefer to shorten the page using a mixture of custom helpers + partials, when the page gets too busy looking.
-Ryan
Ryan Walker on July 21, 2008 10:57 AMI haven't figured out which is worse.
a) The horror of mixing multiple languages into HTML, which already tends to be badly formatted. Emacs (even milti-mode) is horrible at auto-indenting.
b) or, MVC (Model-View-Controller) models which tend to lead to file proliferation. In my currently project, it takes at least 5 files to create a single page: 3 JSPs (using Tiles), 1 servlet, and 1 bean. So, I have to open 5 files just to make certain types of changes to a page.
I can see each having their advantage and place. But, IMHO, neither is ideal.
Code like this "snippet" typically comes out of some of the finest Global Development Centers. And when I say finest, I am not talking creme de la creme finest. I am talking Creme Brulee finest. The talent in those shops is just unbelievable and they work for nothin'.
Readability of the code directly reflects clarity of the programmer's mind (about the problem at hand). Code/tag soup tells us that little Johnny was a bit confused (and probably scared) when he wrote this.
BugRree on July 21, 2008 11:17 AMNow imagine that you have to localize this.
The localizable text is allover, in code and in HTML, most likely with different escaping conventions.
How do you put it back? How do you keep 30 languages updated with any code change you might have to do?
Then try going beyond text changes: fonts, font sizes, colors, right-to-left, etc. Total junk!
Anybody looked at DTML that Zope3/Plone/Zope2 uses?
It's kinda good actually, everything is still a mess. But hey, you cant have it all.
http://www.zope.org/Documentation/Books/ZopeBook/2_6Edition/DTML.stx
<html>
<body>
<p>
This is <b tal:replace="template/title">the Title</b>.
</p>
</body>
</html>
Another vote for HAML. Its structured syntax (esp. indentation) is a huge win when it comes to readability.
Cody Caughlan on July 21, 2008 11:25 AMDitto on using ASP.NET Webforms!
MVC doesn't appeal to me and I wish Microsoft would stick with improving ASP.NET proper instead!
Ben on July 21, 2008 11:31 AMNice peace of work man, I liked it. Please tell me if you can guide me further for such a good work. Well, I saw similar brilliant stuff on dreamworltech.com few weeks back. please check it and give me your remarks.
John Wade on July 21, 2008 11:34 AMHi Jef,
The problem with that soup code is that it has too much logic in it.
You shouldn't use <% for %> or <% if %> logic in your views.
On the other hand server controls are not worth it. They simply add a lot of complexity in the codebehind trying to solve their own problems without solving anything for you. The only interesting use for server controls is to show/hide things.
I think that the secret is to balance rendering logic between asp and codebehing.
Although it is a different example, how about something like this:
<div id="containerPanel">
<div id="ordersList"><%= this.RenderOrdersList() %></div>
<div id="paginator"><%= this.RenderPaginator() %></div>
</div>
and in the codebehing:
protected string RenderOrdersList()
{
return Html.Table(this.Model.Orders,
new HtmlColumn<Order>("Id", order => order.Id.ToString()),
new HtmlColumn<Order>("Customer", order => order.Customer));
}
protected string RenderPaginator()
{
return Html.Paginator(Model.CurrentPage, Model.PageCount, Url, Resources);
}
where Html.Table() and Html.Paginator() are just helper methods that concatenate text.
Santi on July 21, 2008 11:40 AMWebObjects (which inspired Tapestry) solved the server-side tag soup problem by introducing a server-side <webobject> tag that had an id attribute which mapped to a .wod file that contained the name and paths of the server-side class and attributes. The server would see the <webobject> tag, look up its id in the pages corresponding .wod file and instantiate and execute the class with the correct attibutes.
WebObjects is pretty-much free now.
mj1531 on July 21, 2008 11:44 AMI think the problem that everyone seems to be missing here is that the browser and HTML were never meant to be a platform like this. All of the technologies that have been added to HTML (CSS, JavaScript, etc.) are all bolted onto the outside of a (somewhat poorly designed) markup language.
The fact that we even have to mix so many different technologies to get a working site is quite ridiculous.
I only saw one reference to Flex, and no mention of Silverlight, but I believe our only hope is that these next generation technologies can free us from the chains of our real enemy, the browser environment itself!
Seriously though, the GWT might offer some relief in the short-term, but as soon as MS or Adobe get a REAL "fat-client-feeling" engine working and accepted by the mainstream, the old HTML web apps will start to fall by the wayside. Then before too long, they'll come up with some great toolkits that let people build their own sites in the richer environment, and that's when it'll really hit the fan.
It might take a few years, but HTML is doomed, and it'll be gone sooner than most people think.
Chris on July 21, 2008 11:53 AMWe have our own template system developed over the past 6/7 years that doesn't allow for any logic in the views.. Just recently ported it to MVC as well, works pretty nicely.
Though it's a potentially different situation here, in that our developers don't touch a line of html/css and our implementation crew doesn't touch a line of 'real' code.. think it ends up for the best that way.
I never considered asp.net webforms / jsp tags to be particularly helpful, they only seemed to move the problem around a bit.. Tried having XSLT templating for a while, but by the xslt specification, it doesn't seem capable of really outputting functional html. (for example, at least .net's xslt parser will close <div></div> to <div />)
Daniel Pihlström on July 21, 2008 12:05 PMIf you like tags, it's cleaner just to take it all the way!
http://www.adobe.com/products/coldfusion/
It actually works out pretty well in terms of using server side logic to structurally output your HTML in an easy to read syntax that is also tag based.
M on July 21, 2008 12:16 PMSomeone's mentioned Zope's Template Attribute Language (TAL) already. I'll second that heartily. In all my experience with templating systems, I haven't seen anything more fastidious about separating logic from markup, while keeping the template GUI-editable.
It's a pity it's not used more widely (which is unsurprising because all of us are tag soup aficionados at heart, until it comes to editing someone else's template).
Kiran Jonnalagadda on July 21, 2008 12:18 PMNot sure how you solve the "tag soup" problem aside from just encapsulating it using something like ASP.NET server/user controls. I don't think going with tag-based constructs is the answer either. ColdFusion has that and it just feels too verbose.
One a side note, the lack of controls support in ASP.NET MVC is kind of a deal breaker for me. I've invested a lot of time/energy in learning ASP.NET Web Forms, page lifecycle, and control development. It just stinks that (at least for now) most of that doesn't play well with ASP.NET MVC. I wonder what the 3rd-party control vendors (like ComponentArt and Telerik) must be thinking!?
Craig on July 21, 2008 12:28 PMThis reminds me of Bourne Shell Server Pages (.shit, Shell-Interpreted Template) at http://www.hyperrealm.com/wtfd00d/shsp/
Quote:
The basic idea behind all server page technologies is this: rather than writing code that generates an HTML document on-the-fly by writing it out as a series of print statements, you start with a "skeleton" HTML document and embed the code right inside it. Voila! Instead of having a tangled, unreadable, unmaintainable mess of HTML embedded in source code, you have a tangled, unreadable, unmaintainable mess of source code embedded in HTML.
You can remove all logic out of views via template languages like Liquid, but at the end of the day, you're spending more time trying to make it clean than just getting the job done.
It also doesn't help you picked the most crusty Rails code possible (Typo). There are a number of ways to clean up the snippet you pasted.
PJ Hyett on July 21, 2008 12:42 PMI second (or rather, third/fourth/...) the TAL suggestion. TAL-compatible template systems exist for all important development platforms (Python, Perl, PHP, probably more), it ensures well-formed HTML (+X if you desire), and force you to separate logic and presentation by supplying only a very limited set of operations. foreach-equivalent loops exist (they are too essential), but counting loops don't. Likewise, there are no expressions except a boolean negation -- if you need to evaluate some complex boolean expression, do so in your code. No calculating, no string manipulation, just inserting pre-calculated placeholders.
Actually, most implementations allow some kind of custom extension, so if you are sure you know what you are doing, it's possible to add the missing capabilities yourself.
Toss in another vote for wicket. It's seriously by far one of the best, if not the best framework I've worked with. There is no tag soup, your logic peanut butter doesn't get into your html chocolate, and everything is nice. No, seriously. Go try it now.
Luke on July 21, 2008 01:12 PMOuch, Dave... this reminds me of one of your classics "You can write VB in any language"
Now you are not taking your own advice... tag soup is completely avoidable in ASP.Net... but it's also accessible. Your choice.
Jasmine on July 21, 2008 01:17 PMFor those concerned about MVC replacing Web Forms...
http://www.misfitgeek.com/Will+ASPNET+MVC+Be+The+Main+Web+UI+Platform+For+ASPNET.aspx
If I'm served tag soup as a starter, I would expect the main course to be spaghetti code.
(And by "main course" I mean the rest of the application)
But done well, a nice template language beats WebForm's runat="server" all the way.
I don't think Jeff understands webforms ASP.NET paradigm, if he did he would have noticed that it is the ONLY web framework which managed to completely eliminate "tag soup". And it is actually old news because Microsoft did it in 2002 with the first release of ASP.NET.
All those pieces have to be present to get rid of tag soup:
a) codebehind
b) html/server/web controls (for abstracting html and referencing/changing it in codebehind)
c) event-driven page-rendering pipeline
"Ruby Envy" my ass.
The code is for the machine, not for the person. As always, there is an uneasy balance between readability, scalability, performance, and well-formedness.
Mattkins on July 21, 2008 01:41 PMPersonally I think using a custom-tag based approach to develop reusable components a la JSP taglibs, faces and ASP.Net controls... You convert something like this:
<table>
{for (Row row : rows) }
<tr>
<td%gt;{row.value1}</td>
</tr>
{endfor}
</table>
Into something like this:
<grid col="rows">
<col field="value1">Value1 Header</col>
</grid>
It really simplifies things and it centralizes a lot of the html (esp. if you use things like JSP-based taglibs written as JSPs--very easy to modify).
Having the ability to introduce "macros" (which is essentially what sorts of controls are) can really clean up the UI code. And if you've got a halfway decent web guy it's also something they can be comfortable working with using their familiar toolset.
Sam on July 21, 2008 01:42 PMI think if you want to do this properly, you will end up at parts of compiler construction. If you really want to get rid of some tag-soup-stuff, you basically need a code generator with HTML (or XHTML) being the target language.
That basically implies that you define yourself a certain intermediate language. This language definately depends on your application, but in general, it ends up being some sort of sequence of lists of trees (and all that recursively).
This page would probably be a sequence of a blog entry (which consists of a list of paragraphs, which consists of marked up words, and so on)m a list of comments (which consist of paragraphs, and so in) and a way to input data.
I am not entirely sure how abstract you can get, and how abstract you want to get.
This abstract representation is generated by some database layer and passed to a code generator.
This codegenerator then just works like assembly generators or similar things. At first, it has to output a certain prelude, that is, CSS, the header of the page, news, blogroll, CSS, Javascript and all this nonsense. After this, it generates the proper HTML for the text, the comments, and generates a form for user inputs. AFter that, a certain exit code must be generated, in this case, it would be the body end, html end-tags.
That way, the abstraction from HTML would be as large as possible - it would be no problem to generate plain text, or even a certain UI-application.
I just think the problem with such a model is that its pretty much different from what most people think if the