Interview with Howard Lewis Ship at DevRates.com
Today our guest is Howard Lewis Ship from the Apache Tapestry
team. In the first part of the interview, Howard discusses origins of
Tapestry, evolution of the framework and shows its key design concepts.
He also explains what frameworks could be nicely used as the UI layer
for Tapestry application.
What were the origins of Tapestry? It has a fairly long history, has it evolved over the years?
Howard is the creator and PMC chair of Tapestry Framework
Back in around 1998 or 1999, I was exposed briefly to Apple's
WebObjects; this is the granddaddy of all component-based web
frameworks. I didn't get the chance to do a full application in it, just
some demos and proof-of-concepts, but I was intrigued by the
relationship between server-side controllers, elements in the
component's template, and client-side markup. Being an engineer, I was
pretty interested in how it all worked internally. Since it was closed
source, there was no code to look at or people to contact, so I was left
with my own imagination.
Somewhere around the summer of 2000, I found myself stuck in the back
of a MBTA Green line train (I was living in Boston at the time) in
sweltering heat and without air-conditioning, so you can image that my
mind wandered. I went from guessing about how WebObjects worked to
thinking about how something similar might be implemented in Java.
Later on, somewhere later in 2000, I found myself on the bench, between
client projects (I was then a consulting for Primix Solutions); I ended
up writing the first version of Tapestry while waiting for my next
assignment. It's pretty limited, almost pathetic, compared to what's
inside Tapestry 5 now, but some of the core ideas of pages, components,
persistent state, and event handlers were present way back then. That
code, the "prototype that escaped the lab", was my first big project in
Java. I do remember spending several days of frantic coding to get to a
"hello world" application.
We used that early version of Tapestry on a pretty sophisticated
currency exchange portal for Citibank in 2001; the application was
developed but never deployed, alas, due to politics at the client. I
still have a lucite paper-weight from that project: the "home" page of
the application (which, perversely, was the only page NOT implemented in
Tapestry!).
What I don't have is a recollection of how I came up with the name
"Tapestry"; I vaguely remember toying with using terms like "Weaver"
instead of "Component", but eventually came to my senses. I've always
believed in giving projects a real, memorable name, rather than an
acronym.
How would you place Tapestry in the world of web frameworks? Is
it closer to component ones like Wicket and whole JSF world or a bit
like modern MVCs like Grails and Play?
Tapestry is very clearly a component-based framework, which places it in the same camp as Wicket and JSF; SpringMVC, Grails, and Play! are all action-oriented frameworks, like Struts.
Putting modesty aside, I'd like to think that Tapestry has really been a
leader from a purely technological perspective. Being a product, and
not a standard (such as JavaServer Faces) has meant it could evolve
rapidly and radically; the change from Tapestry 4 to Tapestry 5, now
five years in the past, was a pretty dramatic leap frog.
Here's a few things that I believe Tapestry did first, and I still think does better than anybody:
- Reusable components (2001)
- Detailed, useful exception report (2001)
- "Invisible" instrumentation in templates (2002)
- Line-precise exception reporting (2004)
- Integrated bytecode weaving/meta-coding (2005)
- Live class reloading (2006)
- Full exception report for Ajax errors (2012)
I'm sure not all of these will be familiar to readers, but they are all
part of a specific pattern: making life easier for the developer. My
general approach to that is SCEF: Simplicity, Consistency, Efficiency, and Feedback.
Simplicity means that templates and code are concise
and readable; it also means (as of Tapestry 5) that you don't extend
from framework-provided base classes. I do take some criticism to heart;
even some of our sharpest end users have a reasonable complaint, to the
effect that "you can customize almost anything in Tapestry, and in only
a few lines of code ... but it can take you three days to figure out
where those lines of code go."
Consistency means that what works at one level, such
as a complete page, works at other levels, such as components inside a
page. Thus a nested component has the same freedom to store persistent
data, nest other components, and respond to component events as the
top-level page ... and the implications of that is what spurs Tapestry's
pretty fantastic code reuse story.
Feedback is all important to me; starting with my
first forays into Java web development using straight servlets and JSPs.
The fact that in those environments, any failure resulted in (at best) a
server stack trace in the browser is appalling. The further fact that
I'd have to restart in the debugger and, often, pull apart the exception
to figure out what actually failed is unacceptable, but all standard
operating procedure in many other frameworks. Tapestry is just the
opposite; a runtime exception gets a very detailed report, that attempts
to include all the information you'd need to determine the real cause.
For me, a bare NullPointerException without further explanation is a
total failure of the framework, and simply doesn't happen in Tapestry.
The line-precise exception reporting means that all the runtime objects
in Tapestry keep a reference to the file and line of the template they
originate in ... the exception report can say "You have an error on line
10" ... and even show you an excerpt of that file directly in the
report.
Basically, if your framework doesn't provide truly excellent feedback,
then it is getting in the way: whatever gains you might get form a
framework can be offset when the framework doesn't do what you want, and
gives you no clue how to fix it.
Efficiency, though, is not about developer
productivity per-se. My belief is that no matter how great the
development environment is, someone is ultimately going to compare
framework or apps based on response times, so I want Tapestry to be at
or near the front of the pack. This blog post
compares a number of different frameworks on the same simple
application functionality. It's a couple of years old, and I don't know
how the other frameworks have evolved, but Tapestry 5.3 is significantly
faster, operated more concurrently, and consumes considerably less
memory, than the Tapestry 5.2.5 used in the tests.
Further, I've always wanted Tapestry to scale up before scaling out ...
switching from one server to a cluster, even with sticky sessions,
always comes with considerable costs and challenges. Tapestry uses
shared data in the HttpSession very differently than other frameworks;
where server-side state exists, Tapestry application tend to use more
attributes with simpler, immutable values (such as Numbers and Strings),
which is more in accordance with how the Servlet API was designed, and
fits better with how it is implemented. There are definite ambiguities
in how web containers work with HttpSession attribute values that are
mutable; Tapestry tries to limit those, and
deal with them correctly when they exist.
Now, all of these are goals, and they are constantly evolving from
release to release. It's more a way of thinking "how useful is this
feature". In fact, I can easily point to a number of places where I've
added a feature that may not be simple, or not consistent, but seemed
like a good idea at the time; maybe it made one thing a bit more
concise. I now regret those decisions (mostly four or more years old)
because they ultimately undermine the usefulness of the framework, by
making its inner model more mysterious and difficult to communicate.
Well, I didn't entirely mean this to be entirely a marketing pitch for
Tapestry. I think many of the frameworks have very keen ideas, and
Tapestry has a bit of baggage I wish I could jettison in a backwards
compatible way. Certainly, all of the major players borrow ideas from
each other. Many people prefer to the Wicket model, which uses lots of
inheritance and inner classes (for callbacks), but doesn't require the
kind of "leap of faith" accompanied by Tapestry's runtime bytecode
weaving. On the JSF front ... well, you can't really compare a single
project to a standard aggressively driven from the top down. Still, some
of the IDE integration supporting JSF is quite enviable.
What about UI widgets in Tapestry? It is possible to integrate it with Bootstrap, jQuery UI, YUI, ExtJS?
I have existing clients who have used Tapestry with Sencha's ExtJS for quite some time, though I understand they are on path to switching to jQuery and perhaps jQueryUI.
In any case, Tapestry has bundled Prototype and Scriptaculous since the
first version of Tapestry 5, and many of the existing components
provide a lot of functionality based on these libraries. I'm working on
projects that use Tapestry, with jQuery, jQuery UI, Twitter Bootstrap, and even Backbone
all at once; it can be done, but you can see some rough edges where all
the bits and pieces don't merge together ideally. You also have the
issue of deploying a large JavaScript payload that includes this big
shopping list of frameworks and libraries -- it can affect that critical
first page view time.
The current focus on Tapestry 5.4, the next big release, is almost
entirely focused on JavaScript and a big part of that is introducing the
long-awaited abstraction layer that will allow the application to
select Prototype or jQuery, or virtually anything else (by writing an
client-side adapter). We're also going modular, leveraging RequireJS and
the asynchronous module definition, to load JavaScript as needed, and
in parallel (and hopefully, in much smaller volume).
Tapestry 5.4 will also bundle Bootstrap, and many of the existing components are being updated to make use of Bootstrap's CSS classes.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)





