Jörg Viola
Internet und Mobile Software- und Business-Development.
20.05.2012
16.03.2012
Play 2.0 released - first impressions from the 1.2 perspective
Play 2.0 is here! What does this mean for the Joe Average Play 1 developer?
After the download from http://download.playframework.org/releases/play-2.0.zip is installed as usually, I rename the /play script to /play20 to ensure using the right version.
Projects done with release candidates of Play 2.0 have to be upgraded by changing the last line of /project/plugins.sbt:
EDIT: This went into the play 2.0 wiki: https://github.com/playframework/Play20/wiki/Play-2.0-for-Play-1.x-developers
After the download from http://download.playframework.org/releases/play-2.0.zip is installed as usually, I rename the /play script to /play20 to ensure using the right version.
Projects done with release candidates of Play 2.0 have to be upgraded by changing the last line of /project/plugins.sbt:
addSbtPlugin("play" % "sbt-plugin" % "2.0")Below you find a number of snippets you may find helpful:
- Iterate over collection
- Play1: #{list items:collection, as:'var' } ...$var... #{/list}
- Play2: @for(var <- collection) { ... @var ... }
- Insert relative URL in template:
- Play1: @{controller.method}
- Play2: @routes.Controller.method()
- Insert absolute URL in template:
- Play1: @@{controller.method}
- Play2: http://@request.headers().get("HOST")@routes.Controller.method()
- URL to file in public:
- Play1: @{'/public/images/logo_16x16.png'}
- Play2: @routes.Assets.at("images/logo_16x16.png")
EDIT: This went into the play 2.0 wiki: https://github.com/playframework/Play20/wiki/Play-2.0-for-Play-1.x-developers
15.02.2012
Play 2.0 RC1 is released
The first release candidate for Play 2.0 has been released yesterday! Download it here: http://download.playframework.org/releases/play-2.0-RC1.zip
Documentation can be found here: https://github.com/playframework/Play20/wiki.
First simple load tests using apache ab showed promising results: 4.000 simple "hello world" requests per second (or 7000 with http keep-alive) on an iCore 7 QC, 8GB notebook - comparable to node.js.
Time to Play!
Documentation can be found here: https://github.com/playframework/Play20/wiki.
First simple load tests using apache ab showed promising results: 4.000 simple "hello world" requests per second (or 7000 with http keep-alive) on an iCore 7 QC, 8GB notebook - comparable to node.js.
Time to Play!
13.01.2012
Play! 2.0 and Eclipse: Current Status
Play 2.0 recently made awesome progress especially for Eclipse users. Creating projects and working from within the IDE now is nearly as simple as in the 1.x releases:
For building Play 2.0 I followed this recipe (beware - bleeding edge ;-)
$ git clone git://github.com/playframework/Play20.git
$ cd Play20/framework
$ ./build publish-local
$ PATH=$PATH:Play20
In an Eclipse Workspace:
$ play new test20
$ cd test20
$ play eclipsify
$ play ~run
In Eclipse:
For building Play 2.0 I followed this recipe (beware - bleeding edge ;-)
$ git clone git://github.com/playframework/Play20.git
$ cd Play20/framework
$ ./build publish-local
$ PATH=$PATH:Play20
In an Eclipse Workspace:
$ play new test20
$ cd test20
$ play eclipsify
$ play ~run
In Eclipse:
- Preferences/General/Workspace: Enable "Refresh using native hooks or polling"
- File/Import.../General/Existing projects into workspace...
11.11.2011
Play - Real live experiences
The Play! framework is one of the upcoming stars in the sky of web frameworks. Featuring stateless "share nothing", asynchronous IO and especially blazingly fast turnarounds, it seems to combine two of my dream features: High productivity and trustworthy scalability. Time to test it in a real live project.
Our project
www.waduno.de - short for "what you know" - is a german-speaking website for proving IT and business skills. By mastering several tests, you get scores and can publish them on social networks, your own website or in your resume. In the long run, we enable candidates to enrich their resumes which trustworthy quantitative skill information.
We started waduno by closely following the lean startup methods. In order to provide the high-speed iterations required for a fast validated learning cycle, we needed a highly productive web framework. Ruby on Rails was a natural first choice. But since we are more familiar with the Java world, we looked around and fell in love with Play!
Though it is of course a risk to try a brand new technology for a serious project, our first tests were so promising, we couldn't resist. Just open your browser on your newly created application, change whatever you like, templates, code or configuration, reload - and there you are. It is hard to describe the boost of freedom in development you get from this feature - you have to try!
Basics
The MVP model looks familiar if you accept static methods as manifestations of the stateless architecture. The Play! people did such a good job in simplifying standard tasks. Let's as an example look at the code to save a business object, which is itself of course represented as a Model class:
Here you can see:
Isn't that extremely simple to understand?
Our experiences
It really was fun to develop with Play! We needed one man-month to come up with a first MVP-iteration (and we mostly worked on the graphical design ;-). Variations of flow, output or business logic could be implemented very fast.
We even saw developers and product managers sitting side by side in front of a monitor, trying features and developing in real time! This way not only productivity is boosted, but the whole team gets a much better understanding of product features and technical possibilities.
Our project
www.waduno.de - short for "what you know" - is a german-speaking website for proving IT and business skills. By mastering several tests, you get scores and can publish them on social networks, your own website or in your resume. In the long run, we enable candidates to enrich their resumes which trustworthy quantitative skill information.
We started waduno by closely following the lean startup methods. In order to provide the high-speed iterations required for a fast validated learning cycle, we needed a highly productive web framework. Ruby on Rails was a natural first choice. But since we are more familiar with the Java world, we looked around and fell in love with Play!
Though it is of course a risk to try a brand new technology for a serious project, our first tests were so promising, we couldn't resist. Just open your browser on your newly created application, change whatever you like, templates, code or configuration, reload - and there you are. It is hard to describe the boost of freedom in development you get from this feature - you have to try!
Basics
The MVP model looks familiar if you accept static methods as manifestations of the stateless architecture. The Play! people did such a good job in simplifying standard tasks. Let's as an example look at the code to save a business object, which is itself of course represented as a Model class:
package models; import javax.persistence.Entity; import play.db.jpa.Model; @Entity public class Person extends Model { public Date created; @Required @Email @Column(unique = true) public String email; @Required public String password; @Required @Column(unique = true) public String name; public int score; @ManyToOne public Company company; public static Person findByMailDomain(String domain) { return Person.find("email like ?", "@"+domain).fetch(); } public void upgrade(String msg) { score++; Event.log(this, msg); this.save(); } }From that simple example, you can observe several key aspects of Play! models:
- Persistence is done with JPA
- The Model base class provides ID handling
- Several validation annotations are available
- No anemic models: You find the business code in the model, not in services.
- Querying is simple using find()-methods
- the dirty state model is inverted when compared to hibernate et. al.: Objects are only save after an explicit call to save()
#{extends 'main.html' /} #{set title:'waduno - New Quiz!' /} #{form @UserAdmin.save()} <input type="hidden" name="person.id" value="${person?.id}"/> <div class="region"> Name:<br> <input type="text" class="big #{errorClass 'person.name'/}" name="person.name" id="title" value="${person?.name}"/> <br> <!-- lots of other fields --> </div> #{/form}
Here you can see:
- Play has templates, Groovy based, that can be extended (main.html in this case) and parameterized
- It can construct URLs for server methods for you (@UserAdmin.save())
- Simple error handling, e.g. by #{errorClass ...}
public static void saveQuestion(@Valid Person person) { if (validation.hasErrors()) renderTemplate("@edit", person); person.save(); show(person.id); } public static void show(Long id) { Person person = Person.findById(if); render(person); }
Isn't that extremely simple to understand?
- Play! takes the person.id request Parameter and loads the Person from the database
- It applies the remaining request parameter to the object
- ... validates the object
- ... and the passes it to the controller method
- The method the shows the form again if validation failed
- ... or saves the updated object
- ... and the applies Post-Redirect-Get. Yes, by simply calling another controller method show().
Our experiences
It really was fun to develop with Play! We needed one man-month to come up with a first MVP-iteration (and we mostly worked on the graphical design ;-). Variations of flow, output or business logic could be implemented very fast.
We even saw developers and product managers sitting side by side in front of a monitor, trying features and developing in real time! This way not only productivity is boosted, but the whole team gets a much better understanding of product features and technical possibilities.
20.07.2011
GWT: UiBuilder Internationalisation the simple way
UiBinder, the tool for declarative UIs for GWT, can of course be internationalised. The procedure is explained in the GWT docs. But this approach looks a little bit too complex to me, especially because I already have a simple I18N interface for my App. I would like to use that one and have only one place to add translations to.
GWT provides us with a very simple way of doing I18N. Simply create an interface like that one:
The recipe for I18N of UiBuilder templates describe a procedure where the property files above can be generated from annotated templates. Cool, but you know, I do not want two different techniques and qould like to re-use the simple Text interface from above.
And of course this is simple. As explained here, import the interface as an external resource and simply use it:
GWT I18N, recalled
GWT provides us with a very simple way of doing I18N. Simply create an interface like that one:
public interface Text extends Messages { public static final Text LANG = GWT.create(Text.class); String create(); String save(); String delete(); }In the same folder, put a properties file called Text.properties:
create=Create save=Save delete=Deleteand for your german user, for example, add another text file Text_de_DE.properties:
create=Neu save=Speichern delete=LöschenIn order to set the correct locale from the users request, I usually convert from index.html to index.jsp (do not forget to change your welcome file in web.xml, too) and add:
<meta name="gwt:property" content="locale=<%= request.getLocale() %>">Finally, add this to your Module.gwt.xml:
<inherits name="com.google.gwt.i18n.I18N"/> <extend-property name="locale" values="en"/> <extend-property name="locale" values="de_DE"/> <set-property-fallback name="locale" value="en"/>Now, instead of writing string literals in your app code, use this interface:
Button save = new Button(Text.LANG.save());
Now, what about UiBuilder?
The recipe for I18N of UiBuilder templates describe a procedure where the property files above can be generated from annotated templates. Cool, but you know, I do not want two different techniques and qould like to re-use the simple Text interface from above.
And of course this is simple. As explained here, import the interface as an external resource and simply use it:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:t="urn:import:de.joergviola.tripmark.client.util"> <ui:with field='i18n' type='de.joergviola.tripmark.client.i18n.Text'/> <g:HorizontalPanel spacing="3"> <g:Anchor text="{i18n.save}" ui:field="save"/> <g:Anchor text="{i18n.delete}" ui:field="delete"/> </g:HorizontalPanel> </ui:UiBinder>That's it - simple, eh?
06.07.2011
GWT MVP made simple
GWT Model-View-Presenter is a design pattern for large scale application development. Being derived from MVC, it divides between view and logic and helps to create well-structured, easily testable code. To help lazy developers like me, I investigate how to reduce the amount of classes and interfaces to write when using declarative UIs.
You know how to post a link in facebook? - Recently I had to create a this functionality for a little GWT travelling app.
So you can enter a URL, which is then fetched and parsed. You can select one of the images from the page, review the text and finally store the link.
Now how to properly set this up in MVP? - First, you create an abstract interface resembling the view:
The implementation is straightforward, shown here with declarated UI fields:
So here we are: Using MVP, you can structure your code very well and make it easily readable.
The payoff is: Three types for each screen or component. Three files to change whenever the UI is re-defined. Not counted the ui.xml file for the view declaration. For a lazy man like me, these are too many. And if you take a look at the view implementation, it is obvious how to simplify this:
Use the view declaration (*.ui.xml) as the view and inject ui elements directly into the presenter:
But now, you have it all in one class and one view.ui.xml-file and you can apply structural changes much simpler.
TextBox implements HasValue<String>. This is simple. But what about properties of ui elements that are not accessible through interfaces? An example you may already have recognized is the VerticalPanel named result in the above code and its method setVisible(), which unfortunately is implemented in the UiObject base class. So no interface is available that could eg. be implemented at test time. For the sake of being able to switch view implementations, it would be better to inject a ComplexPanel, but even that cannot be instantiated at test time.
The only way out in this case is to create a new Interface, say
Wait - how to use self-made components in UiBuilder templates? - That is simple:
The standard way of declaring (click-)handlers is very convinient:
So unfortunately one has to stick back to registering ClickHandlers manually (as one has to do in full MVP anyway):
GwtTestCase is able to execute tests in the container environment but requires some startup-time. In TDD, it is desirable to have very fast-running tests that can be applied after every single change without loosing context.
So MVP is designed to be able to test all your code in a standard JVM. In standard MVP, you create implementations of the view interfaces. In this simplified approach, it is sufficient to create implementations on a component interface level like the following:
What do you win?
You get code structered as clean as in full MVP with much less classes and boilerplate code.
Some situations require utility classes for components and their interfaces, but as time goes by, you build an environment which is really easy to understand, test and extend.
I'm curios: Tell me your experiences!
Classic MVP
You know how to post a link in facebook? - Recently I had to create a this functionality for a little GWT travelling app.
So you can enter a URL, which is then fetched and parsed. You can select one of the images from the page, review the text and finally store the link.
Now how to properly set this up in MVP? - First, you create an abstract interface resembling the view:
interface Display { HasValue<String> getUrl(); void showResult(); HasValue<String> getName(); HasClickHandlers getPrevImage(); HasClickHandlers getNextImage(); void setImageUrl(String url); HasHTML getText(); HasClickHandlers getSave(); }It makes use of interfaces GWT components implement that give some access to their state and functionality. During tests you can easily implement this interface without referring to GWT internals. Also, view implementation may be changed without influence on deeper logic.
The implementation is straightforward, shown here with declarated UI fields:
class LinkView implements Display @UiField TextBox url; @UiField Label name; @UiField VerticalPanel result; @UiField Anchor prevImage; @UiField Anchor nextImage; @UiField Image image; @UiField HTML text; @UiField Button save; public HasValue<String> getUrl() { return url; } public void showResult() { result.setVisible(true); } // ... and so on ... }The presenter then accesses the view using the interface, which by convention is written inside the presenter class:
class LinkPresenter interface Display {...}; public LinkPresenter(final Display display) { display.getUrl().addValueChangeHandler(new ValueChangeHandler<String>() { @Override public void onValueChange(ValueChangeEvent<String> event) { Page page = parseLink(display.getUrl().getValue()); display.getName().setValue(page.getTitle()); // ... display.showResult(); } }); } // ... and so on ... }
So here we are: Using MVP, you can structure your code very well and make it easily readable.
The simplification
The payoff is: Three types for each screen or component. Three files to change whenever the UI is re-defined. Not counted the ui.xml file for the view declaration. For a lazy man like me, these are too many. And if you take a look at the view implementation, it is obvious how to simplify this:
Use the view declaration (*.ui.xml) as the view and inject ui elements directly into the presenter:
class LinkPresenter @UiField HasValue<String> url; @UiField HasValue<String> name; @UiField VerticalPanel result; @UiField HasClickHandlers prevImage; @UiField HasClickHandlers nextImage; @UiField HasUrl image; @UiField HasHTML text; @UiField HasClickHandlers save; public LinkPresenter(final Display display) { url.addValueChangeHandler(new ValueChangeHandler<String>() { @Override public void onValueChange(ValueChangeEvent<String> event) { Page page = parseLink(url.getValue()); name.setValue(page.getTitle()); // ... result.setVisible(true); } }); } // ... and so on ... }Since it is possible to declare the injected elements using their interfaces this presenter has a lot of the advantages of the full-fledged MVP presenter: You can test it by setting implementing components (see below) and you can change the views implementation easily.
But now, you have it all in one class and one view.ui.xml-file and you can apply structural changes much simpler.
Making UI elements abstract
TextBox implements HasValue<String>. This is simple. But what about properties of ui elements that are not accessible through interfaces? An example you may already have recognized is the VerticalPanel named result in the above code and its method setVisible(), which unfortunately is implemented in the UiObject base class. So no interface is available that could eg. be implemented at test time. For the sake of being able to switch view implementations, it would be better to inject a ComplexPanel, but even that cannot be instantiated at test time.
The only way out in this case is to create a new Interface, say
interface Visible { void setVisible(boolean visible); boolean isVisible(); }and subclass interesting UI components, implementing the relevant interfaces:
package de.joergviola.gwt.tools; class VisibleVerticalPanel extends VerticalPanel implements Visible {}This seems to be tedious and sub-optimal. Nonetheless, is has to be done only per component and not per view as in the full-fledged MVP described above.
Wait - how to use self-made components in UiBuilder templates? - That is simple:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:t="urn:import:de.joergviola.gwt.tools"> <g:VerticalPanel width="100%"> <g:TextBox styleName="big" ui:field="url" width="90%"/> <t:VisibleVerticalPanel ui:field="result" visible="false" width="100%"> </t:VisibleVerticalPanel> </g:VerticalPanel> </ui:UiBinder>
Declaring handlers
The standard way of declaring (click-)handlers is very convinient:
@UiHandler("login") public void login(ClickEvent event) { srv.login(username.getValue(), password.getValue()); }In the simplified MVP approach, this code would reside in the presenter. But the ClickEvent parameter is a View component and can eg. not be instantiated at runtime. On the other hand, it cannot be eliminated from the signature because UiBuilder requires an Event parameter.
So unfortunately one has to stick back to registering ClickHandlers manually (as one has to do in full MVP anyway):
public initWidget() { ... login.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { login(); } }); ... } public void login(ClickEvent event) { srv.login(username.getValue(), password.getValue()); }
Testing
Making your app testable is one of the main goals when introducing MVP.GwtTestCase is able to execute tests in the container environment but requires some startup-time. In TDD, it is desirable to have very fast-running tests that can be applied after every single change without loosing context.
So MVP is designed to be able to test all your code in a standard JVM. In standard MVP, you create implementations of the view interfaces. In this simplified approach, it is sufficient to create implementations on a component interface level like the following:
class Value<T> implements HasValue<T> { private T value; List<ValueChangeHandler<T>> handlers = new ArrayList<ValueChangeHandler<T>>(); @Override public HandlerRegistration addValueChangeHandler( ValueChangeHandler<T> handler) { handlers.add(handler); return null; } @Override public void fireEvent(GwtEvent<?> event) { for (ValueChangeHandler<T> handler : handlers) { handler.onValueChange((ValueChangeEvent) event); } } @Override public T getValue() { return value; } @Override public void setValue(T value) { this.value = value; } @Override public void setValue(T value, boolean fireEvents) { if (fireEvents) ValueChangeEvent.fire(this, value); setValue(value); } }As usual, you have to inject this component into the presenter-under-test. Though in principle, you could create a setter for the component, I stick to the usual trick to make the component package-protected, put the test into the same package (but of course different project folder) as the presenter and set the component directly.
What do you win?
You get code structered as clean as in full MVP with much less classes and boilerplate code.
Some situations require utility classes for components and their interfaces, but as time goes by, you build an environment which is really easy to understand, test and extend.
I'm curios: Tell me your experiences!
Abonnieren
Posts (Atom)