Showing posts with label mvp. Show all posts
Showing posts with label mvp. Show all posts

Thursday, July 22, 2010

Converting to the MVP architecture

If you see one thing referenced again and again in writings about GWT development, it's Ray Ryan's Google IO 2009 talk on GWT Architecture Best Practices. In the talk he describes using the MVP architecture to develop GWT applications that allow easier unit testing and clean logic separation. There's also a couple of articles about large scale application development and MVP also at Google Code. And there's a million other things you can read with a quick search.

I've used the MVC architecture for other projects, and it's treated me pretty well, but you can still end up with some code that's difficult to follow from beginning to end. This is generally because of the View cutting the Controller out of the loop in going to the Model. MVP looks like it could help resolve that, so I wanted to give it a shot while learning GWT.

Finding a framework


I also didn't want to do all of the work involved in developing my own framework to support MVP, so after looking around to see what open source projects are available, I came across gwt-presenter. Several blogs and examples talk about this framework, and early on I had decided that I'd use it for this project. But now that I'm at the stage where I want to implement it, I looked a little closer.

It doesn't seem to be in active development. The last release was in August 2009, and GWT 2.0 was not yet released. There are two branches, and the GAE/GWT development blog talks about using the "replace" branch, but I'm not sure what stage it's at.

Though this may be due to my own prejudices, I preferred something that's currently being hacked, and I found that in mvp4g. It also looks to have some more features without being bogged down, have some more complete documentation, uses JUnit with pretty high coverage, and a discussion group where the developer regularly responds to questions. So I'm giving it a shot, at least the 1.2.0 snapshot (found in the examples zip), since it supports Gin.

Moving to mvp4g


The code for this stage is available under the "add-mvp4g" tag on github, or in a zip download.

I'm going to convert the login page that we currently have working (well, working is probably a bit too strong) to using this framework. The mvp4g FAQ has some good, quick explanations of their architecture, including a class diagram that I didn't find terribly useful until I got into implementing it.

The first step, as usual, is to include the jar in your classpath, as well as commons-lang and commons-configuration. We also need to inherit it in our .gwt.xml module file.

com/lisedex/volinfoman/Volinfoman.gwt.xml
<!-- Mvp4g configuration -->
       <inherits name='com.mvp4g.Mvp4gModule'/>

We fire it up in our entry point class.

com/lisedex/volinfoman/client/Volinfoman.java
// code to initialize mvp4g, which handles setting up our
      // Ginjection
      Mvp4gModule module = (Mvp4gModule)GWT.create( Mvp4gModule.class );
      module.createAndStartModule();
      RootPanel.get().add( (Widget)module.getStartView() );

If you prefer to use a layout panel for your application, the last line can use RootLayoutPanel instead of the RootPanel.

Event bus


Most of the initial configuration is done through annotations in our event bus class, so we'll set that up next; apparently you can also set mvp4g up through an XML file, but I didn't play with that.

com/lisedex/volinfoman/client/VolinfomanEventBus.java
@Events(startView = LoginView.class, historyOnStart = true,
        ginModule=VolinfomanModule.class)
@Debug( logLevel = LogLevel.DETAILED, logger = 
        Mvp4gLoggerToGwtLogAdapter.class )
public interface VolinfomanEventBus extends EventBus {
        @Event(handlers = LoginPresenter.class)
        public void login();
}

