Another Round of URL Fiddling

Thu Jun 19 17:59:51 EDT 2014

Tags: domino urls

I was working on another installment of "Be a Better Programmer", but the result isn't where I want it to be yet, so it'll have to wait. Instead, I'll share a bit about my latest futzing around when it comes to improving the URLs used in an XPages app. This has been a long-running saga, with the latest installment seeing me stumbling across a capability that had been right under my nose: the ViewHandler's ability to manipulate the URLs generated for a page. That method worked, but had the limitation that it didn't affect navigation between pages.

As it turns out, there's a slightly-better option that covers everything I've tried other than navigation rules specified in faces-config.xml (but who uses those in XPages anyway?): the RequestCustomizerFactory. This is one of the various classes buried in the Extensibility API and present in the XSP Starter Kit, but otherwise little-used. In the Starter Kit stub (and in a similar commented-out stub in the ExtLib), it can be used to add resources to a page without needing to specify them in code - say, for a plugin to add JS or CSS libraries without being specified in a theme.

However, there are other methods in the RequestParameters object that would appear to let you shim in all sorts of settings on a per-request basis - different Dojo implementations, different theme IDs, whatever "debugAgent" is, and so forth. The one that interests me at the moment is the UrlProcessor. This is aptly named: when a URL is generated by the XPage, it is passed through this processor before being sent to the browser. This appears to cover everything other than the aforementioned stock-JSF-style navigation rules: link value properties, form actions, normal navigation rules, view panel generated links, etc..

Following my previous desire, I want to make it so that all links inside my task-tracking app Milo use the "/m/*" substitution rule I set up for the server. The method for doing that via a UrlCustomizer is pretty similar to the ViewHandler:

package config;

import java.util.regex.Pattern;

import javax.faces.context.FacesContext;

import com.ibm.xsp.context.RequestCustomizerFactory;
import com.ibm.xsp.context.RequestParameters;

public class ConfigRequestCustomizerFactory extends RequestCustomizerFactory {

	@Override
	public void initializeParameters(final FacesContext facesContext, final RequestParameters parameters) {
		parameters.setUrlProcessor(ConfigUrlProcessor.instance);
	}

	public static class ConfigUrlProcessor implements RequestParameters.UrlProcessor {
		public static ConfigUrlProcessor instance = new ConfigUrlProcessor();

		public String processActionUrl(final String url) {
			String contextPath = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath();
			String pathPattern = "^" + Pattern.quote(contextPath);
			return url.replaceAll(pathPattern, "/m");
		}

		public String processGlobalUrl(final String url) {
			return url;
		}

		public String processResourceUrl(final String url) {
			String contextPath = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath();
			String pathPattern = "^" + Pattern.quote(contextPath);
			return url.replaceAll(pathPattern, "/m");
		}

	}
}

The method of adding this customizer to your app directly is, however, different: instead of being in the faces-config file, this is added as a "service", as mentioned in this handy list. For an in-NSF service, you accomplish this by adding a folder called "META-INF/services" to your app's classpath (you can add it in Code/Java) and a file in there named "com.ibm.xsp.RequestParameters":

In this file, you type the full name of your class, such as "config.ConfigRequestCustomizerFactory" from my example. You'll likely have to Clean your project after doing this to have it take effect (and possibly in between each change to the code).

Now, my current use is very limited; the UrlProcessor has free reign for its transformations and is passed every URL generated by the XPage (except hard-coded HTML, unsurprisingly) - you could change URLs like "/post.xsp?documentId=foo" to "/blog/posts/foo" without having to code that explicitly in your XPage. You could write a customizer that looks up all Substitution rules for the current Web Site from names.nsf and automatically transforms URLs to match. You could go further than that, trapping external links to process in some way in the "processGlobalUrl" method. The possibilities with the other methods of the customizer go much further (and are largely undocumented, to make them more fun), but for now just fiddling with the URLs is a nice boon.

The frostillic.us Framework

Mon Jun 09 15:40:17 EDT 2014

Tags: framework

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.

REST Services for my Model Framework

Fri Jun 06 09:55:01 EDT 2014

Tags: framework

Recently, I've been refactoring out my framework code from XPages Scaffolding into an OSGi plugin. Part of this is just to help with code reuse and versioning: having a whole bunch of framework classes in each NSF is a drag, both from a perspective of having a bunch of extra stuff in the NSF and for having to worry about keeping them up to date (a template would work, but eh...). But another part is that it lets me work on some new features I've been itching to try.

