Using GWT’s Application Framework Judiciously

I am very excited to see the inclusion of a proper application framework in the upcoming Google Web Toolkit 2.1 release. The addition of this framework is a clear signal that GWT is a serious library for enterprise scale applications.

As a seasoned developer, I am very familiar with the traditional Model-View-Controller approach to building web applications. The MVC approach works great for server-based frameworks like Spring MVC or Struts. However, ever since I started working with GWT way back at version 1.4, I’ve had a hard time mapping MVC into a truly client-side application where the entire GUI is built in GWT.

The MVC approach is tried and true in the desktop software world. But on the web, there are a few extra quirks that make traditional MVC a little tricky. Here are some of the challenges I’ve run into.

History Management and Support

Because it is a web application running in a browser, there is an implied expectation that the forward and back buttons work, regardless of whether your web application is mostly client- or server-side. This presents a unique challenge to MVC because most desktop applications don’t have forward or back buttons.

Bookmark Support

Another important feature to any good web application is the ability to bookmark or share the link you’re currently viewing. It should be possible to bookmark a page or paste the current URL into an email, for example, and restore the state of the application based solely on that URL.

Composite View Structure

When working with traditional MVC frameworks like Spring MVC, the process is pretty straight forward. For any given URL, only a single Controller responds to the request. The Controller prepares a single Model and that Model is handed off to a single View. Common elements of the UI can be rendered with include statements, but the View generally has a very direct relationship with the URL.

Conversely, with a more desktop-like application built in GWT, the UI is frequently built as a Composite. There are several components in play at any given time and there isn’t necessarily a straight forward relationship between the current URL and the current set of components viewable to the user. This makes intra-application messaging and navigation a bit more challenging; you can’t just rely on a DispatcherServlet, for example, to coordinate user interaction.

Enter the GWT Application Framework

Clearly, the new App module in GWT is designed to address many of these concerns. It’s great to see History Management and the notion modular composite structure being supported as first class features.

The application framework in GWT is all new to me, though, and it isn’t really MVC. Instead, it’s more of a Model-View-Activity (or -Presenter) approach. In this case, the Activity takes the place of the Controller and is responsible for only the slice of the UI represented by its View. This MVA approach handles application navigation very well, assuming your application is, like a traditional web application, a series of screens or “activities” through which the user navigates linearly.

So what happens when the UI dictates that two or more of these activities be present at once? Well GWT can handle that as well by using multiple ActivityManagers. The ActivityManager is responsible for coordinating all of the Activities for a designated Display – the area of UI over which control can be delegated to an Activity.

This is all well and good, but Project: Apollo presented me with a unique challenge in this new MVA architecture. What do you do with UI components that are always present? Case in point: Apollo has a control bar that is always present in the UI, similar to the button on the front face of a DVD player.

The control bar allows the user to control playback and displays pertinent playback information such as the elapsed time and name of the current track. The control bar, by nature of its omnipresence, does not participate in the navigational functions of the ActivityManager, nor is there any other Activity that would fill its slot.

I’ve also gleaned through GWT code in trunk that the usual way of handling Activities is through an ActivityMapper; the ActivityMapper is responsible for resolving and creating instances of Activities and their corresponding Views. However, control bar isn’t managed as such. I have a self-imposed rule in development of Project: Apollo that UI components should be UiBinder compatible; I should be able to include the control bar in my UI declaratively through the constructs afforded by UiBinder. By contrast, Activities depend on the current state and history of the application, so their lifecycle would not be appropriate to manage through UiBinder, hence the Display slot concept.

Bring Back the Controller

The Java docs for Activity state:

Implemented by objects that control a piece of user interface, with a life cycle managed by an ActivityManager, in response to PlaceChangeEvent events as the user navigates through the app.

It’s easy to see that my control bar doesn’t strictly qualify as an Activity. In this case, MVA isn’t a good fit; I need a different approach. One option, for simpler components, is to let the UiBinder template be the “view” and the backing Widget code be the “controller”. For more complex components, though, I still want to break out application logic to a separate class and leave UI-centric logic in the View-backing code.

Taking a hint from previous iterations of GWT’s application framework, I am choosing to call my pseudo-controllers “delegates”. The Delegate represents a code structure to which the actual View will delegate user interaction for handling. Delegates contain familiar Activity-esque functions to facilitate lifecycle events where necessary.

public interface Delegate<W extends IsWidget> {
    void shutdown();
    void startup(W widget, EventBus eventBus);
}

For my control bar, then, I have broken the code into a ControlBarWidget (the View), a ControlBarDelegate (the Delegate), and a ControlBarModel (the Model).

To keep with my requirements that the control bar be UiBinder compatible, I am allowing the View to handle creation of a default implementation of the Delegate. I’m using GWT.create() to instantiate it so the actual implementation can always be easily swapped out later via deferred binding, but for now, the need to swap out implementations is low to non-existent.

The Judicious Part

The lesson I am driving at here is that the new application framework in GWT may be great for some portions of an application, but it probably isn’t appropriate for everything. Parts of the application that do not participate in history or navigation (such as global menus or controls) are not good candidates for Activities.

I think GWT and the new application framework represent a fantastic toolset for building user interfaces and entire applications. You just have to be smart about when and how you use them.

2 thoughts on “Using GWT’s Application Framework Judiciously

  1. Your “delegate” really is a Presenter in the MVP design pattern (be it Supervising Controller or Passive View). I don’t think there’s much added value to having a startup and shutdown methods (an initialize method sure, but shutdown?), but if you think there should be, then why not using the Activity interface, even if you call the methods directly rather than rely on an ActivityManager and PlaceChangeEvent?
    Also, if you want some example of a Widget that uses MVP, then have a look at the Cell data presentation widgets (AbstractHasData for instance), which use a presenter internally so you can use them as any other widget.

    • A Presenter by any other name… yes I realize the patterns I’m using here. I just wanted to be sure these Presenters were distinguished from “Activities” since they are not Activities. They also don’t fit the “Presenter” interface found in frameworks like gwt-presenter.

      You make good points, though. Here, UI objects like my ControlBar are intended, nay expected, to be created once, added to the DOM, and stay there until the application shutdowns due to the user navigating away or closing the browser. In this case, there really isn’t much need for a startup or shutdown method.

      Based on this, it probably makes sense to revisit whether the WidgetDelegate interface is really necessary.

      Thanks for the feedback.

Leave a Reply

Your email address will not be published. Required fields are marked *