What Do We Really Need From A Controller?
A Discussion Paper
By Duncan Mills
Over on the Apache Struts Development list server discussions have been going
on about the proposals for Struts
2.0 (aka "Shale"), in concert with this we have Erwin Vervaet's
Spring
Web Flows recently announced. All of this has got me to thinking. What do
we really need from a Controller? We have a lot of competing frameworks out
there, each with a world view and enthusiastic user base, is this a race that
needs to be won or has no-one defined the finish line yet?
Name the Beast
So first of all what is a Controller? Even in the clinical world of the Model
View Controller (MVC) architecture the Controller is a somewhat schizophrenic,
just take a look at the Core
J2EE Patterns index diagram published by Sun, as an example. We have multiple
instances of the Front Controller pattern liasing with View Helpers and a Dispatcher.
If you think about an established Controller framework such as Struts, these
are all mushed together into a monolithic Controller framework, is this approach
still relevant in today's J2EE development?
Looking at development for today's systems we may well have to think about
integrating with technologies such as Portals or JavaServer Faces (JSF), situations
in which there is already an owner of the Front Controller role and potentially
the View Helper role as well.
JSF is an interesting example, if I think about the Controller in Faces I'm
really just thinking about Faces Navigation. All of those other "Controller"
roles are there, but handled by the View framework itself in a front controller
role. So the controller is shrunk down to not much more than a simple dispatcher.
Is this enough? Does JSF offer me all of the functionality and maintainability
that I would get from a fatter Controller framework such as Struts? My heart
tells me that the answer is No, I do need more functionality than the simplistic
navigation model in JSF can offer, but in turn leads me back in a circle to
this question of what exactly it is that I think I need.
This fundamental problem of the exact definition of the Controller role needs
to be resolved. It is inevitable that there will be bleeding at the edges where
the controller interfaces with the View in particular, and the degree of overlap
will differ based on the View technology being used. (If we take the assumption
that a Controller framework should be View agnostic, which I think is uncontested).
So lets look at some of the things that a controller must do and could do.
Things A Controller Must Be And Do
- Be agnostic of the view technology. Yes we need good controller for JSF,
but that's not to say that all UIs will be written in that technology. This
was a point well made in the Shale (Struts 2.0) proposals where the requirement
is for a layered controller that can be adapted to the View technology in
use.
- Be driven by some sort of metadata. It is, after all, a framework. If you
had to code it all then there's no point. Metadata (let us say XML, although
annotations are an alternative) can be understood and rendered in a useful
way by development environments as well as fulfilling the job at runtime.
We should not underestimate the importance of making a technology tool friendly,
you should not have to use an IDE of one flavour or another to complete a
task, but if an IDE can be instrumented to take away the drudge work and prevent
silly mistakes you can but encourage better, and faster development.
- Make it declarative. You don't want to have to write code to do something
as simple as check the value of a request attribute and route accordingly.
Many simple tasks within the View layer are now being accomplished using Expression
Language, there is no reason why Controllers cannot adopt the same techniques.
The more logic that is pushed into that metadata the better.
Allow code execution as well as page navigation. This is one of the major
flaws in the JSF navigation engine; all it does is pages. A Controller should
be able to chain non-visual activities into a flow as well as the visual ones.
A common use of this in the Struts world is the use of a page handler Action,
acting in co-operation with the page display action. But the same technique
is used for all sorts of call outs and routing logic in particular.
- Make security simple. If you are running a Controller "in container"
the very least to be expected is that it should be simple to hook into the
container defined security. Frameworks like Struts already give us this at
a simplistic level, but of course in reality a simple role match is not enough.
The argument could be made that Servlet Filters are the best solution for
applying security across an application but I beg to differ. As soon as you
start to care about more than "Is the user authenticated" then the
Controller has an interest. Tasks like routing based on user role are common
and should be provided out of the box.
- Escape the tyranny of the Servlet API scopes. In reality Application, Session
and Request don't reflect the requirements of applications. We need support
for sub-processes (or "Dialogs" in Shale parlance), which will provide
a task based persistence scope rather than being tied to the request/response
cycle.
Allow multiple configurations. As part of the metadata ideal you want to be
able to split defining metadata into multiple fragments. This helps with team
development, but it's also valuable with runtime customisation and reuse (see
below).
- Back button support. One of the bigger headaches suffered by application
designers is how to handle the browser back (and forward) button. The approaches
you'll see will vary from running the application in a window without any
browser chrome, right up to sophisticated handcrafted state management that
handles the situation. The norm here being some sort of token-based implementation
that will not roll back state in response to the back button, but will at
least allow you to detect it and throw a suitable error. Ideally a controller
will manage state automatically and restore the correct state automagically.
Such a facility should be declarative and configurable, there is after all
a cost associated with such management, a cost you may want to limit or indeed
eliminate all together. Although this idea is great on the surface, as you
dig deeper you realise that there is a much more complex problem to overcome
here. How do I coordinate such state management with other participants in
the transaction, my EJBs for instance?
- Customisable. It goes without saying that it should be possible to provide
your own implementations of the key portions of a Controller framework. Both
in the override sense, and in the supplementary behaviour sense of a plug-in
mechanism.
Things A Controller Could Do
- Runtime customisation. One of the issues with Struts is its immutability
at runtime. How can a vendor of packaged applications provide site level customisations
and even personalisation in this case? You end up either having to work every
case into the base metadata, vastly increasing the complexity of the thing,
or you have some kind of manual merge of site customisations with the base
controller definitions every time that you apply an upgrade or patch to the
base. One of the great bonuses of good metadata design is that, with a suitable
backing framework, you should be able to make all of this seamless. So Sites
can customise their page flow, for instance, and theses changes are held separately
from the base definition, allowing the system to be patched and upgraded with
much less intervention because the base definitions have never been changed
on site. It's also important that the normal way of doing such customisation
is through layering metadata rather than having to write code, although there
is a place for that too.
- Headless operation: When is a Controller not a Controller? - When it's a
workflow! Seriously though, is there a place for using the same Controller
framework for both UI driven applications and what I will carefully call "Process
Flow". I hesitate to use "Workflow" here as that is a more
complex beast, and implies multiple concurrent activities and so on. The kind
of process flow to consider here is a simple process, which may have alternative
pathways based on conditions and outcomes, but is essentially linear. If a
Controller framework is View agnostic, should it not be Container agnostic
as well? I want my Controller to be able to run in batch mode as well as within
the context of servlets, or portals. This implies of course that a Controller
is about much more that displaying pages, and suggests a level of abstraction
(lets call it an Activity) which wraps tasks like displaying a page which
are UI related, as well as backend tasks such as automating a milling machine
or sending an email.
- It should be testable. Something that headless operation leads to is enough
abstraction to make the processes managed by the controller testable out of
container.
- More reuse. One of the promises of using a controller in the first place
was to take navigation logic out of the page definition and thereby make pages
re-usable. How true this really is in reality is debatable, the pages are
certainly easier to maintain but re-use? Anyway, it is still a laudable aim
for a Controller to aspire to although I feel that page re-use is too modest
a target. Imagine if you will a toolkit of sub-processes (dialogs) fulfilling
standard tasks that encompass more than simple page re-use, for example a
complete user maintenance module. It should be possible to construct such
re-usable flows or processes and plug them in anywhere. This approach is already
used in some Controller frameworks, such as the Oracle MVC framework, and
from a slightly alternative viewpoint: JetBrains Fabrique.
In Conclusion
This article has been all about throwing a few ideas out there with an aim
to gather consensus as to what the problem is that a Controller framework is
trying to solve. We are at a pivotal time with respect to both JSF and Struts
Shale and indirectly with the percolation of J2EE adoption into the larger business
programmer community. One big question remains of course, is the Controller
role something that should be standardised? We have standards now for UIs in
JSF, persistence and business logic in EBJ, JSR227 offers another piece of the
puzzle with respect to data binding, but the Controller is still one of the
larger missing pieces. It's worth thinking about.
© Duncan Mills 09/Nov/2004
Version 1.0 http://www.groundside.com/blog