The @Events annotation declares what View our application will start in, whether it will parse any history information embedded in the URL that starts the application (we currently don't use this, but I have it enabled anyways), and what Gin module, if any, we want it to use to configure a Ginjector. Previously we defined the Ginjector in the onModuleLoad2() method in our entry point, but for mvp4g we pull it out and let the framework handle it.

I also turn on debugging using the @Debug annotation, and set the logger to one that I wrote that forwards mvp4g's logging calls to gwt-log instead of GWT.log. I wanted all of the logging in one place. It's a very simple class, so I'm going to skip it here.

Finally, we declare an interface that extends EventBus which defines all of the events that can be raised on the bus. The events should not return anything, and can have either one or zero parameters. We don't need a parameter for the login event, since the presenter that handles it will have access to the fields the user has filled out. The @Event annotation declares which classes, separated by a comma, are registered to be notified of the event.

Presenter


com/lisedex/volinfoman/client/LoginPresenter.java
@Presenter(view = LoginView.class)
public class LoginPresenter extends BasePresenter
        <LoginPresenter.LoginViewInterface, VolinfomanEventBus> {

The Presenter will be matched with a View, so we declare that association through the @Presenter annotation, which also lets the mvp4g compiler know that this class defines a Presenter. Our presenter extends BasePresenter, which is a generic that takes the class defining our View interactions (LoginViewInterface), and our Event Bus class (VolinfomanEventBus) as parameters.

The Presenter class handles the logic that will make the interface displayed to the user actually do something. In this case, we're working with a login page, so we need to define what we need for interactions with the View. I followed the mvp4g documentation, which defines it using an inner interface. I don't see why you couldn't break it out to a separate file, but it's a bit more clear having it bound to the Presenter class. Plus it's right there to reference when writing your Presenter.

public interface LoginViewInterface {
  public String getUsername();
  public String getPassword();
  public void setMessage(String msg);
  public HasClickHandlers getLoginButton();
  public void setLoginButtonEnabled(boolean enabled);
 }

We need a few things from the user, and we don't really care how the View gets them. All we care about is that it can provide the information we need to process the login. In this case, we want to be able to get the username and password they've entered, and we also want to be able to send them messages, in case of an error. We also need to find out when the user's told the interface they've completed their data entry, so we want to bind to something that throws Click events; we don't really care if it's a button or not. I also need to be able to control whether the user can request to log in; for instance, if they've just clicked, until the server responds, I don't want them to be able to keep clicking. If the View is not implementing a button, they can use this information in whatever way makes sense. In fact, writing this, it really shouldn't be called setLoginButtonEnabled, but something like setLoginEnabled instead.

The Presenter is going to perform the logic we had in our previous DefaultHomepage class, so we need our UserService.

private UserServiceAsync userService = null;

 @InjectService
 public void setService(UserServiceAsync service) {
  this.userService = service;
 }

mvp4g supports injecting these services (both RPC and non-RPC) with the @InjectService annotation. You define them as you normally would, with both Service and the ServiceAsync version. I didn't have to change the code at all.

The bind() method is called by the framework for us to do further set up of our interactions with the View. The BasePresenter we're extending provides both view and eventBus references so we don't need to handle that.

@Override
 public void bind() {
  super.bind();
  view.getLoginButton().addClickHandler(new ClickHandler() {
   public void onClick(ClickEvent event) {
    view.setLoginButtonEnabled(false);
    eventBus.login();
   }
  });
 }

All I want right now is to know when the login button (or whatever the View is using) is clicked, and when it is, I turn off the login button and fire a login event onto the Event Bus. This will allow some flexibility later, if I need to have another class know about logins.

Finally we define the method to handle the login event. All events are handled by methods that start with "on" followed by the event name. In this case, it will be onLogin.

public void onLogin() {
 if (userService == null) {
  Log.fatal("userService is null, not injected", 
    new NullPointerException("LoginPresenter.userService"));
  view.setMessage("Fatal application error.  \"userService not injected.\"");
  view.setLoginButtonEnabled(true);
  return;
 }
  
 userService.getUser(view.getUsername(), new AsyncCallback<User>() {
  @Override
  public void onFailure(Throwable caught) {
   view.setMessage("RPC FAILED");
   view.setLoginButtonEnabled(true);
  }

  @Override
  public void onSuccess(User result) {
   if (result == null) {
    view.setMessage("NO SUCH USER");
   } else {
    view.setMessage("SUCCESS: " + result.toString());
   }
   view.setLoginButtonEnabled(true);
  }
 });
}

This is pretty much the click handler that was in DefaultHomepage. We first do a quick sanity check for our UserService, and if it's not there, there's something really wrong. Then we call our service's getUser method, and when it returns we either tell the user the user doesn't exist, or spit out the user's information. Then we turn the login button back on.

View


The View just sets up visual aspect of the interface the user sees. In this case, we're still using a UiBinder, copied from the DefaultHomepage, and then adding the methods to flesh out the View interface we built in the Presenter.

com/lisedex/volinfoman/client/LoginView.java
public class LoginView extends Composite 
 implements LoginPresenter.LoginViewInterface {

 private static LoginViewUiBinder uiBinder = GWT
  .create(LoginViewUiBinder.class);

 interface LoginViewUiBinder extends UiBinder<Widget, LoginView> {
 }

The View is going to be a Composite widget, and it will implement the View interface. We also bind the View with its associated LoginView.ui.xml file, so we can use the fields declared there to provide information to the Presenter.

@UiField
 TextBox username;
 
 @UiField
 TextBox password;
 
 @UiField
 Button sendButton;
 
 @UiField
 HTML sendStatus;
 
 public LoginView() {
  initWidget(uiBinder.createAndBindUi(this));
  
  sendButton.setText("Login");
  
  sendStatus.setStyleName("serverResponseLabelError");
  
  DeferredCommand.addCommand(new Command() {
   public void execute() {
    username.setFocus(true);
   }
  });
  username.selectAll();
 }

This code is basically the same as what was in DefaultHomepage. We bind the XML defined user interface, then we set the text for our login button. We also set the style for the place we'll send messages to the user, so text shows up red, and then we set the focus on the username field. Setting focus did not work in previous versions of our code, so after a quick search I found this workaround described in GWT issue 1849, where they discuss making this the default implementation of setFocus().

The rest of the class is just implementing the LoginViewInterface.

@Override
 public String getUsername() {
  return username.getText();
 }

 @Override
 public String getPassword() {
  return password.getText();
 }

        .... etc, etc.

They're all just basic getters and setters, so I won't include them here, but you can take a peek at the complete code if you want to see the whole thing.

Some notes


I like the way mvp4g seems to work, and reading past posts on its discussion group was useful in figuring some of it out. There's other functionality I haven't even touched yet: code-splitting through using different modules for different parts of the interface, lazy loading, and, most importantly, history. I'll be adding history as soon as I have a second page or something where history makes sense. The others seem to be optimizations which we don't need yet.

I also may want to implement the command pattern later, to have more complete bits of information passed with their event on the event bus.

I've been avoiding it long enough, but now it's time to figure out a good authentication/session design, since I don't want to require the volunteers using this to have a Google account. If I did, it would pretty much be implemented for me in the App Engine Users API.

Sunday, July 18, 2010

Dependency injection and Gin

I was coming across the phrase "dependency injection" quite a bit while reading articles about GWT and MVP, and references to the Guice and Gin libraries coming out of Google. I figured it was some new programming paradigm and that I was hopelessly out of date not knowing what it was. The wikipedia entry didn't really help clear it up, nor did other articles I read. I kept getting the feeling that I was missing something, and that the concept wasn't really something new.

Turns out I was missing something, all right


I was missing that DI is giving a name to something that I and every other object oriented developer have been doing for years.

The short summary in this great article is what finally made me realize that I could stop trying to make it more complicated than it was: "Dependency injection means giving an object its instance variables. Really. That's it." If you're having trouble with the concept, James Shore's article is invaluable.

A conceptual example would be something like: you have an object that relies on a reference to some sort of data provider. In production, the provider will be a database back end, but during testing you want to mock up a provider that is always up and you can precisely control what errors it has.

You might solve this by constructing a factory that spits out the correct type of provider, and your object can ask that factory to give it a reference to the proper kind of provider. This works, but your testing has to construct, tear down, and reset the factory to the previous state between each test. You also have to write a lot of boilerplate code for each of these factories.

DI refers to giving the object a reference to the proper provider, which, during testing, allows you to build a new provider instance which you pass to the object during each test. As you exit the test, the object and provider are dereferenced automatically, saving you the cleanup. But in the code itself, you're now either passing provider references possibly through layer after layer of constructors, or you're building factories for the initial object which get the proper provider and pass it to the object, and then return the completed object.

Guice and Gin save you from all this repetitive factory building and wiring, and what provider each object needs can be declared in one place, or inline where the instantiated providers will be injected in the object.

I'm certainly not qualified at this time to discuss all of the nuances and capabilities of these libraries, since there are many different ways this concept could be used.

Instead, I'll talk about using Gin in this project


com/lisedex/volinfoman/Volinfoman.gwt.xml
<!-- Include Gin -->
<inherits name="com.google.gwt.inject.Inject" />
Adding those lines to your module's gwt.xml file, and adding the Gin and Guice jar files to your classpath, is all that it takes to enable the Gin annotations and compile time code generation.

If you go to the VolInfoMan project page on github, you can go to the basic-gin tag and download the source. The project is very, very basic at this point, and it's easy to find the one instance of using Gin.

As practice, I wanted to set up the home page you land on when loading the site to be capable of being changed by dependency injection. This will allow, later, changing the implementation of the page by making a new class that extends the skeleton Homepage class, and just changing the Gin binding in one place, and all references to that Homepage will be using my new implementation. Look ma, no factory!

com/lisedex/volinfoman/client/Homepage.java
package com.lisedex.volinfoman.client;

import com.google.gwt.user.client.ui.Composite;

public class Homepage extends Composite {
}

First we define our skeleton Homepage class, which will be added to our RootPanel later in onModuleLoad() (actually onModuleLoad2() due to our use of the gwt-log library).

com/lisedex/volinfoman/client/gin/VolinfomanGinjector.java
package com.lisedex.volinfoman.client.gin;

import com.google.gwt.inject.client.GinModules;
import com.google.gwt.inject.client.Ginjector;
import com.lisedex.volinfoman.client.Homepage;

@GinModules(VolinfomanModule.class)
public interface VolinfomanGinjector extends Ginjector {
 Homepage getHomepage();
}

We extend the com.google.gwt.inject.client.Ginjector class and use the @GinModules annotation to specify what class contains the binding configuration. We also define the getHomepage() injector method, which we need when using Gin in our application initialization code, because Gin is working at compile time to generate JavaScript, unlike Guice. Other dependencies that operate below our initialization code will be injected automatically, and won't require this type of method.

com/lisedex/volinfoman/client/gin/VolinfomanModule.java
package com.lisedex.volinfoman.client.gin;

import com.google.gwt.inject.client.AbstractGinModule;
import com.lisedex.volinfoman.client.DefaultHomepage;
import com.lisedex.volinfoman.client.Homepage;

public class VolinfomanModule extends AbstractGinModule {
        @Override
        protected void configure() {
                bind(Homepage.class).to(DefaultHomepage.class);
        }
}

We extend AbstractGinModule to declare our bindings for injection. Using AbstractGinModule instead of GinModule allows us to drop the binder.bind() syntax in favor of bind(). In the above code, we're declaring that when our code asks for a Homepage object, it will get a DefaultHomepage instead.

com.lisedex.volinfoman.client.DefaultHomepage actually contains no references to Gin. It extends Homepage but doesn't need to know anything about injection.

com/lisedex/volinfoman/client/Volinfoman.java
package com.lisedex.volinfoman.client;

import com.lisedex.volinfoman.client.gin.VolinfomanGinjector;
// import GWT objects here...

public class Volinfoman implements EntryPoint {
        public void onModuleLoad() {
                // we set up gwt-log here and
                // use a DeferredCommand to execute
                // onModuleLoad2() */
                // ...
        }

        private void onModuleLoad2() {
                // Create a ginjector
                VolinfomanGinjector ginjector = 
                    GWT.create(VolinfomanGinjector.class);
                // Add the homepage to the rootpanel
                RootPanel.get().add(ginjector.getHomepage());
        }
}

And our GWT entry point creates the Ginjector, and we use the injector method getHomepage() to inject an instance of DefaultHomepage, thanks to the binding we set up in VolinfomanModule. As mentioned above, we have to use an injector method due to current limitations in Gin.

That's it. Remember to grab the basic-gin tag of the source code from github for a compile-ready Eclipse project where you can immediately play with Gin.

Other Gin information


Gin supports some of the same annotations as Guice, such as @Inject, @ProvidedBy, @Singleton, @ImplementedBy, all of which allow you to move much of the binding information out to the source where the bindings occur. Much of this is to provide an alternative to using a GinModule to declare all of the bindings in one place; the latter is the option I prefer, but it's personal preference for the most part.

Some of the other bind() syntaxes are:
bind(Something.class).toProvider(SomethingProvider.class);
bind(Something.class).to(SomethingImplementation.class)
    .in(Elsewhere.class);
bind(Something.class).annotatedWith(SomethingAnnotation.class);
    .to(SomethingImplementation.class);
bind(Something.class).to(SomethingImplementation.class)
    .in(Singleton.class);

Line 1: When Gin injects an instance of a class normally, it uses the class's default constructor. If you need to give extra information to a constructor, you can use the toProvider() syntax. Gin will inject an instance of Something from the SomethingProvider wherever you need a Something class.

Line 2: If you only want a binding to apply in Elsewhere, instead of globally, you can use this syntax to specify that scope.

Line 4: You can also set up custom annotations. When you want multiple bindings for one type, you can specify which binding to use by setting up an annotation for each. The annotation and the type will uniquely identify which binding is appropriate. See the Guice wiki for more information.

Line 6: Gin's injector normally creates a new instance of each SomethingImplementation when it gets injected. However, sometimes you'll want to use the Singleton pattern, and only have one instance of SomethingImplementation running around. Remember that this is a Singleton per Ginjector, so if you have multiple Ginjectors (which, if you do, you probably need to double check your code) there will be one instance of the SomethingImplementation for each.

There's a bunch more that can be done with Gin; this is obviously only scratching the surface. Remember that Gin does the injection at compile-time, so there should be almost no overhead for using it, and it can save you a lot of repetitive coding. To understand all of the capabilities, it would behoove you to read the Guice User's Guide, the Gin tutorial, and the compatibility information between Gin and Guice. The documentation for Guice is much more thorough, but you have to know which ideas can be used in your GWT code. Guice will be used later for our server side code which runs under GAE.

Monday, July 12, 2010

More research...by watching YouTube videos

I'm itching to start hacking code, and I probably will this evening, but I forced myself to spend a good bit of time yesterday doing research: I read articles at the Google App Engine site, GWT tutorials, and best practices for both GAE and GWT. Generally, what I got from those is how much I have to learn about these technologies, which is a little depressing. Also, that if I'm not really focused, I'm going to get sidetracked by reading about issues I'm not even facing yet. But the up side is that there's so much information out there, already available, that most of the problems I'll run in to someone else has already hit and written about it.

Google IO videos, or how I learned to stop multitasking and love YouTube


The Google IO talks, presented on the Google Developer's Channel on YouTube, were probably some of the most informative stuff I looked at yesterday, as well as exemplifying my tendency to get sidetracked; do I really need to watch an hour and a half of the Google Wave product launch? I'm not even going to provide a link to that. It also served to remind me that sometimes trying to multitask is inefficient, as when I'd put the videos in the corner of my screen and try to do other work, I'd completely miss huge chunks of the talk. Having to continuously rewind, and, while the video was getting back to the section I missed, going back to my regular work, only to completely miss the same section again...well, it started to border on the absurd. Biting the bullet, and telling myself that just watching the video with no distractions was actually most the efficient way to get this done, was also the way to get the most out of these videos. And there's a ton of good information there.

Max Ross easily rose to the top as one of my favorite speakers. During his videos, I would actually neglect my work and focus completely on the video. The first talk of his I watched was an explanation of schemas in the data store, since I'm not going to have complete SQL functionality while writing an application for the GAE. I also listened to his (audio only) talk about Hibernate Shards, even though I won't be needing that, most likely ever, for this particular project. Speaking to Max's skill as a speaker, my girlfriend, who actively tries not to learn about computers almost to the point of Luddism, got sucked in while I was listening. I believe that, initially, it was her mishearing the word "sharding" as "sharting," and that hooked her scatalogical mind. But she ended up putting down her book, and listening with me. By the end, she actually asked me questions that showed she grasped a lot of what Max was talking about. She's a smart girl, but I was pretty surprised.

Testing


I'm a big proponent of proper testing when I'm developing software, and though I occasionally get some push back for that, it really helps my confidence in code as a project progresses. So it was nice to hear from Max that he really believes in testing, too, during his talk about GAE Testing Techniques. Using the cloud as a test farm is pretty ingenious, so I wastedspent some time looking at Cloud Cover test harness. The code hasn't been touched since May, but I really like the idea of testing my GAE code actually on the App Engine servers. This led to GWT testing, which reinforces the idea that the MVP model will promote not just a clean conceptual layout for the project or make it easier to implement code splitting, but will also make it much easier to have GWT test cases that will run very fast, except for the small percentage that need to test the GUI widgets themselves. This talk also pointed me to WebDriver, which is the heir apparent to Selenium. The fact that Selenium ran the testing through JavaScript always seemed a bit too abstracted from the browser itself to provide true test from the user all the way to the data store. WebDriver will plug directly in to the browser and generate actual key strokes, button clicks, and other events.

Odds and ends


I also watched a talk about some of the new stuff in Google App Engine (at least new since the 2009 Google IO conference), developing complex and scalable apps in GAE, and new query capabilities that have been added to the data store.

And I believe watching all of that in one day kind of made me a bit loopy, and I know that a lot of the specifics ended up getting pushed out by new specifics; but now I have a better idea of what's out there, so when I do run into an issue or question, I know where to look. This post is actually more for me, so I have a place to refer with all of these links. I also have a good idea of how to implement my testing, and how the project should be designed initially.

It was actually time well spent, even though I had to suppress my urge to just start coding, and I'm now in a better position to start without having to feel like I'm going to have to revisit, in the near future, every single decision I make.

And I need to get over my mancrush on Max Ross. He's so dreamy.