Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Wednesday, January 03, 2007

Latest T5 Snapshots: Invisible Instrumentation

I just uploaded the latest T5 snapshots. I did some work on the template parser; you now have an alternate template syntax, more like Tapestry 4:

<span t:id="foo" t:type="Bar" param="literal-string"/>

In Tapestry 4, it would be the same, except jwcid="foo@Bar".

I'm struggling with what's the correct binding prefix? With <t:comp> the default binding prefix is "prop:", meaning a property name or property path unless an explicit prefix is given.

With invisibly instrumented elements, the expectation is that more of the parameters will be fixed string literals, so the default binding prefix is "literal:". Thus you might have to do the following:

<input type="text" t:id="userName" t:type="TextField" value="prop:userName" validate="validate:required"/>

However, there's some implemented and upcoming improvements that will shorten and simplify this snippet.

Notice that the t:id and value attributes are pretty much the same? That's a Dont Repeat Yourself violation; Tapestry 5 already handles this particular case: if the value parameter is omitted, it is assumed to match a property of the container with same name as the component's id. This is already implemented. So the example is reduced to:

<input type="text" t:id="userName" t:type="TextField" validate="validate:required"/>

The remaining ideas are not yet implemented.

We've put <input type="text"> into the template for preview purposes. Tapestry should be able to deduce that we want a TextField component. That reduces the example to:

<input type="text" t:id="userName" validate="validate:required"/>

The final change refers to the validate parameter. It's type is FieldValidator, not string ... that's why we're invoking the "validate:" binding factory to convert the string ("required") into a FieldVaidator instance. I'm not sure what this would look like (either special code on the TextField component, or some additional logic to invoke the ValidateBindingFactory), but it seems to me we should be able to remove the "validate:" portion:

<input type="text" t:id="userName" validate="required"/>

This is part of the goal of Tapestry, that whether you're writing templates or Java code, you should only write the bare minimum that's necessary, and Tapestry should be able to fill in the gaps. That's partly convention over configuration, but the overall concept goes deeper than that.

This last bit, omitting the need for explicit binding prefixes, was a battle I lost in the Tapestry 4 time frame, but the approach I was taking then was more involved; a default binding prefix for each parameter. I just want Tapestry to realize that I supplied a simple string, but the component needs a FieldValidator, and that those come from athe ValidatorBindingFactory service. Tapestry should be able to close the loop on that without generating any surprises.

9 comments:

hooks said...

i would drop the t:id and just use id, binding everything else transparently-- based on existence of a matching component in the backing page, otherwise require a t:as :-)

arnljot said...

I would agree, the "t:" namespace seems unelegant, but I see how it could be troubblesome with the existing namespace of xhtml

Anonymous said...

Seems to make sense, I love the direction T5 is going. You are addressing all the little things that add up to bigger, more painful experiences...

Howard said...

Using t:id instead of id may be just a bit of dogmatism on my part; the t:id has a specific meaning to Tapestry, the XHTML id has a specific meaning to XHTML and the client web browser. If the parser matched on "id", not "t:id", then any static element with an id attribute would become an Any component instance. Not really a problem, but I'm not certain it survives the Principle of Least Surprise.

The last couple of years of teaching Tapestry has really educated me on what things people get and what things they don't. As I code up features, I picture a classroom of people's eyes: bad features result in that awful glazed over/desperate look (the one you get when you start explaining about abstract classes in Tapestry 4). Good features result in that eager I-cant-wait-to-start-coding look. Hopefully, the real world students will reflect my imagined ones.

hooks said...

i agree that implicits can be sometimes hard to trace/debug-- take apache tiles for example, it's a total guessing game as to where properties/values come from in complex layouts because there's no declaration requirements (equiv to always using t:id)

Massimo said...

This is a great enhancement, Howard, probably is better sad that Tapestry5 is a great enhancement for the web development.
But i would like to see more... more on the dev list since here seemed too much :)

Anonymous said...

The implicit binding of value parameter to a container property is confusing. What if you had multiple parameters? What would get bound?

Also, the use of the t:id parameter and default binding to a component parameter provided a thought-segue to the .NET world where the id parameter actually denotes the property in the container, except the property is the component instance, not a parameter that is bound to the component. I like that model much better. Components have first-class presence in a page, not brittle binding of individual parameters.

That way, if I have a text component, in my page, I can do comp.getText(), comp.setText(). I can also setup listener bindings by using constructs such as comp.onValueChanged. IMHO that has always been a shortfall programming with Tapestry.

With all the versions of Tapestry - from 3/4/5, Tapestry 5 will not be a success beyond its current niche following for the simple reason that it doesn't focus on components and creating a viable commercial component marketplace. No vendor is going to be interested in maintaining components across such drastic architectural changes. It is unfortunate that JSF has such a terrible legacy JSP technology still built into it. Otherwise, all other frameworks would be rendered as academic experiments.

Howard said...

I don't think you can appreciate how grating it is to have Tapestry 5 declared dead on arrival by "anonymous".

The defaulting parameter bindings is something documented on a per-component/per-parameter basis.

I especially don't like systems that require engineered coincidences bewteen component ids (or the equivalent) and property names. Struts has been down that path with ActionForm and all. The idea that someone could hack a form submission and update properties that were never intended to be changed (not especially a problem from Struts, but Tapestry allows direct editting of component properties).

The mapping from t:id to a property is a default behavior used as a convienience, to eliminate ugly repetativeness.

In a real application, you'll likely be updating properties of data object, not properties of the page itself, and you'll be back to using value="prop:user.name" or equivalent.

I'm not "focusing" on creating a component market. No one has every successed at creating a component market, in any area (except Microsoft and VB controls). Anyway, my focus is entirely on the developer and simplfying their life. I'm looking for ways to ease people into Tapestry, to hook them on it, without overwhelming them with its inner richness.

David Channon said...

For me, the real power of Tapestry is the ease of creating your own components. The benefits of a component oriented framework is sigificantly reduced when it is not easy for a developer to create their own components. This factor and the template layer are the two primary major strengths that I find Tapestry has over all other frameworks.
Keep up the good work. I look forward to Tapestry 5 being release.