For a while now, I've maintained a project called XPages Scaffolding on OpenNTF and GitHub. This project is the NTF that I use when creating a new XPages application and acts as a storehouse for my "bag of tricks", things like my model framework, controller classes, and various goodies I've picked up over the years, like a JSFUtil class and a flashScope. For a while, I've figured that, once this stuff is in proper shape, I'd extract it into an OSGi plugin and get it out of the NSF. Last week, I decided to take the plunge.
Something surprised me about the process: not only did I gain the benefits of a cleaner NSF and a nicer environment for editing the code, but it really solidified my focus for what I want it to be and gave it a real sense of purpose. The newly-dubbed Framework is geared towards turning an NSF app into two main things: a data-access API available via Java and REST and an XPages front-end that is first-among-equals for accessing that API and follows defined structural conventions.
The Model Framework
The model framework is the newest part of the project and the REST API in particular is only days old, but it's rapidly becoming the most important aspect and is likely to be the spiritual core. By providing a way to define models in a way that is simple, consistent, and (theoretically) storage-agnostic, a large part of the work of creating a new application is made significantly easier to write and understand. The models provide numerous characteristics built-in that would previously have been implemented as a series of script libraries, XAgents, and UI components:
- Collection access. The Manager classes let the XPage care only about getting a collection of "my Tasks", rather than "the 'Tasks by Assignee' view filtered to just the category of @UserName()".
- Property control and side effect handling. Model objects allow handling side effects where they belong, so setting, for example, the Client field to a new value needing to reset Project to blank is done there, not on every XPage implementing those fields.
- Validation. I'm currently trying out integrating Hibernate Validator into the framework to allow for declarative constraints on a model's properties. It shouldn't have to be the XPage's job (solely) to know how to validate an email address or ensure that a username is at least N characters long. By declaring it at the model level, it frees up code elsewhere while also allowing to constraints to function when accessing models programmatically.
- REST API. This is the new golden child that has brought this clarity of purpose to the framework. Having "for free" REST access to the model objects in an app removes a ton of potential work from the programmer and also opens up tremendous opportunity for integration. Previously, allowing access to an app's data meant rewriting all of the business logic, either in the foreign app (accessing the data via DAS or legacy Domino APIs) or in XAgents designed to serve up JSON. Now, when you write the business rules for your XPages app, you're also writing a method for external access. Things like a JS-based or mobile app move from "possible with lots of work" to "may as well". It also means you don't have to choose between having either an XPages app or an interoperable API.
The XPages Components
The XPages side of the framework is still something of a grab bag, filled with the aforementioned small utilities, controllers, my dying-on-the-vine messaging framework, support classes for writing in-NSF servlets, and a number of useful converters. In the process of plugin-ifying these, I've made some refinements, such as turning the converters into real JSF components, redubbing "JSFUtil" as "FrameworkUtils" and making it work in a non-Faces OSGi environment, and integrating my @ManagedBean implementation.
The transition has also given me the freedom to be a bit more brash about changes, making backwards-incompatible tweaks that I've been meaning to do for years, making the different parts of the framework a bit more integrated, and a number of other things I have in mind to try out.
But though this side is less integrated than the model side, it still represents a consistent way to write XPages applications: model objects for data access, controllers for primary logic, servlets instead of XAgents when appropriate, SSJS relegated to glue code in Custom Controls, and a consistent, simple naming scheme for Java classes favoring simple "local" package names like "controller" or "model" over fully-qualified ones like "com.somecompany.appdev.domino.xpages.apps.someapp.controllers" when appropriate.
All in all, I'm pretty excited about the changes I've been making. For as long as I've been working with XPages, I've been searching for the "right" way to write them, and I feel like I'm finally approaching an answer I can feel comfortable with.
And not only does my XSP code feel better and less cluttered, but it makes the platform as a whole feel better. It's always been the case that server-based app-dev lets you use whatever environment you want, though modern web development has modified that situation somewhat. It's still true that your framework doesn't necessarily matter, but it should be able to adhere to common contracts to function in an interoperable world. Much like other things I want the platform to do, the model framework in particular brings Domino into a role where the NSF-based app is the central dispatch point for a multi-platform environment. Don't want to use NSF for data storage? Plug in a different back end. Don't want to use XPages for the UI? Use the REST API and get the same transparent data access.
I think there's good potential with this setup.