On the suggestion side, of course, when a framework is doing something you don‘t want it to do, the simplest solution is to say it needs to be rearchitected to expose that particular part of its functioning to pluggable replacement. So somewhere in the JSF codebase, there is code that is responsible for marshaling/unmarshaling of data. Right now that follows a super simplistic approach: the EL expression is interpreted as bean.property, so User.name is the user bean having a property called name. At that point, the framework looks to gain access to name through a pair of set/get methods. (See prior post on why this is suboptimal.) The first, and simplest solution would be to make this a strategy pattern. Now, the problem would be of course that you would be making it so that the little language of the framework was subject to being rewritten, which means that the whole benefit of a standard faces possible dilution. I would propose that we should expose this piece, then do a swarm on how it should work, and ratify the result as the 2.0 strategy. For instance, what would be wrong with explicit support for static builders that followed the following guidelines?:
- When a property is found, if a set is not available, a builder is sought, and then the method on the builder is found either through annotation, method name, or argument type? (Keep in mind, the marshaler could do this once and hold onto the results.) Now that may seem like a tortured way to get to a conclusion, BUT, consider the fact that IF it could not figure out how to marshal the data, it could throw a very clear explanation telling the user his/her choices on how to get the two filaments to fuse.
- If this is not explicit enough, perhaps builders could be registered as types of managed beans.
- A test harness could certainly be provided where any given entity could:
- (Textism cannot do nested numbered lists.. :(.) Have a form generated from its properties complete with the appropriate bindings.
- Could be exercised as part of the build process to make sure that the bindings were all still valid.
- Could even have an assistant that would be invoked when bindings were broken, with fix suggestions.
- Ultimately, these things could be handled as a simple Strategy, or a Chain of Responsibility.
If this all sounds to wishy-washy, consider the fact that an EL-based process, by its nature, is going to require some functional form of an Interpreter. Interpreters that only cotton to one sort of expression often harm their own cause, as is the case here.
Other Haunting Issues
One of the other architectural features of JSF that has haunted it in its n years of existence is the fact that it is totally based on intercession at the component level, but on a per property basis. There is no ready means to effect page behavior (there is hardly a concept there at all), and likewise, there is no notion about the lifecycle of the beans that are part of the whole binding process. Now, clearly, this makes for a somewhat blind dynamic. Facelets is a good example of this: as superior as it is as a templating technology, as a component, it is out of gas very quickly because there is no sense of component state. Anyone who has written components in JSF knows that it isn‘t that the components don‘t have state, it‘s that they choose not to expose that state, but rather act as if it is always reflected in the bound bean. Consider also the fact that RIAs carry with them the concept of updating the current state of a set of components interactively. If you use RF, you know that you have to do that by going through the lifecycle each time, otherwise, you don‘t get updates out to the various interface elements. This causes pain when you have things like required, and validation in place because you might want to do an update of just part of the aggregated state. (This is where PAC starts to make a lot more sense: providing as it does for component state and intercomponent coordination to exist while editing.)
The other problem that JSF‘s choice of narrow intervention opens up is the fact that transformations of the entities being edited cannot be standardized in any way. For instance, we have done a wizard framework that is based on a single component that has many panels, and it can be run in 3 different modes: wizard, tabbed, and stacked. The advantage of this approach is I can walk you through the initial creation of an entity (e.g. a membership that includes a subscription), in wizard mode, then invoke the same component in tabbed mode when you want to edit it. Well, this recent exercise of doing a subscription made me realize a few things:
- Class design must reflect the boundaries of what is editable in an entity, and putting set/gets on every property effectively erases this chalk circle. For instance, a Subscription must be made of at least: a Subscriber, a Publication, and a Term. Meanwhile, where each issue of the Publication is sent is probably going to be changeable. So in a Blochean universe, we would only provide a set for ShippingAddress and all other properties would either be constructor args, or better yet, only settable through the static builder. What we are saying with such a design is very clear. Now, it would make sense to delineate in the ui what activity we were seeking to engage in. Clearly, if we are going to create a new subscription, we need the ability to provide values for all the properties then go through the whole cycle and create a valid entity and probably store it. Later, when we want to edit that entity, only the editable properties should be editable. (This is something I think most people who have done a lot of JSF run into, which is making interfaces where in a certain mode a property is editable and in another it is not; generally the ugly solution prevails: two controls for each thing and a rendered flag.) I, for one, would love to see the framework expand to grapple with these kinds of issues and do not see them as in any way out of scope. Frameworks are labor-saving devices and this would save TONS of labor.
- When new objects are created, lifecycle things often get kicked off, for instance, a Subscription is something that expires. This of course means that either the starts property and the duration or term fields are computed upon creation, or there has to be a start method added to the class. This is another reason for delineating between new/update bean transformation modes.
- Also, a huge raft of very useful additional services could be opened up, for instance auditing functions, permissions, authorization integration, etc.
What form would this take? Well, there would have to be some simple means of knowing whether we were creating an entity or not, and frankly, the more sophisticated, builder-aware interpreter would only be needed for that mode. For edits, set/get would not only suffice, but would even communicate constraints that could help in defining the rights the ui had to transform the entity. This is a whole other area that bleeds into the process/tools layer, whereupon the components group (think PLE) would be able to prevent one of the typical JSF disasters: well-meaning juniors throwing all the doors open in the name of making a ui ‘easy to use.‘