At line 1 added 383 lines |
(points made to Hans Bergsten in email exchange) |
|
!!!RSF FROM JSF - SEQUENCE (JSFUTIL) |
|
|
In the beginning there was i) FlowTalk (intended to |
be a highly configurable "discussions with workflow" webapp, and ii) |
your book. |
|
The library "JSFUtil" I created was based around (initially consisting |
only of) the "ClassViewHandler" and "TemplateHandler" from Chapter 15. |
The changes that I made, roughly in order, were as follows (as you |
go down the list these involve an increasing violation of JSF's |
natural semantics): |
|
i) refusing to restore the component tree from restoreView in the |
case of a GET. This was part of my very initial perception that JSF's |
component tree was extremely wasteful in server resources, or else |
in client state. Since I was going to the trouble of regenerating |
the entire component tree in any case it seemed highly absurd for |
the framework to have been trying to cache it somewhere. In addition |
given this was a highly dynamic application it is quite likely that |
the model had asynchronously changed in the meantime. This was very |
much a "token" measure since at this time I had no way of servicing |
a POST without access to the component tree, but I think marked out |
symbolically the direction I thought JSF had to go in. A core point |
of RSF is now that the component tree is destroyed at the end of |
EVERY request cycle and stored nowhere. |
|
If you were to ask for a succinct summary of the reasons I thought |
JSF ought be abandoned, it would be "Heavyweight components, in |
particular ones that must be persisted, must not be a necessary |
part of a web framework". |
|
ii) instituting strict POST->GET redirect for all requests. This is |
as far as I can see a completely fundamental requirement for webapps |
which satisfying the browser idiom, which in my view should be all of |
them, given they all end up being viewed by browsers. A difficulty |
created here was managing to transfer FacesMessages from one cycle |
to the next (see below). No rendering is performed on POST cycles |
as is correct for portlet as well as general HTTP. I expect this |
problem is one of those solved in JSF 1.2. |
|
iii) instituting the "ViewParameters" system. Probably the #2 |
deficit of JSF is that it has no idiomatic system for accessing |
URL state. This has in fact proved completely fatal in a large |
project that I am working with (Sakai) in that all the framework |
developers eventually lost faith in URL state and other than the |
viewID, came to rely on random stuff stored in the session. The |
result is that the project's portal has essentially architecturally |
collapsed in that REST idioms are impossible and the back button |
cannot be made to work. Obviously this is not a forced consequence |
of working with JSF, but JSF's lack of respect for the natural |
idiom of HTTP being that state, primarily, is URL state exacerbated |
the problem enormously. ViewParameters does the work of representing |
the URL state in a HTTP-neutral way by mapping parts of the URL into |
fields of a user-defined near-POJO. Actually since ViewParameters is |
pretty much the oldest part of RSF it is now actually the most |
deficient (although this is actually still not a completely easy |
problem to solve conceptually). It is due for an overhaul in RSF 0.8. |
|
iv) The introduction of the "fast EL" system for bindings. These |
were a set of hidden fields rendered into forms that were guaranteed |
to be processed *first* before JSF's "apply request values" phase, |
that would properly contextualise the bean model. These bindings |
encoded primitive operations on the request bean model. This was the |
beginnings of RSF's "request-scope IoC" system in which |
request-scope entities could participate in first-class IoC by |
means of "assignments" (in Spring-speak, "wirings") performed as |
a kind of context startup. This became clear when reading your |
chapter on the "ReportHandler" app, primarily in chapter 10. |
I constantly asked myself the question... "how does the |
ReportHandler know which report it is to work on"? In your |
non-persistent example this was clear - there was just one |
Report in request scope, and this is the common pattern I have |
seen in JSP-type apps since the beginning of time. But say this |
Report had a persistent identity, how on earth would we come |
to find it? In JSF, the only answer would be to scrawl a note |
in the session scope - pretty unacceptable. Even that done, there |
would be the matter of communicating this to the persistence system |
in some kind of idiomatic way, which is leading even the Spring |
people to measures such as injecting DAOs into "entities" |
signalled by annotations &c. With the "fast EL" system, which |
gradually evolved into RSF's bindings system and RSAC, this is |
completely idiomatic - every entity has its unique EL path, and |
these are set up to be "wired" by bindings before the subsequent |
request starts up. |
|
v) JSF components are so behaviourful that a constant requirement |
was to generate references from one component to another. In |
particular, without access to the "clientId" of a component it is |
impossible to prepare for any client-side work - this was also |
essential for the FacesMessage propagation work for ii). |
Unfortunately the code to compute this ID is buried in the |
monstrosity of the UIComponent hierarchy, so the only way to get |
at it was to institute the "EarlyFacesContext" - this delegated |
to the existing FacesContext in all cases except for getViewRoot() |
which was initialised with the correct root "early", the moment |
the component tree started to be constructed. This forced |
"top-down" construction of component trees has continued in RSF - |
given JSF seems to be designed from the view that the component |
tree *could* have been constructed in any order, it seems there |
was no provision for working out clientIds until the construction |
had finished. |
|
I could go on about JSF's other architectural deficiencies (firstly |
the existence of FacesContext, and secondly the global access to it |
which is the most utter destroyer of testability, thirdly |
the crazy table rendering model, fourthly the fragile and |
untrustable PhaseListener system, fifthly the lack of any coherent |
policy wrt. exceptions &c), at some length, |
but I will move on :P |
|
!!!RSF FROM JSF - SEQUENCE (RSFUTIL) |
|
|
With these 5 major heads of changes (along with a host of other |
details to make things work) we get to the state of "JSFUtil" as |
it was in July of last year. This operated a kind of "shell" of JSF |
that was being used principally for rendering and the basic sequence |
of the request cycle, with most of the logic routed out due to the |
custom ViewHandler. At this point I was presented with an |
essentially intractible reskinning requirement - we were required |
to make the *same app* render fundamentally reorganised (i.e. in |
HTML order, not just in CSS) versions of the same user interface, |
preferably without recompilation or developer effort. |
|
At this point the idea for the IKAT renderer, which I had been |
kicking around my head, initially inspired by your "HTMLTemplateHandler" |
came to the fore. IKAT is actually just a generalisation of |
HTMLTemplateHandler (as indeed you could in some way say Facelets is), |
only with the crucial capability of *alternation* between |
template-driven scanning and component-driven scanning. This last |
is the key capability which lets things like tables and trees be |
rendered in RSF so straightforwardly, since it allows RSF to |
induce replication in the structure of the template in a particular |
domain, but then to *return* to the static template structure |
once the replication/branching is complete. There are other |
important differences in philosophy which I could talk about if |
you're interested. |
|
Given at this point I was using JSF largely for rendering, there |
seemed little point in maintaining the JSF component structure at |
all, given I fundamentally disagreed with its idiom where the |
incoming request values were applied *first* to the components |
during "applyRequestValues" and only THEN to "UpdateModelValues", |
and was intending to apply my own rendering. So this was the signal |
to kick over the rest of the structure, which could loosely be |
described as "renaming JSF to RSF and trying to get the code to |
compile again" :P In particular the key action was the creation of |
RSF's component hierarchy which became semi-ironically named |
after JSF's. The core contrast here is that RSF's "UIComponent" |
is 61 lines, which are mostly comments, with just one method - |
compared to JSF's UIComponent+UIComponentBase which is an intricate |
tangle summing to a grand 2900 lines. I have to say that this is the |
key answer to your question as to whether I though I might not have |
made "better inroads" building my framework on JSF - the key point |
is that RSF was primarily derived by starting with JSF and taking |
things *out* - had I built on JSF as so many are now unwisely |
doing, it simply couldn't have ever become the right framework, |
even had it perhaps initially enjoyed more popularity. As far as |
I can see, Facelets is roughly would have been had I built RSF |
on JSF, but it can only reform the rendering system (which I don't |
think is done as neatly as RSF). Given I had already replaced |
most of JSF *except* for the rendering system by the time I came |
to write IKAT, logically there was pretty much nothing that should |
remain. |
|
!!!JSF - KEY "DIAMONDS" RESCUED |
|
|
That said, I think I should summarise the "diamonds" that I managed |
to rescue from JSF, since it did indeed contain many ideas that |
were both new and highly valuable. In these terms JSF actually "is" |
the best framework out there in terms of ideas, since I don't think |
any other framework has innovated in quite so many ways at once - |
the tragedy is that these great ideas were practically negated |
by being wired together in a close relationship with so many poor |
or "unreformed" ideas, and often poor execution. |
|
!!JSF key value points: |
|
i) Introduction of the idea of an "abstract" component tree |
insulating framework users from the target idiom (HTML, WAP, XUL, |
whatever)\\ |
ii) Increased cementing of the idea begun in JSPs of a pure |
"bean" model, potentially defined framework-free by developers which |
is poked by abstract "EL" paths.\\ |
iii) The use of "bindings" attached to components which |
represented an association of UI values to model values.\\ |
iv) The idea of an "action" binding which invoked an abstract |
application-defined action with a String result, which was then |
interpreted by a layer of indirection.\\ |
v) Beginning to become "portal-ready" by separating Action |
URLs from Resource URLs &c.\\ |
|
!!!JSF key errors: |
|
i) Continuing use of a "fat" component hierarchy. Not only fat |
in terms of size (2900 lines for a base class is simply beyond |
a joke in terms of poor design) but fat in behaviour. Actually |
90% of JSF's badness lies in its components - they\\ |
a) consume state and developer resources in being looked after\\ |
b) provide strong framework coupling that is almost ineradicable\\ |
c) constrain developer's idioms in enforcing particular models |
of UI interaction\\ |
d) obstruct cooperation with ORM solutions\\ |
e) lack of natural integration with IoC (JSF-Spring obviously |
helped with this at the developer end, but this is actually |
even more critical for the *framework* - providing a set of |
5 interfaces that could be overridden in faces-config just doesn't |
cut it\\ |
ii) Lack of access by view producers of a (portable) representation |
of URL state\\ |
iii) Lack of natural cooperation with client-side logic and HTML |
idioms. JSF form rendering is obnoxious and the unpredictable nature |
of the assigned ids pretty much rules out any kind of productive |
interaction with client-side logic.\\ |
(see above for 5 more key JSF problems) |
|
Naturally since it was me who drew up these lists, all the key |
"value points" are preserved in RSF, and all the "errors" are |
removed... |
|
I've surely gone on for far longer than you have patience for, but |
hopefully I've conveyed enough of my reasoning into why I think |
JSF is beyond salvaging in terms of constructing a good framework |
by building on it. |
|
!!!RSF FUTURE (HEAVYWEIGHTS) |
|
|
An important point that I hope I put across on the ServerSide |
thread is that by designing RSF's "lightweight" components I have |
not in any way closed the door to somesequent "heavyweight" |
framework being built on them (perhaps a kind of JSF-on-RSF, |
or Wicket-on-RSF), although given the constraints offered by RSF's |
bindings and encoding system, this heavyweight framework would |
probably not develop quite in the same way as JSF or Wicket. |
|
One idea I am however kicking around is that essentially *all* |
view logic (of the sort expressed in heavyweight components) |
is actually completely unnecessary! Already in RSF I am not |
feeling particular pain due to not having stable "view domain |
objects" whose job it is to manage bits of the view, and the |
only danger I can see coming down the line is this whole nasty |
business of "listeners" and "events" to which most of the bulk |
in H-C systems is devoted (cf JSF's and Wicket's "Component" |
base class). I have an idea that UI event propagation might |
in fact be done in a kind of "declarative" way much in the same |
way that Spring demarcates transations. A key part of this would |
be a kind of "Bean Invalidation Model" (BIM) which summarises the |
network of *model side-effects* that are expected to be |
represented in the view as a result of writes issued to EL |
paths. Some parts of the model could also just be declared |
"volatile". Event propagation as a result of user actions would |
then just be performed by framework code. Asynchronous propagation |
might be achieved just by timers, or perhaps by some form of |
AOP proxying. |
|
!!!XML AND OTHER TEXT |
|
|
To answer your question proper as regards XML stuff, at least in |
the area of Spring configuration, I think what will help here is |
the tool chain. I went on at length about Spring IDE in the TSS |
thread, but I should say again that Spring IDE was a key |
consideration in going with Spring for RSF as well as RSAC, in that |
now app-scope and request-scope containers can all be validated and |
refactored with a single tool. |
|
Lots can be done through "convention" as you say - in my Hibernate |
app for example I try to exploit the fact that an entity will be |
mapped under a name that agrees with its classname (in Hibernate |
2.x this happens by default anyway) which helps in constructing |
the bindings. I think the key problem in Java in this respect |
is that while may is possible for *beans* it is not possible |
for *methods* - given Java lacks the equivalent of C++'s |
"pointer to member function" or "pointer to member data" constructs, |
there is simply no way to programmatically generate a reference to |
a bean's property in a way the compiler could check. |
|
This does point decisively back to the "tools" answer. I think |
in general this is fuller answer than the "convention" answer |
which does if taken to extremes force a sort of "wizard" mentality |
on developers (lots of discussion on this on the "will Ruby displace |
Java" thread on TSS). Like humans, I think Java has survived |
primarily through its increasingly excellent tools, rather than |
through being adapted to any particular purpose :P RoR may be |
marvellous at cranking out "CRUD" type apps but take it even slightly |
out of its domain and it quickly becomes a nonsensical, fragile and |
frustrating environment. On the other hand Java (and more strongly |
XML) are sometimes annoyingly verbose (especially if you are using |
a bad framework :) but by their general regularity and widespread |
nature are increasingly becoming amenable to some quite marvellous |
tools - Eclipse, IoC containers such as Spring, CGLIB, various kinds |
of AOP are just a smattering - and now we are seeing the |
"2nd-generation" of meta- or fusion tools such as Spring IDE which is |
gradually becoming quite slick. |
|
|
!! Further points |
|
I do have to say that I would have dearly loved to have been |
able to preserve JSF as you advise - and struggled for nearly 9 months |
to do so if at all possible, given the very obvious practical and |
commercial benefits that this would have had. |
|
But unfortunately I came to consider even the two core JSF inviolables |
that you mention, the JSF lifecycle and the component "API" to be in |
error - Firstly, the form of definition of the JSF lifecycle, based |
on the "Phase" system is brittle and out-of-keeping with modern |
thinking on "locally controlled" systems based on IoC. For |
example, it is quite easy for a "rogue" piece of JSF logic to hijack |
the entire request processing by simply poking globally visible |
methods of FacesContext. The validation phase is particularly |
tightly coupled, I recall, both being hard to disable, and also |
quite liable to cause other phases to be skipped on its own |
initiative. Local code with global effects is a standing hazard. |
|
Another difficulty with the Phase system is that it makes it |
very hard to write "reliable" logic, especially viz. cleanup - |
in general no execution in Java can be relied upon other than |
a clearly visible try {} finally {} pair within the same stack |
frame, which is a situation impossible to arrange surrounding Phase |
logic - it is quite possible for Phase events and notifications to |
go astray in the event of unexpected failures and exceptions. |
|
Yes - I agree with you completely as regards the role of a framework |
as creating a standard "format" for interchange of self-contained |
pieces of logic and presentation. However, I'm far from convinced |
this should be done with the currency being a Java Object operating |
the semantics of something similar to a JSF (or other traditional) |
"component". It's a common misunderstanding of RSF that it makes |
such a "format" impossible, but as I argue on the TSS thread, it would |
seem a superior solution for developers to swap "components" in the |
form of paired ViewProducers (and other finer-grained beans such as |
Validators &c) and markup fragments rather than heavy components - |
polymorphism through interface and aggregation rather |
than derivation is a more sound development practice, in terms of its |
dependency impact. |
|
Anyone who I've spoken to who has worked with taglibs has been |
outraged at how hard they are to work with. In terms of |
"reinventing the wheel", many users tend to find that the wheels |
invented by vendors are rarely quite the wheels they want to use, |
and discover that trying to create their own is highly unrewarding. |
I think most framework authors tend to grievously underestimate the |
diversity of applications and requirements that their code will |
encounter, and imagine that the scope for "fully interchangeable |
parts" is far greater than, realistically, the industry is yet at |
a position of supporting. It would be far less effort for the |
community if as a whole they could define and exchange software |
artefacts on a variety of different scales, rather than the single |
monolithic scale that the vendor has determined - we still face |
the situation that there remains a lack of consensus in the |
industry as to what the equivalent of "wheels" actually are... or |
even, whether they should actually go round. |
|
I think this sort of problem is symptomatic of what could be called |
JSF "meta-failings" - while JSF always had the aim close to heart |
to establish interoperability, its development practices actually |
militate against this. As a different illustration, while many |
JSF core interfaces are in principle "reimplementable", this is |
unlikely to be realised in practice by more than a single |
vendor/developer at the same time - since JSF interfaces are so |
large and stateful (FacesContext, ViewHandler &c), it is unlikely |
that two different "users" of JSF would be able to arrange for |
their choice of semantics to be able to coincide within the same |
JSF "installation". |
|
In your mention of AJAX I have to note that it's precisely in this |
area I feel RSF more likely to benefit through "interoperability". |
Your point re reusability I think overlooks the point that Java |
"components" of any kind are now, and probably will remain a minority |
element of the webapp scene, which is increasingly full of bizarre |
heaps of dynamic HTML libraries and self-contained and |
self-conceptualised client-side artefacts of many kinds. It's |
precisely through being "behaviour-light" I feel the RSF "component" |
idiom is far more likely to lend itself to rapid integration with |
emerging technologies, in addition to its "plain-language" bindings |
system which renders server-side artefacts in a form readily |
interpretable and easy to manipulate on the client side. |