Hi Howard,
I want to begin by congratulating you for
developing Tapestry. A quick personal story: In the
past couple of years I had been looking for a proper
component-oriented web development framework that
allowed code reuse and all related perks.
Unfortunately, most frameworks out there (Struts, etc)
were pretty much variations of the same theme --
reusability either via compelete pages, or via tag
libraries -- and focused on improving other elements
of the system instead. With WebObjects being out of
the picture for us for various reasons, I had started
to consider developing a framework of my own (even
though it seemed incredible that nobody else had
needed and done something like that).
In October/November of last year, I read about
Tapestry and quickly realized that it was pretty much
what I was looking for. I was also very pleasantly
surprised by the design and implementation of the
framework -- great overall vision; clean and
well-designed code; a development philosophy that goes
from general to specific, providing various plug-in
points at multiple levels; fairly well developed
documentation, etc. All in all, kudos to you --
Tapestry is a great piece of work, and even though as
everything in this world it has ways to improve, it
has already achieved a very high quality level
(personal opinion, at least). We have started using it
for development in our company, and we are pretty
happy with it.
I am writing to share some of our thoughts about
Tapestry. There are quite a few of them (I hope not
too many :), so I will break them up into two parts --
conceptual and practical.
I am writing the conceptual suggestions in this
email. Please keep in mind that they are proposals for
the "longer term". I find them important, but it is
clear that discussions and planning would be necessary
to enact changes related to them. I would be very
happy to hear people's opinions about them.
So here are my suggestions:
1. Component contribution mechanism
It appears that your push to popularise Tapestry
via JavaLobby and TheServerSide did have an effect,
nevertheless I have to admit that I was somewhat
dismayed by some of the opinions by the people not so
familiar with Tapestry expressed there. It seems to me
that the conceptual basis of the framework and its
significant potential for productivity improvements
are simply not that easy and obvious to grasp to the
casual observer brought up on JSP and perhaps Struts.
Part of the reason for that, I believe, is the lack of
clear and unambiguous examples of Tapestry's power.
There are a lot of great perks within Tapestry
(automatic URL composition, built-in
internationalization, etc), but at the end they are
just that -- perks. What makes Tapestry special and
the source of its real power is the ability to build
reusable components. It seems to me that that power
has been greatly under-utilized on the community
level. Let me explain what I mean.
As you yourself mentioned, it is harder to design
and develop components that are horizontally reusable,
rather than vertically reusable. In fact, most of the
components within a typical web application are
usually only vertically reusable. Nevertheless, there
is a significant number of horizontally-reusable
components that are pretty much universal. I am
willing to bet that most of the current Tapestry users
who have developed larger applications have ended up
implementing a set of components that are common for
almost all of them, or at worst would have been happy
to use such components out of the box.
Some such components are already available in the
Tapestry distribution (e.g. the Palette), however
there is much more that can be done. Here are some
very quick examples off the top of my head (some of
these are components I would be happy to contribute
right away):
- A Table component that displays a list of
objects and provides the following features: automatic
pagination into pages, a flexible page-navigation,
sortable columns (by clicking on the titles), etc. I
am sure we all have seen numerous implementations of
something like that.
- A Tab Pane component (implemented in the demo,
but not packaged as a component)
- Specific data entry components:
- Date entry component that allows a small
calendar to open (by clicking on an image next to the
field) and to select the date from it
- IP Address entry component (mentioned on
this list)
- JavaScript-enabled validating entry
components
Obviously the list can be very long. Ideally,
current Tapestry users would contribute some of the
components they have written, and at the end the
developers using Tapestry would have an access to a
pool of ready-to-use components that would allow them
to implement some features much faster, or add
features to their applications that they would not
have included otherwise. Throw in the network effect
(more components -> more users -> even more
components), and you can have a fairly large and
triving community, indeed.
Why cannot the current contrib mechanism achieve
that goal? Simple: It is uninviting, unreglamented,
and brings no clear (moral) rewards. At the moment
people have to put an extra effort to do something
that should just be a simple and encouraged step.
Here is what I would suggest to be done to
fascilitate the process as much as possible:
- Create a specific site for contributing
Tapestry components (Tapestry Component Repository?)
- Define clear rules and guidelines for
contributing components:
- What should be included into a
contribution. For example: distribution jar, examples
or unit test, description, contact address (may be
visible only to the maintainer), source code.
- Code licenses allowed, with quick
explanations of the benefits of each. For example, GPL
and derivatives may (should?) be allowed, but the site
could provide sections based on license class, so that
developers could easily know what they can use and
what they cannot; closed source may not be allowed due
to the danger of trojans, but alternatively a
"commercial" section may exist, where a market for
such components can be developed.
- General component building guidelines
(not rules), e.g. access to data via interfaces (i.e.
a Model-View separation) to improve reusability.
- Easy submission of components, requiring a
minimum of human interaction and setup, e.g. via the
web interface of the site.
- Approval and rating of the components can be
either centralized (dedicated maintainer(s)) or
distributed (people can rate a component, and comment
on it)
- Paste the site and submission information
all over the Tapestry FAQ and other documents.
The reason I am using so many conditionals is that
I believe that such a mechanism needs to be discussed
in details by the developers on the mailing list, and
by you in particular. Nevertheless, I feel that going
ahead with such a project is imperative, and it is
both in the interests of Tapestry developers, as well
as Tapestry distribution and advocacy.
2. Component Libraries
This is closely related to the above suggestion.
The general idea is to be able to group a number of
components together and to avoid repetitions in the
definition of those components between different
applications.
The simple solution is apparent, and I believe
there is a fairly old feature request on Sourceforge
about that in fact -- being able to define component
aliases outside the app spec by being able to "import"
separate definition files into the application
specification.
One problem that may arise when there are many
libraries on the table, however, is that of
conflicting alias names -- different libraries define
components with the same alias. To resolve this issue,
namespaces must be used. One possible way of doing
that is by having a library define a namespace.
Accessing a component from the library would then be
done by refering to it as "library.component", rather
than just "component". One consequence of that may be
that if a library uses another library, then the inner
library components could be accessible by reference to
"library1.library2.component" (some protection scheme
for "inner" components used for implementation, but
not desirable for export may also be helpful, but that
is a reach at this point).
It may also be a good idea to allow the app spec
to define aliases referring to other aliases. In that
way it would be easy for developers to make
"shortcuts" (e.g. "comp" to point to
"lib1.component"), as well as to be able to swap
different component implementations quickly without
having to modify any application code other than the
app spec.
3. Polymorphism
Consider the following use case:
An online store with different types of products.
A random selection of products needs to be displayed
(for example for a front page or a search result).
Each type of product needs to be displayed
differently, however -- books in one way, electronics
in another, music in a third.
The typical way to do that in OO is obviously via
polymorphism -- all products implement a common
interface and can be asked to provide views specific
to themselves through it (this is more PAC than pure
MVC, but that's another topic). The resultant code
becomes extremely simple, clear, and highly
maintainable.
The currently available way to do that in Tapestry
is demonstrated in the Portal example -- essentially a
separate page is created for each "dynamic view", the
view is inserted in there as a Block, and when the
object is requested to return its view, it returns the
Block, which is then inserted into the target
location.
This obviously works, and if the messages on the
mailing list can be considered to be representative,
it appears to be used fairly often (which is also an
indication of how often polymorphism is actually
needed). There are a few things that bother me about
it, however:
a) It is clearly a hack. As such, it is a very
rare occurance on top the overally consistent design
of Tapestry, and precisely because of that it stands
out like a sore thumb. It is also rather unintuitive.
b) It provides no way to pass parameters the
Tapestry way. There are other ways, but they are
really black magic. (cf. Java: passing parameters to
the views assumes polymorphism -- all views also
implement a base interface, which is what the base
class/interface of the actual objects returns. That
ensures that all views support the parameters that are
passed to them.)
c) Rather than just defining a component per view,
one has to define the component and a page that is
essentially dummy.
The reason that this approach has been chosen, I
guess, is that Tapestry relies on a static definition
of the components included in a page. Since bindings
are set only once, a "dynamic" component that is a
different object every time would break the
assumptions and wreck havok with the system.
It seems to me, however, that it is quite possible
to devise a clean solution that does not break the
static definition assumptions of Tapestry and achieves
all other goals by using a static "placeholder". It
can be something like InsertBlock, but accepting
parameters. The placeholder then essentially defines
the base interface of the views (mentioned above). (I
suppose one way to implement the placeholder would be
as a user-defined component that extends a predefined
class, similarly to the way links extend
AbstractServiceLink).
The next step then would be to provide a clean
mechanism to define "dynamic components" that can be
initialized without having to be within a page, and
can be returned without a problem by a Java method.
(perhaps the initialization can be performed by the
placeholder?) That part I am not that clear about,
unfortunately -- I cannot be sure that I am not
missing something important in the lifecycle of the
components.
Anyway, this is just one possibility to implement
polymorphism in a cleaner way. In any case, it does
seem to me that something needs to be done -- this is
a fairly common case, and the current solution is less
than satisfactory. What's more, Tapestry seems ideally
suited to cater precisely to those needs of the
developers -- the effort to do that here well would be
much smaller than doing it with JSP or other
frameworks.
I hope my comments make sense. Again, I am not
looking for quick solutions in the next Tapestry
version. Rather, I am hoping to start a discussion on
those issues, so that the best ways to go forward are
selected. In any case, I would be happy to contribute
what I can :-)
Best regards,
-mb
__________________________________________________
Do You Yahoo!?
Yahoo! Health - your guide to health and wellness
http://health.yahoo.com
_______________________________________________
Tapestry-developer mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/tapestry-developer