Tapestry 5, and how not to treat HTML
I've previously written about how Microsoft Sharepoint mistreats HTML, and makes it look a whole other language. But truth to be told, Sharepoint (and .NET for that matter) isn't the only framework that can't handle HTML. I've recently worked with a Java framework called Tapestry 5, and it's really bad in some respects too (though not quite as bad as Sharepoint). Note that this is a review based on only how it handles HTML, not any other of its merits. Let's get started.
Many of Tapestry's problems comes from their design decision to parse the HTML you're trying to output. Yes, Tapestry parses your HTML, and adds stuff to it dynamically. This is nothing new, anyone that has played with ASP.NET knows how hidden form elements get stuffed in here and there. This is a nightmare for an interface developer, we need exact control over HTML to do our jobs well.
Tapestry does horrible things to HTML:
- Several extra javascripts and CSS files are referenced in the head tag. There is no simple way to get rid of these.
- A meta tag which states that the tapestry did generate this page, is added.
- The two above are added to the head, and if a head tag doesn't exist, it gets added. Never mind that your current little HTML snippet was just a little part of a page, that was being fetched with AJAX, Tapestry will add a head tag for you.
- More javascript, and a hidden div with a firebug-like console, is appended to the end of the body element.
- Self-closing tags are expanded to a start tag and an end tag (
<input />
gets transformed to<input></input>
), which means you can't use XHTML together with Tapestry. - All whitespace is removed by default, and you have to disable the "feature" on a tag-by-tag basis ("Please don't strip whitespace inside this list, IE6 goes crazy then"). This is a mess for interface developers, who know that whitespace matters for rendering. It was even pointed out to Tapestry developers early on, but was ignored.
- There are ways to do loops, if:s, reference variables and generate URL:s, but all of these are based on the HTML parsing. And as a good parser, it skips all comments. This means using tapestry template code inside a HTML comment will not work. When do you need that? Conditional comments! So what if you want an URL generated to your IE6 stylesheet? No go. You'll have to write a custom component that does that for you.
- Changes the id of all your forms to "form" and adds name="form" (which is invalid HTML).
- Adds a hidden "t:formdata" field to forms, much like the dreaded ASP.NET viewstate.
- One of the javascript files added is prototype, a javascript framework which isn't compatible with jQuery. So you have to rewrite your javascript code to work in "No conflicts mode" if you want it to work with Tapestry.
No. Tapestry was clearly not built with an interface developer in mind. Why is it so hard for many web framework developers to just talk with people that work with HTML, CSS, and Javascript? Please ask us before implementing stuff like the above. We'll gladly give you our viewpoint.
Comments
By: Anders Ytterström (#1)
Another framework which should have consulted an Interface developer during development. Sad to read this.
It's good to see an article about a framework not being .NET powered suck in HTML as well, people tend to believe that .NET-people is extraordiary bad in HTML knowledge which is for no good. Many Java frameworks tend to lack of Interface feedback during development phrase as well.
By: Ole (#2)
So I'll never ever work for the .NET platform anymore. And now also not for "Tapestry5". Thank you for that information.
By: Andreas (#3)
Regarding the whitespace though, I'd think that was only positive?
The problems I tend to have with whitespace is that IE renders it when it shouldn't.
So, removing whitespace altogether only seems like a good thing to me? Kindof like how some people do * {margin: 0; padding: 0;}.
Also, the page you link to had some points on why one should remove whitespace (fewer text-nodes in the DOM and obviously smaller filesize).
I implemented whitespace-removal in my own framework so that I could write my template-code any way I like without worrying about IE rendering the whitespace.
By: Emil Stenström (#4)
By: Emil Stenström (#5)
By: Andreas (#6)
Are forms inline by default? I've never had a form-element not linebreak before and after it unless I've set the form and everything inside it to display: inline;
Also, I don't remove whitespace between inline-elements like this:
<p>Hello the <strong>spaces</strong> in here will <em>not</em> be removed</p>
I do however remove all tabs and linebreaks etc. I've never noticed a difference in anything but IE.
By: Howard M. Lewis Ship (#7)
It's disappointing that you did not do proper research on Tapestry 5. All of the complaints you make about the framework reflect features that ARE correct for the vast majority of users, and CAN BE DISABLED quite easily.
Tapestry gives you very good control over the exact output generated from your template, you just have to actually read the component documentation.
I'm not sure where you are coming from with a tag being added via Ajax calls; that's not what Tapestry does at all.
Tapestry adds quite a bit of JavaScript to the page ... if you use Tapestry's JavaScript facilities. This is part of Tapestry's approach to making things Just Work (tm) ... people don't want to read a five page treatise on how to get Ajax to work on a page, or client-side validation, or dynamic HTML ... they just want things to work without care to how they are implemented. That's what Tapestry does.
I think you don't understand XML/XHTML correctly as and are exactly identical in XML (and if not, your browser is broken). What Tapestry does (by default) is to support broken browsers in HTML mode (SGML compatibility) where there is a difference between the two ... this is mostly to make the tag work in broken browsers like IE.
Adding conditional CSS support for IE is on the planning board. You clearly state you can achieve your goals while dissing the framework. The framework would be in error if it was NOT possible to achieve your goals; instead, you are saying that your very specific, very personal choice are the only valid choice for any developer. If that is the case, please write your own framework, because nothing else will ever satisfy you.
Tapestry does not blindly chaing the Form's id to "form"; it allocates a unique id for each form on the page, and you can control what that id is if you care to.
Tapestry does add elements to a ... and is very careful to add the new invisible and tags in HTML compatible locations.
Tapestry is quite happy to use HTML5 or other elements but it does use an XML parser (though not a validating parser, your documents just need to be well formed). The majority of components, including Form, the link components, TextField, etc., all support informal parameters ... what ever attribute you put in the template will be honored when Tapestry renders (unless the attributes directly conflict with an attribute generated inside component code).
In fact, Tapestry was specifically designed with user interface designers in mind; with discipline, it is possible to remove from the templates everything except a single attribute, t:id, for dynamic elements of the page, which makes it much more reasonable for interface developers to work on Tapestry templates using standard, off-the-shelf tools. This "invisible instrumentation" originated in Tapestry around 2003 and has been gradually adopted into other well-known Java web frameworks.
I think if you take a look at Tapestry without blinders on, you'll find a lot more about it to like than to carelessly dismiss as you have so far. The majority of Tapestry users have worked in multiple frameworks prior to Tapestry but have become passionate about Tapestry because it works fo well for them ... and this applies not just to Java developers but to the interface side of the equation.
By: Emil Stenström (#8)
You're saying, that these defaults "are correct for the vast majority of users". I'm certain that most interface developers (the audience of this blog) would disagree with that statement. Each of the issues I list, sprung from real problems I've encountered. I should of course have included those problem descriptions with the text. Sorry for being lazy, let me know if you want them.
You say that "with careful instrumentation", I can reset all the defaults this article describes to what I need. That I need to reset them in the first place, is the problem. From my side of the board, those defaults are a real obstacle that stops me from doing my job well. I'm sure you're right that there are ways to sidestep most of the described issues (I mean, if anyone, you should know), but I've guessing that that's lots of work for an overage Java/Tapestry developer, not to say an interface developer like me, with only little experience with Tapestry.
Now. There are several things one could do to make an interface developer's job easier. The simplest is probably to document how I would do the instrumentation you describe. I've given each of the issues I describe some serious Googling, without finding any reliable workarounds. Feel free to do that yourself. Another would be to release a sample project with the necessary changes made, that someone like me could use as a starting point.
By: Emil Stenström (#9)
About "AJAX": What I'm saying is, you don't always want a head element on each page you build. In our case, we made a stripped down version of a page with Tapestry, and then completed the HTML of that page according to a given HTML template later in the rendering cycle. Our head element was added later, but Tapestry forced it's own head element in first. The same would be true for a AJAX search page. You would make a separate page with just the search results (no head element), and then fetch that page with an AJAX call and insert it into the current page.
On Tapestry's javascript: Interface developers know how AJAX works, and don't need frameowork features that "help" them. Tapestry does this for Java developers, who don't know. If I don't want that help, how do I remove those scripts and handle things myself?
By: Emil Stenström (#10)
About conditional comments: They are not a "very specific, very personal choice". Conditional comments are best practice in the interface development world. Ask anyone. No framework needs to build their own method to send custom CSS to different versions of internet explorer, it's there, it's what we use everywhere else.
About form id:s: I developer my page in another java framework (with <form id="signup">, and CSS that referenced that id), when that page was migrated to Tapestry the CSS suddenly stopped working, since the id was changed to the default "form". To me, this is another example of small barriers that make an interface developers job harder.
About HTML5 compliance: I might have exaggerated here, based on a single error in one of my templates. I tried to add "default="default"" to an option element (which is invalid, should be "selected"), and got an error from Tapestry which I interpreted as "your HTML is invalid". My mistake is that was an incorrect conclusion, I'm remove that point from the post to reflect this.
By: Emil Stenström (#11)
By: Emil Stenström (#12)
If you gzip your HTML, you will hardly gain any file-size by also removing whitespace. I think your way of removing it could work, but I'm rather sure that there are edge-cases where it might change the rendering.
By: HTML Framework (#13)
By: Cody (#14)
By: (#15)
Seems to me you are looking for perfection, but most of us understand that any web-related framework will ever be perfect for everybody, due to the nature of the beast.
My question is: what is the contribution of articles like these for the community?
By: Emil Stenström (#16)
By: Alex (#17)
I think that article's like this one are usefull not just for the community but also for the framework creator who can consider and repair all those HTML fights. It's like a large feedback.
I don't think that Emil is looking for perfection, i think that the word which can be used here is called "improvement"
Regarding those who read and not try i think that they should reconsider.
By: Max (#18)
By: Martin Reurings (#19)
.Net makes for some seriously screwed up html, I agree, out of the box it is most likely one of the most horrible frameworks out there. I can probably find you 50 others, strewn around php, java, python, etc... So let's get that out of the way, by default a framework is far from perfect, that's because interface-developer think differently from backend developers and what's even worse, they disagree between themselves!
Same goes for Tapestry, out of the box, it ain't perfect! Surprisingly enough, out of the box it gets most of the stuff pretty close to perfect, from my personal perspective.
- It forces id's on elements that need it, of course only if the developer didn't actually set one correctly in the first place!
- It removes white-space from the page, and I like that, what's even better, should I really need white-space somewhere on the page, I can tell it to preserve that, only there!!!
- All the default javascript and css can be disabled or overwritten, damn, that's so cool, it only takes a single configuration property for each! With other frameworks I was unable to even so much as think about such things.
- The last point, about hidden elements you make? Really, get a live! Hidden elements rarely, if ever, screw up design, it's a lousy point to make when the result of those hidden elements have many benefits that have, indeed, nothing to do with your little narrow field of specialization.
- Oh, did I mention that T5 can return only page-partials for Ajax-request, or JSON, or plain text, whatever you need? Guess you didn't know that, I also guess the developer you worked with had as little experience with T5 as you did, since returning a seperate page for an Ajax-request is not quite the logical way to do things. The developer you work with should have been able to tell you how to work it out with T5, actually, he probably should have done the work. If you didn't work with one, either you should not do the job, or you should get more serious about learning the framework you work in.
One last feature, plain html templating, the only non-html information you 'have' to add being t:id="..." to elements that require an actual T5 component to render in their place.
All of this just being the tip of the ice-berg. Suffice to say, I've seen plenty of frameworks come and go, I've never (from an html/js/css point of view) been more enthusiastic about the capabilities of a framework before. Should you really not like the fact that you may need to re-configure parts of [insert name of a framework here] to get it closer to your private perspective of perfection, build your own, or start using plain old .jsp or .php pages and hope your backend developers won't kill you :)
By: Ernst-Udo Wallenborn (#20)
And where the xml element expansion is concerned: why would you want to deliver XHTML to browsers who don't speak XML in the first place? Why not use old-fashioned HTML instead?
By: Emil Stenström (#21)
You also seem to agree with my main point: Tapestry 5's defaults are not as good as they could be. So, now we need two things: Change the defaults, and meanwhile, documentation of how to change the defaults to our liking.
There are many frameworks which are worse than Tapestry, no doubt, but that doesn't mean Tapestry is perfect.
By: Emil Stenström (#22)
Concerning XHTML. I usually don't use it, but I don't see why a framework should disallow people to use it. If Tapestry developers wants to disallow XHTML, they of course can. But it would be easy to make it possible to use.
By: Alan Earl D. Luayon (#23)
It depends the way you develop your application.
Tapestry is designed to be extremely scalable in several dimensions:
* Tapestry applications may contain large numbers of pages and many custom components.
* Tapestry applications may contain very complex functionality.
* Tapestry applications may be created by large, diverse teams.
* Tapestry applications can service large numbers of concurrent users.
Please read first ... before you give commentsssss...
By: Pierce Wetter (#24)
I think some of your complaints are just inexperience with T5, and frankly with web frameworks in general, because some of your statements are just wrong.
Also, you're complaining about including JavaScript. I have to say, managing which JS libraries get loaded when can be a big pain in any of the application frameworks I've used. The fact that T5 has stuff to deal with that is a good thing.
By: Emil Stenström (#25)
My experience with T5 is limited, and I've not claimed otherwise, but I think a framework should handle that, either by being easy to learn (and by that I mean modify to ones liking, not simply using), or by being properly documented. My experience is that T5 is neither.
Feel free to say *which* of my statements are wrong, and I will address your concerns.
I've used several frameworks that let me choose the js frameworks myself, and that's a good thing.
By: Martin Reurings (#26)
Yes, I have worked with Tapestry quite extensively and yes, I have quite different opinions of how to use html and css, but I 'personally' think that gives my bias a much stronger foundation than yours. Unfortunately, only somebody who has actually worked with Tapestry is capable of figuring out the holes in your arguments, so anybody who actually believes your _opinion_ might turn to something that is far worse but didn't get flamed by a developer who didn't get enough time put into learning it properly.
So, yes, I am biased, but no, I'm not close-minded. Among other things that's how I am able to realise that Tapestry works extremely well for me while I accept that this may not count for everybody. Why I believe that you ARE closeminded, and I quote: "No. Tapestry was clearly not built with an interface developer in mind." Which means that everybody does interface development the way you do, right?
By: Emil Stenström (#27)
So read this blog post as my (as an Interface Developer) reaction to working with Tapestry. Reactions like these can be avoided in two ways:
1) Document why Tapestry have chosen a different path than most other frameworks (for instance concerning white-space-collapsing). I found almost no reasoning when googling about the issues I encountered.
2) Change the defaults to more closely match when someone like me expect. From the comments I read that Tapestry developers don't like to change any defaults, since they are used to things how they are. That's fine. Do step 1 instead.