Why Ext-GWT MVC is broken

Introducing Ext-GWT

Our current project is a GWT project, and we’re using Ext-GWT as a widget library and framework.

Ext-GWT (formerly MyGWT) is a “pure” Java/GWT port of the well known Ext-JS JavaScript library, not to be mistaken for gwt-ext, which is a Java/GWT wrapper around Ext-JS… Still following?

In short, gwt-ext requires Ext-JS, while Ext-GWT doesn’t. Ext-GWT is from the same company that makes Ext-JS (appropriatley called Ext), while gwt-ext is an independant work. Also, since version 2.1, Ext-JS removed LGPL from its licensing options, which effectively prevents software like gwt-ext from using it, so it’s stuck with v 2.0.x.

Anyway, this isn’t my point. Ext-GWT in its version 1.2 features a so-called “lightweight” MVC implementation, which we use on our project. Unfortunately, this implementation is quite flawed, and this isn’t harmless because it allows all sorts of problems to arise, that a clean MVC should prevent.

YAAADMVC (Yet another attempt at defining MVC)

First, it’s hard to come by a good explanation of MVC.  according to Wikipedia, it was first described in 1979 by Trygve Reenskaug, and since then it has seen innumerous variations and implementations, some bright, some less bright… Judging by the number of incorrect or plainly wrong explanations you can find on the web, there must be something inherently hard to get in it. However, I’ll have my shot at explaining.

MVC is about roles. It defines three roles, namely Model, View and Controller, and how they interact. Some have interpreted these roles to be software components, which led to MVC frameworks, and some as architectural components, which led for example to so-called MVC web frameworks. Here we concentrate on the software component approach.

So what are those three roles?

  • The model holds the data and provides an interface to manipulate the data.
  • The view is a graphical representation of the model, and possibly also user controls (such as buttons, etc.). It is also able to generate events to any interested listeners, for example to signal a user action (button pressed, etc.)
  • The controller pilots both the view and the model. It reacts to user interaction in the appropriate manner, including possibly updating the model.

This definition might not be universal, and some might disagree on some points, but it is viable.

Some important points:

  • The model does not know anything of views or controllers. Ideally, it is observable and notifies its changes to any interested listeners.
  • The view only has to know its model, at least enough of it to build the display. If the model is observable, the view will register as a change listener and update the display whenever the model changes. The view does not need to know its controller (and indeed you could use a view without a controller if you didn’t need user interaction)
  • The controller listens to events sent by the view, and only the controller should have the intelligence to know what to do when something happens, like a user pressing a button.

Why is this important? because it cleanly separates the responsibility of each component, and we know that leads to code that is more readable, more testable and more maintainable. Less coupling, more consistency: the basis of a good architecture.

Here’s the best diagram I’ve found describing the relationships between MVC components (from http://best-practice-software-engineering.ifs.tuwien.ac.at/patterns/mvc.html):

Relationships between components in a MVC architecture
Relationships between components in a MVC architecture

MVC in Ext-GWT

So let’s have a look at Ext-GWT’s MVC implementation. This is the constructor of class View:

  /**
   * Creates a new view instance.
   *
   * @param controller the parent controller
   */
  public View(Controller controller) {
    this.controller = controller;
  }

Yes, the view knows its controller… Why is it so? Looking further into the source code, we can find the explanation:

  /**
   * Called when a view needs to pass an event to it's controller.
   *
   * @param event the app event
   */
  protected void fireEvent(AppEvent event) {
    Controller c = controller;
    while (c != null) {
      if (c.canHandle(event)) {
        c.handleEvent(event);
      }
      c = c.parent;
    }
  }

So apparently, the view knows its controller only to be able to send events to it… In a correctly designed system, the view should allow the controller to register itself as an event listener, thus eliminating an unnecessary dependency. We can also notice that the knowledge that controllers have a parent, and that the event should be propagated to all ancestor controllers, is all built right there into the view… ouch.

But there’s more. The handleEvent() method in class Controller is public, making it possible for anyone to call it. The problem is that, as we can see above, the handleEvent() method should only be called if canHandle() is true. Making handleEvent() a public method allows anyone to bypass this rule.

We find a different flavour of the same design flaw in method Controller.forwardToView():

  /**
   * Forward an event to a view. Ensures the view is initialized before
   * forwarding the event.
   *
   * @param view the view to forward the event
   * @param event the event to be forwarded
   */
  public static void forwardToView(View view, AppEvent event) {
    if (!view.initialized) {
      view.initialize();
      view.initialized = true;
    }
    view.handleEvent(event);
  }

Here, we can see that the method View.initialize() must be called once before the first call to handleEvent(). But this is enforced only here, so it’s easy to call View.handleEvent() directly and break this rule. If handleEvent() depends on something that is done in initialize(), you can imagine what can happen. You could also call initialize() and not set initialized to true, then it would be called again the next time…

You will also notice that the existence of the Controller.forwardToView() method implies that the controller can forward events to a view. This is clearly not appropriate because what the controller really does is send orders to the view. And since the controller must know its view, it’s best to simply call a method of the view when it needs to alter it.

Of course you could send orders disguised as events, but it has two major drawbacks:

  • it complicates the control flow and makes it very hard to understand
  • it prevents static code analysis and refactoring that is offered by modern IDEs.

In addition, for some reason Ext-GWT event types are not defined as Java enum members, but mere integers. This makes it very difficult to identify an event from just its code, for example when stepping through code.

Bottom line: don’t use Ext-GWT’s MVC

Ext-GWT has a lot of nice things to offer, but clearly its MVC implementation is not one of them. More could be said about it, but I think you get the picture: don’t use it. Write your own clean MVC implementation from scratch, you’ll save yourself a lot of trouble.


9 thoughts on “Why Ext-GWT MVC is broken

  1. Good writeup, our experience with GXT MVC was similar. We gave it a try for no reason other than, else all being equal, I’m game for favoring a framework’s conventions when it makes everything else play nicer. However, because of inherent problems you describe we’ve ended up using just their Dispatcher and AppEvent and rolling the rest ourselves.

  2. Dustin Mallory :

    rolling the rest ourselves.

    That’s what we should have done really, but when I joined the project they already had a homebrew framework using GXT’s MVC classes. So we’re using it, but trying to be “clean” and avoid the pitfalls (now that we know them…)

  3. Would be interesting to see a blog entry on how a better MVC implementation would look like.

  4. Pingback: GWT libraries
  5. For an additional point of view on Ext-GWT’s design choices, you may read this post: http://extjs.com/forum/showthread.php?p=192504#post192504
    Although it was written about Ext-GWT 1.0RC, it still applies to Ext-GWT 1.2.4! Obviously Ext-GWT’s developpers don’t care much.

    Impression confirmed after I had a look at the recently released Ext-GWT 2.0RC, where not a bit has changed in the MVC model. The view is still responsible for feeding events to controllers, initialize() is still as badly managed, etc.

Leave a Reply

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