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?
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 4: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 4: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 4: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 4: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 4:31 AMDitto on HAML. It's HTMLegant! ;-)
Ted on July 21, 2008 4: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 4: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 4: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 4: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 4: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 4: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 4: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 4: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 4: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 4: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 4: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 4: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 4: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 5: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 5: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 5: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 5:15 AMI use jquery's taconite plugin to avoid getting code into the presentation layer.
Goran on July 21, 2008 5: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 5: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 5: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 5: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 5:21 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 5:24 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 5: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 5: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 5: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 5: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 5: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 5: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 5:32 AMI'd second the call for Seaside. It's a whole new way of working!
Rob on July 21, 2008 5: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 5: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 5: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 5: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 5: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 5: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 6: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 6:08 AMJeeze, replace those <% XXX %> with <?PHP XXX ?> and that looks just like my crappy php.
LOL
Allen on July 21, 2008 6: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 6: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 6:19 AMNormal ASP.NET controls and web forms?
chakrit on July 21, 2008 6: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 6: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 6: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 6:24 AMhow about Markaby ?
Trev on July 21, 2008 6: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 6: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 6: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 6: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 6: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 6: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 6: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 6: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 6: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 6: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 6: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 6: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 6:49 AMSo basically to code in sane looking HTML, you have to abandon HTML. Great.
JMJ on July 21, 2008 6: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 6: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 6: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 7: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 7: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 7: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 7: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 7: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 7: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 7: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 7: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 7: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 7: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 7: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 7: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 7: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 8: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 8: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 8: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 8: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 8: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 8:41 AMTAL ftw.
dnm on July 21, 2008 8: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 8: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 8:51 AMJust add a Tag Soup Nazi on your team.
Robert S. Robbins on July 21, 2008 8: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 9: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 9: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 9: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 9: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 9: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 9: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 9: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 9: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 9: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 9: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 9:46 AMhttp://code.whytheluckystiff.net/markaby/
luke on July 21, 2008 9: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 9: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 9: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 Pihlstrm 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 1: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 1: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 1: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 1: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 they build web applications. Most say "I pull this statistical data from a database and generate that and that code in order to output", instead of "Right, I need a certain HTML-Generator that translates an abstract tree into HTML, and then, I need something that turns my relational data into such an abstract tree in order to output things. Oh well, its like that all the time if you apply compiler-internal ideas to other problems, even though the solution looks nice currently.
Greetings, Hk
Hk on July 21, 2008 1:53 PMI currently work, as a designer, for a large e-commerce site in the UK, and they don't use a template system like this. All the html is coded in functions within the web application.
The result of this is that the HTML and css is coded, by the design team, separate from the main application. This is then passed to the development team who must then rip it apart and stick it all in functions.
Not only is this wasted effort, the developers often get it wrong and break the html structure. Which then has to be ran past the design team again to figure out what the problem is.
Another problem is that if there is not development resource, then there can be no changes to the sites html. This means you can't get your design team to freely change the interface, as you require.
Not good. Templates are a much better solution for large sites, where you are likely to need a design team.
dbuttar on July 21, 2008 2:13 PMI hate even more "frameworks" that make you pretend you're writing a desktop GUI app and then generate a lot of convoluted and malformed HTML full of Javascript that happens to look like what you wanted.
Everything under my domain name passes validator.w3.org. With the exception of some extensions from the Web Forms 2.0 spec, which no browser supports anyway (but I want to avoid chicken-n-egg: browsers not supporting it because websites don't use it; I take the first step).
Nicolas on July 21, 2008 2:16 PM>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!"
I will third Flex. Haven't used Silverlight yet, but the promise seems the same.
I only found web programming platible once I could approach it like regular app development, with regular compiler and debugging support.
No tags at all, and one develops a distinct app that happens to run in the browser and communicate with the server -- a nice clean separation that is easy to program with.
Now whether the user likes it that much is another thing, depends on the app really.
Ray on July 21, 2008 2:21 PMI've always found it ass-backwards to have the code embedded in the HTML instead of the other way around. I can write a readable program that emits HTML.
---scott
I usually don't use code like that.
In PHP (Jeff, I know you hate that :-) I usually write a block of code at the beginning of the file, and then I set up some variables to print in the page template, just like this:
<?php
$title = getTitle();
?>
<html>
<head>
<title><?=$title?></title>
</head>
<body>
...
</body>
</html>
You chose a very bad example for python. Python supports templates by default. I tried them using pylons, you have simply to create a template like this:
<html>
<head>
<title>$title</title>
</head>
<body>
...
</body>
</html>
As you have the model, the controller and the view separated (MVC), when you call a template you can replace the variables on the fly:
t = getTitle()
render('/template.mako', title=t)
Things are very separated here, aren't they?
Andrea on July 21, 2008 2:31 PMWell, I guess that's the price you pay for jumping on the MVC bandwagon... You could have avoided that by using the out of the box, event driven ASP.Net.
But then this post would probably be a rant about viewstate or unreadable/non-css compliant id attributes.
Rob on July 21, 2008 2:31 PMIt always surprise me how some can call their solution the "right solution" for web development.
Some people argue that too much logic is in the code that Jeff posted above. But have you actually read the code? It shows page number, empty list text, etc. That is not logic, that is just user interaction and usability. Try writing the same code with asp.net form controls without using GridView, ListView, etc. For me logic is the "Create Product" and the "Calculate Income" methods.
ASP.Net is great, but ASP.Net forms is just terrible for anything but microsoft only standard asp.net forms. You tend to worry more about page cycle, viewstate, etc. then the actual pages.
anyway I would probably for the sport implement my own template system if that I could find did not satisfy me. A framwork does not have to be brain surgery.
Peter Palludan on July 21, 2008 2:33 PMI third the Haml recommendation. Jeff - try Haml (NHaml, in your case: http://andrewpeters.net/category/nhaml/) . Just write a single page and see what you think. The syntax weirds people out at first but once you've tried it, it is hard to go back.
Casey on July 21, 2008 2:40 PMHere, briefly, are the basic options in ASP.NET. (only looking at inline versus server controls and code-behind)
I never minded the inline for the output of simple values that are only for viewing. e.g. label controls and viewstate are overkill. It makes easy stuff quite easy to read what the layout is with
<h1><%= _movie.Title %></h1>
<h3><%= _movie.Director %></h3>
<span class="description"><%= _movie.Spoiler %></span>
and alternative can be, when databound (asp.net)
<h1><%# Eval("Title"); %></h1>
<h3><%# Eval("Director"); %></h3>
<span class="description"><%# Eval("Spoiler"); %></span>
or another alternative is to use server controls when you need more control and keep the markup readable.
<h1><asp:Label id="lblTitle" runat="server /></h1>
<h3><asp:Label id="lblDirector" runat="server /></h3>
<asp:Label id="lblSpoiler" runat="server CssClass="description" />
in the 'code behind' file, at some point in the page life-cycle, you'd write....
lblTitle.Text = movie.Title;
lblDirector.Text = movie.Director;
if( string.IsNullOrEmpty(movie.Spoiler) )
{ lblSpoiler.CssClass="missing"; lblSpoiler.Text = Resources("MissingSpoilerText"); }
else
{ lblSpoiler.Text = movie.Spoiler; }
The reason for the inline styles is allowing for non-coders to change the markup without knowing the code. Obviously this can go too far when there's too much tweaking that needs to be done, but the idea is flexibility. Personally I don't dig Eval, because it's always better to catch errors at compile time, but sometimes easy works just fine. Not every page will get your undivided attention, and it does have the utility of showing what is being used.
The other benefit of inline styles in ASP.NET is (usually) you can alter the output on a live system. If you do everything code-behind then you have to recompile and redeploy. [I say 'usually' because in Web Deployment Projects you can specify that pages are not updatable at runtime]
The problem is that real websites, with real logic, get messy quickly no matter where the logic goes. But when things get messy, it's easier to refactor in code than it is to refactor in html.
<%# (Eval("Prop") != null ? (Eval("Prop")) : Resources("PropNotFound"); %>
One thing in ASP.NET that I still find a bit persnickety is single and double quotes inside inline tags, and obviously this following is quite hard to read. I can't remember examples offhand, but there are still times inlining fails inside of some tags, but not others.
<a href='<%# Eval("Url") %>' title='<%# Eval("Title") %>'><%# Eval("Name") %></a> -- watch ' versus "!
At least MS, to their benefit, does allow flexibility. You don't always have to do it the same way, which is very handy. You can embed the name of events in the aspx file, but you don't have to (you can attach the delegate at runtime). You can just make a normal tag runat=server and then it becomes a member of the page. It can be a source of errors and frustration (knowing exactly where something is done) but that's an issue of DRY and following good coding practices.
Sometimes I curst that it's harder to write some forms of javascript because all the control names are mangled (based on the container they live in), but I get over it.
hombre on July 21, 2008 2:43 PM@Wheelwright: 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".
ASP.NET not only isn't the only framework that can avoid tag soup, the example provided shows that it didn't eliminate it; it made it possible to avoid (mostly). Many of the "current" books on ASP.NET still show tag soup examples.
@mj1531: WebObjects (which inspired Tapestry) solved the server-side tag soup problem ...
WebObjects is an incredible web application framework, with a thriving community. It does eliminate tag soup. And it does so many things so well. Thanks for bringing it up.
But regarding tag soup in general. ASP.NET has the tools to avoid tag soup in most cases. There are a few instances where dropping code into HTML would be hard to avoid, but it's definitely the exception, not the rule.
So, if you find yourself doing tag soup, realize that you're probably doing yourself more harm than good. Sometimes going back and refactoring to avoid tag soup is harder than doing it right in the first place.
Even languages that seem to promote tag soup, such as PHP, can avoid the mess if good decisions are made up front.
John B. on July 21, 2008 2:51 PMCoding horror cliff notes 2008-07-20:
Look, there is a problem. I don't know the solution, do you?
James A. on July 21, 2008 2:53 PMAfter a quick Ctrl-F through for Flex, I see only three references - I think that the signal to noise ratio ("noise" presumably being PHP, ASP and any <% %> stuff [Python Server Pages etc] is low enough for me to have to give Flex a fourth nod. The reason Flex (and similar things like Silverlight) can get around the tag madness is that they don't do HTML, so they define UIs declaratively in a manner much more akin to "normal" (desktop) application development. Since the page production doesn't consist of a top-to-bottom evaluation (basically a big Main function) you can write proper event-driven code and perform all the user interaction on the client, where it belongs, without having to deal with Javascript browser incompatibilities.
Without wanting to sound too much like a Flex fanboy, I have to say that it's a lot easier to write good code in Flex / Actionscript than it is in ASP/C#, HTML/PHP, or any other server-side framework. Write web services / REST services to deal with the server-side stuff and design a nice event-driven UI for the client. You shouldn't be worrying about transmitting forms over the wire in HTML. Try it, you might like it :)
Eric Greveson on July 21, 2008 2:58 PMHere's the solution: learn HTML and quit relying on frameworks to do something that you can't do yourself. http://agilology.blogspot.com/2008/07/tag-soup-sucks-hey-jeff-heres-better.html
Jeff Tucker on July 21, 2008 3:04 PMThere's another scripting language that I've found that Falcon (http://www.falconpl.org/) to be interesting. I haven't gotten to use it yet (other things are getting in the way :/ ), but the site uses Falcon and you you can see the source of any page. I think it's very clean. Of course, anything can be made ugly, so it still has to be done right.
MathStuf on July 21, 2008 3:26 PMA number of people mentioned XSLT. We have used it quite well for a number of years with some large clients. I try to make a small case for it in Views here:
http://www.onenaught.com/posts/8/xslt-in-server-side-web-frameworks
In short, it is not for everyone, but it can be very useful and encourages good application design.
A couple of comments also talked about how verbose XSLT is. Some of the example above were quite verbose themselves and can be a lot shorter making the XSLT far easier to read (e.g. instead of xsl:attribute, just write the attribute itself and use curly brace short hands, e.g. div class="{$someVariableName}".
What is nice about the XSLT approach is that you can create a master-template/nested master template kind of thing as well, letting you reuse templates even more.
Anup on July 21, 2008 3:35 PMYou're right in that the main example presented is pretty horrible. The syntax coloring makes it somewhat more readable, but you obviously don't want to rely on that.
I mostly do Django when it comes to web development, which several people have already mentioned as generally having a clean template language. A nice feature of it is the ability to extend templates and override some or all of the various sections.
For example, a sub-template might have:
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
...
Whereas the base_generic.html template would have:
...
<head>
<title>{% block title %}Default title text{% endblock %}</title>
...
This allows you to at least break up and abstract the tag soup slightly.
Eugene Kogan on July 21, 2008 3:54 PMThis isn't just an HTML problem... this is also a code generation problem in general. I've been working on an open source project called NBusiness (http://www.codeplex.com/NBusiness) and it is a DSL that uses templates to generate code for you. The templates I am making by default will use NVelocity (http://nvelocity.sourceforge.net/) to generate code for you and it suffers from the exact same problem (perhaps worse because you can't really make controls).
The other obvious option is to generate all of your code using the CodeDom which sucks so bad it makes tag soup seem wonderful.
Honestly, I think this only becomes a preferable solution when you NEED to control your output precisely. I mean, yes tag soup in ASP MVC is painful but so is designing CSS that is compatible with the crap HTML output of most of the default ASP controls... so it becomes preferable only when you need to control your HTML output.
I think the statelessness of the web really plays a part into the difficulty of generating HTML too.
Justin Chase on July 21, 2008 3:55 PMI'm surprised you're reporting this issue. I honestly am. I actually thought this is one of the problems reasonably solved pretty much everywhere by now. At least my daily work perception is that way.
I've searched through the responses on your blog entry for "Zope" and found a couple of references (some of them wrong, some of them enthusiastic but not directly on the point).
I'm a core developer and 'user' of the Zope framework and 'we' usually have the perception issue that we're solving problems that no-one has or providing tools for complexity levels nobody goes to.
We've had a technology call "(Zope) Page Templates" since about 2003 which allows to create "pull" templates by:
- Annotating the HTML/XML with attributes and tags from a separate namespace
- Have a parser/interpreter for those attributes that modifies the DOM of the HTML/XML
- Serializes it back.
Here's an example:
<p tal:content="string:foo"/>
<li>
<ul tal:repeat="x python:[1,2,3]"
tal:content="x" />
</li>
The language is probably turing complete (although that's not its purpose) and allows for more complexity than is usually wanted.
The expressions are written in "TALES", the "Template Attribute Language Expression Syntax" which allow simple statements of various
(registerable) types.
Within the expressions, a few top level variables can be defined. Ususally those correspond to your application's current model and/or view class.
Using view classes you typically avoid putting complex Python code into the template but reduce the attribute expressions to shorter attribute/function lookups:
<dl>
<dd>User name</dd>
<dt tal:content="view/current_user"/>
</dl>
This has been the standard of my work environment for about 5 years now.
Christian on July 21, 2008 4:04 PMI don't think mixing HTML and server code is a problem in general ; in fact, if your site isn't trivial you end up with some complex logic about loops, attributes, content, conditionals, and so on. Using even more abstraction is just plain wrong, because:
1) you generally want to control what the output HTML will look like, so forget about a 'builder' tool, like a series of doc.addParagraph(...), or doc.addTag("P",content,attributes) ... it's Ok for passing data through some XML markup, but HTML documents are generally to complex to keep a clear idea of what the output will be this way. Customizing the layout is going to be a real mess.
2) You want to use a 'template' library to avoid using too much logic inside your markup. This ends up being a joke, because you still want some logic, and you end up re-inventing a worse language that has to do loops, conditionnals, formatting, while your base language has certainly a better, more elegant syntax ( that's why I think Smarty is generally a waste of time ).
3) "simpler" intermediary language, like some XML markup then transformed to HTML through XLST leads you to the same pitfalls. You think you can avoid having logic in your markup, you end up reinventing another language, having to learn that language, learn some other technologies, to find out you get even more complexity.
The problem with tag soup is just the very same of any language in any situation when you lazily prefer writing spaghetti code than creating meaningful functions, explicit variable names, clear indentation, well divided problem solving, and so on. Any programming language embedded in HTML is OK for me, anything else is most probably a waste of time. What you really need is to do all the complex stuff outside that embedded HTML file : do the business stuff and read all the records you need in the controller, and when you need complex formatting or logic rules, do it in helper functions that you'll define in a library accessible from your embedded html. In that embedded HTML, use your primary language, except everything must be very concise and trivial. Anything non-trivial as to be in outside helper functions with meaningful names. How do we program in general ? When we write a method we make sure all the code is about the microproblem you're trying to solve through that method, and anything too complex has to be in other methods, right ? That's just the exact same thing happening here. Being in the middle of HTML markup doesn't mean you can forget those programming rules. It's lame to blame your programming language when you put yourself in a mess, and that applies here too.
So, for your typo example, it's not that bad, really. The "first row" and "even/odd" rows are recurrent problems that can be replaced by simpler helper functions, where counting and choosing the right string happen. Using ruby blocks it can even be rather more elegant than any half-broken template engine with poor syntax. Those temp variables could have been moved to helper functions. Generating links and labels could have been done more concisely, too.
That typo example is quite messy, fair enough, but that doesn't mean you can't clean it up. Don't throw out the baby with the bath water.
Your room is messy ? Hey, just buy some shelves. Burning everything isn't a solution, if you don't get the lesson you'll just get in the same mess again and again, burying your lazyness in layers and layers of dirty stuff you never wanted but that at least you can blame.
There's only so much form factor in text-based source code, that you either take a tag soup (as in ASP/JSP), or attribute soup (as in TAL). Lispish language offers the quasiquote, which comes pretty close to ASP/JSP, but maintaining some semblance of syntax sanity.
If only HTML5 is more like WPF, we'd have a clean separation of machine readable data and templates being processed on the client-side.
Some thoughts on view language design (interesting mostly only if you're designing frameworks): http://lhorie.blogspot.com/2008/07/designing-maintainable-view-code.html
Leo Horie on July 21, 2008 4:51 PMI don't think that flex and/or silverlight fix the problem of effectively marrying code to html, because they don't output html. It's not an apples to apples comparison, and not relevant.
The problem, you see, is html! I don't need another syntax that will, if it's to be as powerful (or broken) as html, will end up being almost, but not quite html.
It's very hard to create html that uses javascript (ie ajax) and proper css that really does work cross browsers for a decent sized web application while keeping everything easy to maintain / change and standards compliant and localized/globalized.
hombre on July 21, 2008 5:08 PMJeff buddy - this post falls into the category of "I don't know WTF I'm doing so it must be THEIR FAULT". And while some of that is true - it's also a bit on you friend. HELPERS are core to centralizing your View Logic. Rails, Django, blah blah framework - they all share this philosophy.
You can rewrite your mess quite easily and make it a ton more readable. This post is fail.
Rob Conery on July 21, 2008 5:37 PMI'm not a Django expert, but I believe their philosophy is that template engine only fills the template with properties of objects provide as context. Last I looked, Django's template engine didn't, by design, even support "obvious" language features like assignment. However, it does provide simple ways to do presentation specific things like time and date formatting.
In my humble opinion, you can't solve tag soup problem any better than that (perfectionist, pedantic and practical). In the real world web developers have to have direct access to the html/css so that they can apply hacks that allow 70% of browsers so render the pages correctly. That throws out all forms of light markup languages like markdown. Throwing more programming at the problem is unfeasible for the same reason and because then only programmers can make chances that should be doable for programming challenged web designers.
Bloodboiler on July 21, 2008 5:40 PMI'm surprised that no one seems to have mentioned Hpricot (which is included in the Camping microframework, both by the inimitable genius that is why the lucky stiff). It leverages Ruby to produce a really nice little domain-specific language specific to producing HTML. The code at http://pastie.org/238265 produces the following HTML: http://pastie.org/238267
Jeff Pants on July 21, 2008 6:01 PMThis kind of thing is a truly horrible and counter-productive technology in my opinion.
I took over a huge suite of manually written reporting pages implemented very badly by a completely undisciplined and careless coder (I refuse to call her a programmer) in jsp, html, Struts (with Java Action classes and custom tags) with a generous larding of JavaScript.
The first few months were very, very unhappy...lots of untraceable bugs...until I realized that I basically had to rewrite everything. What a huge waste of time!
Don't put your least experienced coder anywhere near this stuff as it will cost you much more time to unravel it than it took to create in the first place.
Sue W on July 21, 2008 6:22 PMGreat post keep up the Great work!!!!
Miguel on July 21, 2008 6:51 PMI thought MVC was supposed to eliminate that sort of thing - you know, all that "separate the code from the data" stuff.
Chuck on July 21, 2008 6:55 PMI think that Mako (the current default templating system for Pylons) has some features that help avoid some of the complexity. Some of them are features that other template languages have, but I suppose it's the recommended usage patterns that make a difference.
Generally what I like about Mako is template inheritance, defined "functions" (that are defined in templates) that you can namespace and call inside your templates for output, and an extremely limited number of tags that yet make up a fully complete template language.
I personally have found all my Mako templates very readable, until I start using gettext and have to put ${_(" ")} around all my i18n strings.
-Max
Max Kanat-Alexander on July 21, 2008 7:31 PM@ John B
I looked at WebObjects and granted you can avoid tag soup in simple/medium-complexity situations. That’s not saying much though because even old VBscript-based ASP with some kind of tacked-on templating can do the same to a limited degree (I know firsthand because I wrote DataTemplate class in VBscript emulating ASP.NET’s ListView with varying success).
However to completely eliminate tag-soup/spaghetti-bowl problem you need something like server-side DOM where every component on the page (be it plain html or control/template) can be traversed & referenced by id/index & programmatically changed.
Those changes should be done in event handlers corresponding to this component's lifecycle. For instance: for some kind of data-repeating control you should be able to have "row created" event inside of which you can use "findControl" method to find the row's first "td" cell. Then you can change, let’s say, this “td” cell’s background or hide it, or widen it, or whatever. Clean and simple.
You can also bind to objects in ASP.NET as you can in WebObjects (actually you don’t need .wod files because you assign properties directly in the markup or codebehind). However ASP.NET’s capabilities go well beyond that as I pointed out already because you have full server-side DOM seamlessly integrated with event-driven framework.
Vote 1 nhaml
Simon on July 21, 2008 7:45 PMThis brings back horrible memories for me. Back in the very early days of JSP, we saw a lot of this in the view. JSTL solved a lot of it. Having a standard set of iteration/logic/formatting tags mixed with a solid expression language is very helpful.
Mike on July 21, 2008 8:32 PM@ Wim Leers
"The most painful thing about web/applications is ... maintaining forms"
We are currently evaluating some implementations of XForms, and they seem to provide a *really* neat way to abstract various concerns. The standard itself recognizes a 'model' that each form uses, and you can do all sorts of XPath wizardry to do pretty advanced stuff without any tag soup or even JavaScript. E.g. hiding parts of the form that are dependent on the value of some other input, create neat 'wizard' forms, client side validation and alerts.
The only problem is that people seem to have lost interest in the whole idea, and the main people pushing the implementations seem to have moved on to other things .. But the technology itself is very promising.
Donny Daniel on July 21, 2008 9:37 PMMixing tags and code (the standard PHP way) is the worst possible way to develop a web app, that applies to templating like Smarty also.
I do everything as objects. The page is an object with methods like addContent and addJavascript. Every input type is an object and it knows how to draw itself. A form is an object, which is just a collection of input objects. And it's all based on objects generated from tables automatically.
Objects that know how to draw themselves, e.g. return html, is the best way to develop Web apps.
Steve on July 21, 2008 10:19 PMIt is very easy to let forms degenerate into this kind of cacophony using any web framework. Meeting a deadline often means having to declare something as "done" when it's really just a rough draft.
You can take the low road and say and use the intellectual crutch, "hey, it works!", and stop there. Or, you can try minimizing where you repeat yourself and attempt to make the code elegant. After all, wasn't Knuth who asked, "Programs must be written for people to read, and only incidentally for machines to execute."?
Also, to be fair to Rails, Typo was written originally written in the pre-Rails 1.0 days. Most people who wanted a decently performing Rails blog platform moved to Mephisto since then. A mountain of improvements with respect ERb, partials, pagination, and form generation have slowly been added as Rails has gained adoption.
Tony Perrie on July 21, 2008 10:23 PMJeff,
Take a look at the Eclipse RAP project at http://www.eclipse.org.rap. You can take a Java project that runs on a desktop and run it over the web with the minimal of fuss, because the API is the just about the same.
It currently renders widgets using Javascript but there is support for it to render widgets using flavour-of-the-month-framework.
A most distinctly different and interesting perspective.
Paul Norrie on July 21, 2008 10:28 PMThis is exactly why I prefer ASP.NET over ASP, JSP, PHP, and other similar languages. You can still do the inline stuff when you want to, but for larger pages with more "stuff" in them, all of the server logic is tucked away nicely in code-behind. It's always better to have a choice.
Joe Enos on July 21, 2008 10:29 PMDamn, that link should be <a href="http://www.eclipse.org/rap">http://www.eclipse.org/rap</a>
Paul
Paul Norrie on July 21, 2008 10:29 PMPart of the problem you are having above is that the inline html/javascript is just strings as far as the compiler is concerned. Thus the compiler can't help you confirm that the syntax of the emitted html & javascript is correct.
If you follow either the lispers or the smalltalkers (http://www.seaside.st/) you will see they both go in the direction of expressing their html in code, and thus the development environment can help the programmer keep it all straight.
In simple terms, what you have above is two language domains when you should have one.
Brett Morgan on July 22, 2008 12:01 AMThe only solution i see to this problem that is a little different is intermediate representation. Like generating an XML from the server side code and transforming it via a XSLT (But i think that it could apply to any intermediate representation of the data the view need and transformation language).
But i don't really know if it is better, only different.
virtualblackfox on July 22, 2008 12:30 AMIf you have low-level code mixed in with html markup you've already failed, you might as well dump your current technology stack and start over with perl print statements that include html. If your abstraction is that leaky it's probably not worth using at all.
Robin Goodfellow on July 22, 2008 12:53 AMThe person who wrote that code has deeply missed the point of MVC. He's put parts of his controller in his view.
I'm going to cause lots of screaming here, by mentioning the original (now unfashionable) P-word, but Perl has an excellent solution in Template Toolkit.
In the normal way of working, your Perl puts your data into whatever data structure is convenient and the template works with that. There's a simplified set of loops and conditionalsfor the design folks to work with, which do not resemble Perl at all.
It is possible to break the separation, even have the template driving the code if you must, but that sort of nonsense is strongly discouraged.
@Jeff Pants, I must admit that's a very elegant way to split hairs. I approve this method when it comes to produce data-oriented documents, like RSS feeds, data exports in XML, and the like. When you need real-world HTML you'll be needing to add conditional attributes, javascript events, and when it comes to tweak that HTML code to please all browsers, that level of abstraction is just going to be plain nightmare.
I agree with Bloodboiler, in the real world you want to be picky about you HTML output. Like @hombre said, HTML is the problem. And you can try as hard as you want, that problem isn't going to vanish because you hide it below your carpet. A designer absolutely needs to see what the HTML output will look like and anything trying to hide that HTML is going to fail once you need to refactor the HTML to change the layout or please all the browsers. You don't want to dig around generator functions to see where is that tag id you use in your ajax processing.
Atwood sees 20 lines of code he can't read and immediately concludes everything must be thrown in the wastebasket, without even wondering if it can be refactored, only a few guys mention we can use helper functions to tidy up that code, while about everyone else suggest square wheels so they can climb up stairs. Amazing.
Vincent on July 22, 2008 1:14 AMVincent sees 20 lines of blog and immediately concludes everything should be thrown in the wastebasket, without even wondering if there was more to the point.
Such as mentioning the existence of 'good spaghetti code' and postulating if there IS indeed a better way of doing things. Question (partially) answered I'd say from the reaction/comments received.
Josh Smeaton on July 22, 2008 1:58 AMThis was solved in the nineties. It was called enhydra xmlc.
The html didn't contain any markup other than html. Dynamic elements were marked with id-tags and then the DOM was manipulated.
With good helper libraries creating eg. tables was a snap.
There was also the added benefit that the template could contain mock data for the visual developers and demos, and it was then removed when used through the code.
Shame that it didn't go anywhere, the modern equivalent solution seems to be xslt, which is orders of magnitude more horrible, and visual designers can't use it.
Okay, I must be over-reacting and mixing OP with the soup of over-agreeing comments \o/.
That "good spaghetti code" metaphor is clever, like Jeff's mention to Operation was quite entertaining. But that's way beside the point.
Okay, so Jeff is just asking what we think, wondering if there is good tag soup, and I completely forgot that when I read following comments.
I got quite angry when I read that post about the subject :
http://paraesthesia.com/archive/2008/07/21/tag-soup.aspx
"Some folks argue they want that "tighter control over the HTML" that the tag soup provides. I, personally, am much less interested in hacking HTML. Let the framework do it for me. I'm more concerned with the business logic anyway."
1) promoting just-hide-it-under-the-carpet techniques
2) "let the framework do it for me" - doesn't work. a) either your pages are trivial and you don't need such a framework in the first place b) when you try fancy stuff the framework gets in the way so you miss the whole point having such a framework.
3) That classic "I, personally, am much less interested in hacking HTML" making the whole article absolutely pointless, basically saying : your bike sucks, I don't like you pedals, the saddle is uncomfortable, I don't want to use gears ... Oh, and by the way, I don't even like biking.
For the record, I liked RoR, using helper functions and partials. I'm now on turbogears ( python + cherrypy + genshi), not my choice, but not so bad. Toscawidgets is quite elegant to isolate html components, grouping the html template, required css, javascript and validating code in one place, and still having solid control of what the ouput looks like. With some tweaking, one can easily provide form validation after a submission or through ajax ( allowing real-time checks like username availability, etc. ) with the same validation code. genshi is more a template system than a tag soup, and I guess we have the best of two worlds since it's XML ( so it can be validated ) with python inside special attributes. With cherrypy's append_variables you can easily provide helper function from outside the template.
But really, if you want so much custom stuff your framework has to give you A LOT of control over the produced HTML, and that doesn't prevent you from keeping things tidy. I guess I'd like django if I had a chance to try someday.
Vincent on July 22, 2008 3:17 AMI think tag soup is development lag.
A big advantage of ASP.NET Web Forms on Ruby, JSP, PHP and ASP is the code behind, that separates the logic view of HTML.
The power of web controls in ASP.NET doesn't compare with tag soup approach.
We are step back (maybe until 90's) to bad old days and write ourself basic features that are provided (native) by ASP.NET web controls.
Hi Jeff,
I'm quite curious to know WHERE in Typo you found that piece of code, because I wasn't able to find it anywhere. And you can trust me on this point, I've writen most of the current views code. That's the reason why.
Cheers
Frdric de Villamil on July 22, 2008 4:06 AM@Santi:
"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."
This is utter nonsense. That's exactly the kind of logic that SHOULD be in the view - logic relating to the presentation of the content. What shouldn't be in the view is actual business rules (e.g. if an account is overdue any changes must be approved by a manager). Formatting and presentation logic SHOULD be in the view.
Wayne M on July 22, 2008 4:20 AMI am a fan of Eclipse RCP (SWT) and I think in web development GWT would be really helpful here. Once I had to write a web app in PHP. I hadn't known CakePHP framework back then so I wrote a tiny "GUI framework" which usage resembled say.. SWT or Swing. You could create views and buttons and tables as PHP objects, set their properties and then render them producing HTML output (something like this):
function onCreate() {
$table = new Table();
$table->addColumn("Name", "name");
$table->addColumn("Age", "age");
$table->addColumn("Credit card number", "card");
$table->setModel( $data );
$window->addWidget($table);
$window->addWidget( new SumbitButton() );
}
However all render() methods had to produce HTML and in case of more sophisticated widgets the code was quite messy. Lots of quoted HTML in there.
When I learned CakePHP I never used my framework again.. I guess dealing with tag soup is a lesser evil than trying to reproduce SWT/Swing-like design in PHP5. It didn't work for me.
mantrid on July 22, 2008 4:31 AMAfter skimming through the vast array of comments containing new and fancy ways of trying to avoid tag soup, some of which seem to make the problem even worse, I feel that one should just embrace tag soup and look at a much simpler option of formatting your code to make it more readable.
This is how I would have written the example Jeff showed us:
(I have replaced tabs with 4 underscores)
<% c = 1 -%>
<% f = 1 -%>
<% for page in pages -%>
____<tr class="c% if !page.is_active %>inactive <% end %><%= (c%2 == 0 ? 'alt_row'') %><%= (f == 1 ? 'first_row' : '') %>">
________<td class="first_col">
____________<%= page.created_at.strftime('%d %b, %Y') %>
________</td>
________<td>
____________<%= link_to (page.title == '' ? '[Untitled]' : page.title),
____________Site.full_url + '/admin/pages/edit/' + page.id.to_s %>
________</td>
________<td>
____________<%= truncate(Post.strip_html(page.body), 50) %>
________</td>
________<td>
____________<%= page.permalink %>
________</td>
________<td class="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 perrnanent.\n\nAre you ABSOLUTELY sure?" %>
________</td>
____</tr>
____<% c = (c == 1 ? c+1 : c = 1) -%>
____<% f = f+1 -%>
<% end -%>
<% unless pages.length > 0 -%>
____<tr class="first row">
________<td class="first_col" colspan="S">
____________<span class="gray">
________________There are no pages at this time.
____________</span>
________</td>
____</tr>
<% end -%>
<% if page_pages %>
____<tr class="header">
________<th colspan="S">
____________<div class='pagination">
________________<div class="prev">
____________________<%= link_to '« Previous page', { :sort => params[:sort], :page =>
____________________page_pages.current.previous } if page_pages.current.previous %>
________________</div>
________________<div class=next">
____________________<%= link_to 'Next page »', { :sort => params[:sort], :page =>
____________________page_pages.current.next } if page_pages.current.next %>
________________</div>
____________</div>
________</th>
____</tr>
<% end %>
I'm surprised by the amount of "this is cool/should work'
BUT I'VE NEVER TRIED IT.
wonderful that you are providing links to stuff you find interesting,
but if you have never tried it, than can you really say how well it works?
Jeff, should the same kind of posts appear on stackoverflow, it could be handy to flag those as suggestions rather than experience talking.
They still have value, but just not 1st hand experience....
Or so my best friend's sister's boyfriend's brother's girlfriend heard from this guy who knows this kid who's going with the girl who says so .... [paraphrased]
Eric on July 22, 2008 5:25 AMCorrect me if I'm wrong but the few examples I've seen of asp.net's MVC look pretty much like a ruby on rails ripoff : the controller, view and routing syntax are very much alike. Which is great, by the way.
Vincent on July 22, 2008 6:12 AMThe example you have feels a bit like a straw man put forward for your readers to tear apart - its full of logic that could have been elsewhere.
Templates (we are a PHP shop and use Savant) can reduce the issue of tag soup to insignificance if you can avoid the temptation of making them monolithic and full of logic. I think by and large thats been the response by posters above.
A declarative approach can also work - using XSLT is a declarative approach (with the option of some xpath logic).
wioota on July 22, 2008 7:00 AM@Rob Conery
Unbelievable Rob are you still advocating that sloppy style of coding where you embed tons of code in your presentation view? Rob you're doing it wrong! :-)
Getting rid of code-soup is one of the reason I like ASP.net so much... my code doesn't look anything like that monstrosity.
Kris on July 22, 2008 7:58 AMVincent,
MVC has been around a lot longer than Rails.
And, within the constraints of MVC, there isn't a lot of room for interpretation.
Obviously, Data Model, View and Controller objects need to be created. And it needs an adapter/router/dispatcher (whatever you want to call it) to connect the web paradigm of URLs to a corresponding controller object.
So yes, it is similar to Rails. But no, it's not a copy per se.
Shane on July 22, 2008 8:03 AM
1 point by mattmcknight 1 minute ago | link | edit | delete
I like using the builder approach in Ruby.
x.html {
x.head
x.body {
for i in 1..5 {
x.div(:id => i) {
"yo"
...
but my designer likes the templating stuff better. With a good IDE, it does become pretty easy to tell the code from the template.
matt m on July 22, 2008 8:06 AMAnother advantage of having clean HTML code is that it is much easier to go from design mockups to actual templates and back again.
Many people are on the defense here, saying that the example is over the top, and that it would be easy to do much cleaner with a little more discipline/ another 'mvc' framework. That's true in theory, but in my experience in practice if people can take short cuts, they will (at least someone in the team will), so if technology doesn't enforce separating logic from presentation code, many projects will end up with tag soup.
Eelco on July 22, 2008 8:20 AMAnother advantage of having clean HTML code is that it is much easier to go from design mockups to actual templates and back again.
Many people are on the defense here, saying that the example is over the top, and that it would be easy to do much cleaner with a little more discipline/ another 'mvc' framework. That's true in theory, but in my experience in practice if people can take short cuts, they will (at least someone in the team will), so if technology doesn't enforce separating logic from presentation code, many projects will end up with tag soup.
Eelco on July 22, 2008 8:21 AMWhy just not use a framework like the Google web toolkit to avoid all this. Use Java to program a website, and use all the benefits Java has to offer. Let the "compiler" translate all that good to read and maintainable Java code to web code. Then just use Tomcat to host your site.
This avoids using <place your technology here> with html all together. Off course there are other methods and frameworks if you don't like Google ;)
Dude on July 22, 2008 8:28 AM@Shane : for sure, I remember reading about MVC in a visual C++/MFC book back in '98 ! And that wasn't new already ... anyway, porting that paradigm to web applications can take several forms, design decisions, ... and I wouldn't say it's all about coincidences here ;-)
But if I mentioned it, it's more about setting the record straight, when I read microsoft kiddies saying, 'hooray, asp.net'MVC does it better than anyone else with its brand new concepts'. And guess what, the first thing they'll do is producing the very same code Jeff is mentioning in his article, that is, poorly written view code not using all the helpers available in their framework. And people will rant on MVC's tag soup while the problem is between the keyboard and the chair, starting the same cycle again ...
Vincent on July 22, 2008 8:34 AMDrupal avoids this very, very well.
Mark on July 22, 2008 9:21 AMZope's TAL is the better way - it doesn't invent it's own tags, and doesn't add foreign markup. All template control is done in attributes, so HTML stays lean, readable, syntax highlighting works as usual.
TAL howto:
http://www.zope.org/Documentation/Books/ZopeBook/2_6Edition/AppendixC.stx
PHP implementation:
http://phptal.sf.net
It could be that the real tax of the tag soup is the angle-bracket-tax. The inherant grossness of html makes hybridizing these things difficult.
Long story short I can't see us coming up with a better way of doing the same kinds of things. It helps to have a little of the functionality in with the markup. Keeps the designers aware of what's going on.
Even though you're playing Operation, at least you're not playing blind like you have to with regular asp.net.
Jethro Larson on July 22, 2008 10:20 AMIt is amazing how things stay the same, but with fancier tags.
For large applications, having most markup and javascript emitted from the server is safer. Perhaps the client side markup should just be "targets" for the emitted code.
I'm just glad you said all that because I, not being the most experienced, have always thought, "huh?" when it comes to MVC and templating. It always looked like so much mixed up. just because it wasn't server side code didn't make it more readable. You said "a necessary evil," and that made me understand I wasn't alone in my thoughts. Thanks.
john on July 22, 2008 11:27 AMGWT + java servlets + hibernate + mysql is a GREAT stack to use to avoid stuff like this.
GWT on July 22, 2008 1:49 PM@GWT - hibernate and mysql should have nothing to do with tag soup. Or does mysql now suddenly make my presentation layer that much easier to work with.
chico on July 22, 2008 2:22 PMYou need some proper tools.
Try JSP 2.0 custom tags to modularize presentation components, and use a proper MVC architecture. Spring framework is good.
Struts has been obsolete for 4+ years now, btw. Don't both learning or starting any projects with it. Avoid JSF as well, same guy who was responsible for Strut's design flaws. (Sorry Craig.)
In the Java world, we actually have the technology to build clean, modular, reusable & scalable OO applications. For the first time in history. Check it out.
Spring framework,
Log4J,
Eclipse IDE,
Tomcat,
Hibernate..
I agree. This is a poor strawman. This was 3 minutes of work, having to deal w/ the ___'s, and there's more we could do. I agree. HTML is crap, and it's all messed up, but it can be minimized.
<% pages.each { |page|
____class = cycle("first_row","alt_row","")
____page_created_time = page.created_at.strftime('%d %b, %Y")
____link_title = (page.title == '' ? '[Untitled]' : page.title)
____link_url = Site.full_url + '/admin/pages/edit/' + page.id.to_s_______
____truncated_body = truncate(Post.strip_html(page.body), 50)
____delete_url = Site.full_url + '/admin/pages/destroy/' + page.id.to_s
%>
____<tr class="<%= class %>">
________<td class="first_col"><%= page_created_time %></td>
________<td><%= link_to link_title, link_url %></td>
________<td><%= truncated_body %></td>
________<td><%= page.permalink %>_</td>
________<td class="del_col">
____________<%= link_to 'X', delete_url,
____________:confirm => "You are about to delete this page. This is perrnanent.\n\nAre you ABSOLUTELY sure?" %>
________</td>
____</tr>
<% } -%>
<% if pages.length == 0 # This was a needless unless?!?! -%>
____<tr class="first row">
________<td class="first_col" colspan="S">
____________<span class="gray">
________________There are no pages at this time.
____________</span>
________</td>
____</tr>
<% end -%>
<% if page_pages %>
____<tr class="header">
________<th colspan="S">
____________<div class='pagination">
________________<div class="prev">
____________________<%= link_to '« Previous page',
________________________________{ :sort => params[:sort],
__________________________________:page => page_pages.current.previous }
________________________if page_pages.current.previous %>
________________</div>
________________<div class=next">
____________________<%= link_to 'Next page »',
________________________________{ :sort => params[:sort],
__________________________________:page => page_pages.current.next }
________________________if page_pages.current.next %>
________________</div>
____________</div>
________</th>
____</tr>
<% end %>
@Tim,
I simply used UltraEdit to convert my tabs into 4 underscores :)
Stephen Hill on July 23, 2008 1:45 AMI think the use of left and right angle brackets do no ease the reading of RHTML, its syntax is also way to permissive.
Samori Gorse on July 23, 2008 2:26 AMThe only framework which trully separates HTML from the code is rife:
http://www.rifers.org
The templating engine "only" support putting/binding values/objects into the template, and appending blocks in a template.
No foreach/if_then_else or anything else.
Temnplate part Example:
<table>
<tr>
<td>usernumber</td>
<td>firstname</td>
<td>lastname</td>
</tr>
<r:v name="results"/>
</table>
<r:bv name="result">
<tr>
<td><r:v name="RESULTBEAN:usernumber" /></td>
<td><r:v name="RESULTBEAN:firstname" /></td>
<td><r:v name="RESULTBEAN:lastname" /></td>
</tr>
</r:bv>
In the java Code (an Element in rife) I would fetch the data from the DB, and foreach result would do an:
template.setBean(result, "RESULTBEAN:");
template.appendBlock("results","result");
<r:v name="RESULT:lastname" /> can also be written as ${v RESULT:lastname /}, somtimes this is clearer.
Huibert Gill on July 23, 2008 2:31 AMSeaside works on the principles that components know how to draw themselves:
http://www.seaside.st/documentation/subcomponents
There was a very interesting talk/rant on the web recently by a guy who says that modern developers have forgotten some of the core principals of Object Orientated development - such as objects knowing how to render themselves onto a canvas - but I just can't find the link. It might have been by the same guy who claimed "Object Orientated" programming should have been named "Message Orientated" programming, to avoid people missing the point.
If you don't have the HTML made for you by a Web Designer (i.e. you have to generate it yourself and let them style it with CSS) then this approach could work:
which is based on Markaby.
James on July 23, 2008 3:55 AM@Huibert Gill : what if you need to add "first" or "odd" and "even" css classes to your table's TR, for example ? I would guess that all that logic has to be in the controller, who does all the loops, conditionals, puts these in variables sent to the templates ... yeah, I've been doing that 8 years ago, and it makes the controller way too dependent on the view. Or you divide even more the processing with a controller for business logic, then a separate template-unroll method, then the template itself ( instead of having that template logic inside the template ). Great if it's working for some people, but while it's quite pure, for sure, such ways of processing templates have been abandoned for a reason ..
Vincent on July 23, 2008 4:45 AMWhy aren't we tired of discussing this problem already? Just use an engine like Haml if you don't actually want to write the HTML itself or want your designers to mess with it.
Use a templating engine like Smarty if you want to write the HTML and are having problems with separating concerns, Smarty will almost force you if you abstain from the {php} tag. Tiny but strong also looks neat even if I don't like the way the assignments are done per default.
A combination is also possible like the one I'm using with Pico Lisp: http://www.prodevtips.com/2008/07/17/templating-in-pico-lisp/
Henrik on July 23, 2008 4:57 AM@Wayne M
I agree, the business logic should be in the controller. In the view you should have only the rendering logic: just loops, coditional show / hide, etc...
The best way to avoid that kind of tag soup is to balance the logic through the .aspx file and the codebehind file. For instance, if you need to render a table it is easier to concatenate strings in the codebehind and just call a protected method from the .aspx file.
Anyway, the real soup here is the comment soup, what a post reaction!!
Santi on July 23, 2008 7:35 AMI'm completely confused by this post. Tag soup is not an issue in asp.net. Not just in version 2.0 onwards either. in 1.0 there was absolutely no need to write such confusing and messy code.
This makes me understand the reasoning behind the PHP sucks mentality. Whilst I am not a PHP coder, I have seen code written like the Tag Soup you have shown, I have also seen some extremely neat and easy to understand code.
We write all of our asp.net applications as if they were winforms applications. There is no need to embed the code within the visual layout of the page. You wouldn't be writing script tags like that within the layout of a winforms application, so why do it in a webform?
PHP sucks and ASP.NET sucks. No. Just a lot of PHP and ASP.NET developers only know how to write code that sucks.
Robin
Robin Day on July 23, 2008 8:08 AMTake a serious look at GWT. I think its the most effective approach for web apps (but maybe not necessarily textual content-heavy sites that need to be indexed like a wiki, blog, or news site). I hate the tag soup too (in my case its JSP/JSTL I have dealt with), hence why I'm using GWT for my web apps.
There are also a lot of misconceptions about GWT leading to invalid criticisms. Take the time to study it before dismissing it.
n on July 23, 2008 9:05 AMThe solution to this is easy:
Use a new "pseudo" language.
One that is very close the how you "think" with web apps.
markus on July 23, 2008 11:56 AMxml+xslt will kill tag soup.
Unfortunatly there isn't good support to the twins
Many posts here claim that ASP.NET 2.0 nicely avoids tag soup. Although Jeff told us "Do Not buy This Book" (The ASP.NET 2.0 Anthology: 101 Essential Tips, Tricks & Hacks, http://www.codinghorror.com/blog/archives/000971.html), I did, and I almost got crazy on pg. 126, where they praise the "declarative" nature of the GridView control.
What *I* see is an .aspx page, which is usually a HTML page (the soup) containing server side controls (the vegetables in the soup). For beauty's sake, they just printed the controls, but what *I* see is, besides a complicated GridView declaration: a literal SQL query in an asp:SqlDataSource with a special SQL parameter syntax!
What Microsoft sells as declarative programming at least to me looks like a morbid collapse of the database backend (SQL queries) into the the view frontent (the HTML page).
I learnt declarative programming at university with Prolog and layered architecture (database backend, object model, page controller, HTML template views) on the webapp dev job, and I did well with it.
As a variation of http://www.codinghorror.com/blog/archives/001147.html, all what comes into my mind on the ASP.NET 2.0 topic is "No, I will not buy into asp:GridViews with asp:SqlDataSources. And no, I DO NOT NEGOTIATE WITH TERRORISTS."
tarnold on July 24, 2008 6:12 AMThe structure will be a lot clearer if you turn word-wrapping off. Then the indenting will not be interrupted with continued lines. Also, it helps to have proper syntax highlighting for the ruby code, instead of making it an orangey smear. Finally, it helps to have a syntax highlighting that mutes the angle brackets.
That said, are you sure this code is from Typo? I cannot find it anywhere there.
Matijs van Zuijlen on July 24, 2008 6:49 AMHonestly, the best way AFAIK to avoid tag soup is to forego tags altogether, and produce any HTML programatically, ala Perl's CGI.pm:
http://search.cpan.org/~lds/CGI.pm-3.38/CGI.pm#CREATING_STANDARD_HTML_ELEMENTS:
Evan K on July 24, 2008 7:59 AM@Tarnold: "What Microsoft sells as declarative programming at least to me looks like a morbid collapse of the database backend (SQL queries) into the the view frontent (the HTML page)."
All the problems you describe can be completely avoided in ASP.NET:
a) all the attributes in GridView declaration can be moved to codebehind so they no longer clutter-up the markup
b) SqlDataSource can also be moved to codebehind or better yet replaced with ObjectDataSource which is more flexible
What you criticize is some techniques which are best used for explaining programming concepts, for real production code there are better ways. As usually Microsoft gives you lots of choices and you apply it based on specific circumstances. If you do it right you can 100% avoid tag-soup.
Wheelwright on July 24, 2008 9:53 AMThe solution is the same as with normal code:
>>> REFACTOR! <<< :)
With server-side controls like in asp.net you can reduce all the mess into something like this:
<HtmlHeadBodyAndAllOtherCrap>
<Header>CodingHorror</Header>
<NavigationBar />
<RoundCornerBox><GetBlogPostFromDB id="1"></RoundCornerBox>
<RoundCornerBox><GetBlogPostFromDB id="2" /></RoundCornerBox>
</HtmlHeadBodyAndAllOtherCrap>
Of course you can probably do the same with some custom made template engine.
You're always going to have server side code in your views... it's all a matter of intelligently writing your controllers to make sure that by the time your view loads it's mostly just variable placement.
I agree with the previous comment... if you find yourself knee deep in tag soup perhaps you should consider breaking your view into more / different pieces and doing your logic in your controller.
Keith on July 24, 2008 7:21 PMI'm using CakePHP 1.2 now. I cannot begin to explain how good this framework is. You really need to use it to see all of the points where the mundane work and even slightly more difficult work is simply lifted off of your shoulders.
In your view thought you can use any number of the built in helpers to solve this issue. Since they are built in and not homegrown any Cake developer will be right at home with them. http://book.cakephp.org/view/181/built-in-helpers
Most notable are the HTML, Form, and JavaScript helpers. Also extremely helpful is the RSS helper.
Erik on July 25, 2008 8:20 AMXML + XSLT works so well for this problem that I was naively doing web development for two years before I discovered that this "tag soup" thing was apparently a problem.
You're still left with the ugliness that is DHTML, but we're not quite ready to start building our web sites in WPF yet, are we?
It is perhaps not a coincidence that a person who finds XML to be useless also finds that tag soup urgently requires our attention.
Bob Rossney on July 25, 2008 9:37 AMin the ideal world i am occasionally guilty of slipping into, html is html with no server side influence. all dynamic portions of a page are introduced after the dom is loaded via ajax. everything is perfectly tieed.
unfortunately this ideal can not exist in the wild while users have js turned off and and any sense of commercial responsibility remains. your content must be indexed.
however, with care, a close approximation to this world is possible.
sean g on July 25, 2008 4:55 PMIn the Java world, almost all frameworks are not tag-soupers. Non-XML server-side code mixed to HTML practically doesn't exist on modern Java web development.
Rodrigo on July 25, 2008 6:09 PMThis has always driven me batty. Moreso now that I work primarily in PHP. It gnawed at me with ASP and Rails as well.
The comments: TLDR. I did a quick search for Enhydra-- I've worked extensively with it for years. One match! That guy knows the score. Absolute separation between markup and code was great. Java? Not my favorite codebehind. Ruby or Python would be glorious.
Allowance for both modes is what I'd like to see. Then it's all about balance. Your post on normalization vs. denormalization comes to mind. Salivary glands: Activate!
Chuck Rector on July 25, 2008 6:48 PMStaged Architectures.
Here you go:
http://st.inf.tu-dresden.de/Lehre/SS07/cbse/pdf/40-staged-architectures.pdf
M on July 27, 2008 8:49 AMHave any of you checked out Lilu? http://www.infoq.com/news/2007/07/mockup-driven-dev-lilu
It's a templating engine for ruby which lets you leave the html produced by the design/front-end team more or less completely untouched, as pages are created by populate lists, form fields, etc, by using css selectors from within ruby.
Erlend on July 27, 2008 12:20 PMDjango example doesn't have any "server side code", it's all presentation code. Django uses templates that are not even Python itself, it's a simple markup like PHP's Smarty. No way to compare it with old ASP, or PHP, or embedded Ruby. Get your facts straight.
Henrique on July 27, 2008 1:36 PMLasso is a good choice if your project warrants the expense. The templates you create with it are entirely human readable. Lassos own tags are delimited by square brackets so they stand out between angled brackets of html. Matter of fact it looks a lot like server-side includes - on steroids.
Handles any backend that accepts ODBC connections. Comes with a standalone click-clack template creator. If your database already exists you can point the tool to it and it will populate a drop-down with fieldnames from the database. After that its just drag-n-drop. Once you got the hang of it you can put together entire sites in an afternoon.
Drawback 1: the price BEGINNING at $650 for a basic license.
Drawback 2: The language guide is 850 pages - there are 1500 tags.
If you don't want to buy a license, there are some hosting providers who offer it as part of shared hosting packages, often together with FileMaker. The click-clack tool is a free download from Lassos website.
Bernhard on July 28, 2008 6:19 AMOK, now I see your background. Enough said.
Good Point on July 30, 2008 4:15 PMAnother vote for Apache Wicket! The templating approach is the only one I've seen so far the really keeps any programming logic out of the HTLM template.
I've worked with Wicket for a few months now - so far the biggest drawback is Java's lack of closures, forcing me to write a lot of ugly anonymous inner classes.
The best thing, apart from the templating itself, is the component model. Writing components and writing applications is achieved with the same programming model, just pair a HTML template with a Java class and add some other components. Composing applications from components or new components from other components works extremely well. A ton better then in JavaServer Faces, where you have two seperate programming models for writing applications (works fine) and writing components (ugly as hell, echo-html all over the place).
Jrn Zaefferer on July 31, 2008 9:40 AMSince the LISP-cat is out of the box anyway, have a look at Weblocks: http://common-lisp.net/project/cl-weblocks.
It has some very interesting aspects, although very alpha. Try turning of javascript, reload. Now turn of cookies, reload. It just works.
The commonality with GWT is that the HTML is encapsulated, which IMHBCO is certainly the way to go forward.
Cool!
IVR on August 6, 2008 12:45 AMDeclarative development definitely tackles the soup problem.
However, it also changes the way that we have to approach development. If you take a declarative approach (e.g using Declarative XML) then the developer is only concerned with what the application should do - not how it should do it; in other words the focus is on building the application and NOT on solving technical issues.
So who solves the technical issues? The programmer does this (e.g. using C#) in a programming environment removed from the declarative layer.
In quick conclusion, the reason why soup exists at the moment is that developers are forced to tackle 'development/build' and technical issues on the same page - no wonder it's so difficult!
One person can still carry out both the programmer and developer roles - it's just that declarative development separates them very clearly; solve the build problems in XML, solve the technical problems in C#.
If anyone would like to look at our work give me a shout; we'd love to talk to people who feel passionate about efficient development.
Magnus on August 13, 2008 3:26 AMWikipedia templates (those withing "Template:" namespace) are also as messy (or evil) as the codes you pointed in your post. Actually, I think wikipedia templates' codes are really messy and ugly.
Remember LISP? Tons of parentheses...
Meet wikipedia templates: tons of curly braces!
(mixed with wiki-code and HTML code, with some embedded CSS style rules)
I suggest creating Html helpers
Steve` on August 25, 2008 4:45 PMOne of my best experiences with templating engines has to be PHPTAL.
http://phptal.motion-twin.com/
Andre on August 27, 2008 10:25 AM| Content (c) 2009 Jeff Atwood. Logo image used with permission of the author. (c) 1993 Steven C. McConnell. All Rights Reserved. |