| 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. |