One of those is adding REST services for model objects. Having access to your data via REST+JSON is pretty important, whether you're using Angular.JS, iOS, or miscellaneous. The Data service in the ExtLib does a great job of exposing document and view data directly, but it runs into the same problem that the standard data sources in XPages do: it doesn't have any provisions for your specific domain models. On the XPage side, I've solved this for myself by making a model framework that has done a fine job so far of covering my needs for accessing and collecting data in a pretty friendly way, and now I'm working on building REST APIs "for free".

Using the DAS as an inspiration (both in a vague sense and in a "using the code" sense), I'm working on Wink services to provide access to the model objects defined in each DB in a way that uses all of the same getters/setters with almost no changes to the code. The only change required (at least so far) is an optional annotation to define which fields should be included when accessing the object via REST. I'm aiming to match the data formats used by DAS as much as makes sense, since they're well-thought-out for representing Domino-friendly data, though the URLs will be pretty different due to the nature of my model manager objects.

This has been going well so far, and I'm looking forward to having it fully fleshed out. It should allow me to continue defining my model objects the same way I have been for use in XPages/Java, but then also be able to access the data just as well from other front-end technologies - potentially having NSFs that contain just a set of model definitions to act as a headless API app for use with other clients. And hey, if I get around to adding non-Domino backends to the model framework, the NSF would turn into a platform-agnostic gateway for data access.

Be a Better Programmer, Part 3

Thu Jun 05 11:06:03 EDT 2014

Tags: performance
  1. Be a Better Programmer, Part 1
  2. Be a Better Programmer, Part 2
  3. Be a Better Programmer, Part 3
  4. Be a Better Programmer, Part 4
  5. Be a Better Programmer, Part 5

After a break last week, this week's entry returns a bit to practical concepts. Specifically:

Develop a Working Knowledge of Relative Speeds

Performance of an app depends on almost-countless factors, but I've found that you mostly just need to know a few general ideas and rules of thumb to avoid the real pitfalls.

Big O Notation

The first thing to have a general working knowledge of is the naively-named Big O notation. This is one of the core concepts in a Computer Science curriculum and is often one of the more "mathy" subjects when you learn it. However, for the level of programming we do, it mostly serves as a warning to not loop too much. Specifically, avoid this sort of thing when possible:

for(int i = 0; i < someLength; i++) {
	for(int j = 0; j < someLength; j++) {
		// some stuff here
	}
}

That's O(n²): the amount of times that the inner loop runs grows quadratically with the size of "someLength", and it's among the worst things you can do. I recommend looking around for some basic introductions to the concept, such as this article. One thing to remember with Big O notation is that it's a general guide, not a hard-and-fast rule: an O(n²) algorithm may be faster than an O(1) if what the latter is actually doing is really slow in some other way.

I/O Overhead

Another key thing to keep in mind is that the difference between "levels" of activity - in-memory, DB access, etc. - is often so great that it completely dwarfs any other complexity. For example, it's usually going to be significantly faster to sort/search/mangle a data structure in memory many times over than to access a database even once. As with Big O, this is sort of a fuzzy rule, but I tend to keep a couple order-of-magnitude levels in mind:

  1. In-memory structure access
  2. Efficient database access (open connection, in-memory)
  3. Filesystem access
  4. Remote database/service access (e.g. web services)

#2 and #3 probably go back and forth in performance in different contexts, but any filesystem use is "dirty" enough conceptually that I downgrade it just for that.

This is why caching and minimizing database access is so important. The Domino programming environment makes it feel like the database is there "for free", but it has all the same pitfalls. Say you have a basic List of Maps in Java and the same data stored in a view in Domino, and you want to do what amounts to a keyed lookup. Even though the algorithm for doing a lookup by key in Domino is (presumably) very efficient from a Big O perspective, even a linear search through the List in memory is going to run laps around it.

There are, naturally, limits: some database operations are particularly fast and some in-memory algorithms are particularly slow.

Platform Knowledge

And in addition to the rules of thumb, sometimes it's best to just know a lot about the platform you're working with. Sometimes this comes with a knowledge of the general type of platform (e.g. key/value lookup in a document DB is fast, "relational" activity is not), and sometimes it just takes hands-on experience.

Fortunately, this becomes self-reinforcing as you learn it. Once you run across severe pitfalls (say, db.Search or using @Now in a view), you develop sort of a visceral revulsion to using it again except when it's the only option. Eventually, you build up enough working knowledge and callouses that it becomes second nature.


Once you have a good grasp of what is and isn't quick, it can really help you structure your programs more effectively. Not only does it help you write faster-executing code, but it also helps you understand when it does and does not matter: if you have code that will only execute once, you can intentionally forgo a faster-but-harder-to-maintain algorithm in favor of a clear-but-moderately-slower one as long as you know you're not falling off a performance cliff. That balance between writing for the computer and writing for other programmers is one of the crucial things to strive for.

