More Musing About Controllers
May 13, 2012, 8:45 AM
I've been thinking more about this MVC thing, thanks to re-learning Rails. I'm fairly convinced that moving as much code as possible out of the XPage and into wrapper objects is a big improvement (convinced enough that it feels silly that wasn't doing it already), but it still feels not quite right.
Two parts of the MVC trinity are straightforward in modern Domino development: Forms and wrapper objects are the Model and XPages are the View. The Controller is where things get muddy. Off the top of my head, routing and controlling are handled by:
- Domino's built-in URL handling
- "Display XPage Instead" on Forms and Views
- Web rules in the Directory
navigationRules on the XPage itself
- The XPage's names themselves, as used in URLs
- Anything fancy you do with document mode switching and multi-page XPages
It's kind of a mess, and very few of these are really programmable. You can do a lot with web rules, but the application itself doesn't know about them, so you end up with code that's coupled with a specific server configuration - very unsafe. Domino's built-in URLs work well enough for basic operations - show a view, open a document, edit a document - but don't understand more complex concepts, like a shopping cart "Checkout" (yes, I just re-did the depot tutorial from the Rails book).
Honestly, it might be enough to move the action code out of the XPage and into the wrapper classes. That's a big step in readability, maintainability, flexibility, and error prevention, and most sites get along just fine with a lot less. Still, it doesn't feel right.
I don't really have a better option, though. This morning, I've been kicking the idea around that you could treat the XPage itself as the Controller, sacrificing URL and code cleanliness for some power. In this setup, a main XPage would correspond to an aspect of your application (say, "AdminSite") or management tools for a data type (say, "Posts"). You would construct your URLs by chaining path info past the ".xsp" part and then use the main page (or, ideally, a shared library across all pages) to figure out what the real request is. You'd end up with an extra level to your URLs, like "Posts.xsp/search?q=foo". It's horrifyingly ugly, especially right after "whatever.nsf", but it makes a sort of sense: ":application/:controller/:action?:parameters". The alternative now is to have multiple XPages that each deal with very similar things and, if you have a large app, name them in a structured way anyway, like "Posts_List.xsp" and "Posts_Search.xsp?q=foo".
You'd have to put the individual action code in custom controls with
loaded parameters to match the action - this would add yet another type of element to the custom controls list ("subforms", actual custom controls, and now the View component of each action), but it may be a necessary evil. The Extension Library has something like this, though not exact, in its "Core_DynamicPage" demo.
The whole idea seems a bit half-baked at the moment but worth investigation, so I'll have to tinker with it a bit when I have some time.
Bjørn Cintra - May 13, 2012, 10:02 AM
We do this actually, using the xpage as a "master" controller, that basically loads the rest of the framework, and routes urls to controllers. I am using a modified version of the router that is in the Play framework to map url's and parameters to controller classes.
The framework (and controllers) are built with Groovy, and packaged as jar-files. However, I am not using JSF for the View (as we have a need for our customers to change the views themselves), I am using Freemarker. This gives us great freedom in presenting standard based html5 (and xhtml), something that won us the award for best public website in Norway last year (www.okokrim.no).
Btw, we set up a web rule to map our /path/to/db.nsf/index.xsp/* -> /*, this takes care of the ugly parts of the url, but it does require that sites we build have their urls built to reflect this.