Swift

Wed Jun 04 20:52:28 EDT 2014

Tags: swift

This is a topic that doesn't really fit my usual bailiwick of Domino programming, nor is it something I'm particularly qualified to comment on, since the most Objective-C programming I've ever done was some putzing around years and years ago with a weird idea for a pseudo-database that didn't even involve Cocoa, but I'm going to talk about it anyway.

I'm really excited about Swift.

In case you don't follow Apple circles, Swift was one of the fire hose of announcements at WWDC on Monday. It's a new programming language designated to replace Objective-C, billed as "Objective-C without the C", and can be thought of as Apple's Go.

So why am I so excited about it? Part of it is that I've been flirting with the notion of diving into Cocoa development proper, and this provides a perfect impetus. But beyond that, it tickles my programmer brain in a great many ways.

Low level + dynamic

The primary thing that piques my interest is the way it blends the best of what in olden days were referred to as "systems" and "scripting" languages. It's not the first language to do so, but it'll be among the few to get widespread adoption. It's C without pointers (mostly); it's functional programming without the Lisp; it's Objective-C without the brackets and @s; it's Ruby/Python without the speed loss; it's ML/Haskell/etc. without the "what the hell is this?".

What this means in practice is that it doesn't shy away from syntactic sugar. It's extremely common to want to make literal arrays and maps (Dictionaries in Cocoa parlance), and so Swift has clean syntax for those. They want to really emphasize closures, so the syntax gets cleaner the simpler the task is. They want strong typing, so they use type inference to get the result without all the "oh, come on, you know what I mean!" feeling you get from writing Java.

Good for programmers and compilers

It's striking just how many of the syntactic sugar bits and the defaults of the language are geared both towards improving programmers' lives (with easier code and bug prevention) and improving compiler optimization. It seems like it's a product of the modern state of compilers: whereas C was made during the infancy of computing and is designed to allow the programmer to really turn the screws in tons of crazy ways (see: pointer arithmetic), Swift is designed to take advantage of the fact that the bounds for what makes a good program are now well-known, and by restricting "dangerous" operations, the code is not only safer but also much more predictable.

One example of this is something that most current languages have adopted: for-all loops. In languages without them, it's contingent on the programmer to write the looping logic themselves. In pre–for-all Java, for example, this meant either using array indexes or Enumerators/Iterators. Those ranged from sort of a pain and potentially inefficient (indexes) to probably fast but horrendously ugly (the others). But for-all loops fix that: not only is the syntax much easier to type and is much clearer in intent, but now the compiler can choose the most appropriate method of iteration.

Swift is full of this, from its focus on immutability to its use of the "override" keyword to its integration of functional-programming idioms.

Type inference

I mentioned this already, but it deserves its own section. I've long had a very conflicted view on type systems. On the one hand, I appreciate the values of a Java-style strict type system - the consistency, the prevention of errors, the self-documentating nature - but good lord is Java a huge PITA to actually write sometimes. I can't even count how many times I've written a line like this:

List<Map<String, Object>> someListOfMaps = new ArrayList<Map<String, Object>>();

Gahhhhh. Every time! Never versions of Java have improved on this (though we as Domino programmers likely won't see that for a while), but it's still a drag. Moving to a strongly-typed-but-declaration-free language like Ruby is such a breath of fresh air. Not because I specifically want to assign objects of different types to the same variable, but because I don't have to fight the compiler over nuts-and-bolts of getting the right class name down.

The kind of type inference Swift uses makes Java-style strictness palatable. You get all the benefits of strict typing, both to you and to the compiler, without having to write "Map" five hundred times per source-code file.

LLVM as .NET or the JVM

LLVM is the just-above-the-metal virtual machine that Apple uses on its devices, and this sort of marks its coming-out party as a multi-language platform in the vein of .NET or the JVM. Swift files compile down to the same object types as Objective-C, so you can mix and match them in the runtime, much as you could mix and match multiple .NET languages or Java and Scala. In practice, this means that diving into it in an existing Cocoa app is much easier than having to rewrite the whole thing, while it also means that someone like me who isn't well-versed in the framework can still make use of the decades of Objective-C knowledge online.

Conclusion

So in conclusion: I'm just real excited. This looks fun! It's like a best-of setlist from all modern languages built on top of a giant framework that lets you build apps immediately. You should give it a look too - at the very least, watch the end of the WWDC keynote, where it was introduced.