Google Web Toolkit0-60 in no time flat
Chris RamsdaleDeveloper Relations, Google
Agenda
• Overview
• Deeper dive
• Optimizations for developers
• Optimizations for users
• Intro to GWT & MVP
From 25,000 feet
• Development toolkit, not a framework
• Code in Java, run as Javascript
• One codebase, any browser
• Makes Ajax a piece of cake...and faster
• Used within many Google products, including Google Wave and Ad Words
The GWT Family
GWT SDK Google PluginFor Eclipse
Speed Tracer
It’s a loving relationship
It’s a loving relationship
Develop
It’s a loving relationship
Develop Debug
It’s a loving relationship
Develop Debug
Optimize
Focus on the users
Our users - developers• Leverage existing IDEs and tools
• Minimize refresh time between codes changes
• Automate where possible
Your users - customers
• Minimize startup time
• Make it a comfortable experience
• Allow them to select the browser
Different Goals
Different Goals
Developers• Next killer feature
• Making it look good
• Code refactoring
Different Goals
Developers• Next killer feature
• Making it look good
• Code refactoring
Customers• Make it fast
• ...oh, and don’t charge my credit card twice
Different Goals
Developers• Next killer feature
• Making it look good
• Code refactoring
Customers• Make it fast
• ...oh, and don’t charge my credit card twice
No plugins required
VML Flash
Silverlight
Nothing against them, but...
Foo Player not available for your device
We restrict use of technologies required by products like Foo Player...
Quirkiness
14800 ms4836 ms1997 ms7148 msDOM manipulation
2469 ms1520 ms918 ms2477 msinnerText=...
-1386 ms908 ms-textContent=...
4078 ms2053 ms1276 ms2876 msTypical portable setInnerText()
IEOperaWebkit (Safari)Firefox
Quirkiness
14800 ms4836 ms1997 ms7148 msDOM manipulation
2469 ms1520 ms918 ms2477 msinnerText=...
-1386 ms908 ms-textContent=...
4078 ms2053 ms1276 ms2876 msTypical portable setInnerText()
IEOperaWebkit (Safari)Firefox
Improvement 39%32%29%14%
Quirkiness
14800 ms4836 ms1997 ms7148 msDOM manipulation
2469 ms1520 ms918 ms2477 msinnerText=...
-1386 ms908 ms-textContent=...
4078 ms2053 ms1276 ms2876 msTypical portable setInnerText()
IEOperaWebkit (Safari)Firefox
Improvement 39%32%29%14%
http://quirksmode.org/blog/
function getMax(values) { var maximum = values[0]; for (var i = 0; i < values.length; ++i) { if (values[i] > maximum) { maxinum = values[i]; } } return maximum;}
Can you find the bug?
function getMax(values) { var maximum = values[0]; for (var i = 0; i < values.length; ++i) { if (values[i] > maximum) { maxinum = values[i]; } } return maximum;}
Can you find the bug?
Hint: Javascript is a dynamic language
Our plugin can
Java is a static language
13
A Java to Javascript compiler right?
function rd(a,b){var c;if(b.b){b.b=false;b.c=null}c=b.c;b.c=a.f;try{++a.c;Cd(a.e,b,a.d)}finally{--a.c;a.c==0&&sd(a)}if(c==null){b.b=true;b.c=null}else{b.c=c}}function Hb(b,c){yb();$wnd.setTimeout(function(){var a=$entry(Eb)(b);a&&$wnd.setTimeout(arguments.callee,c)},c)}function ih(a,b){var c,d;if(b.e!=a){return false}try{Vg(b,null)}finally{c=b.f;(d=(hc(),c).parentNode,(!d||d.nodeType!=1)&&(d=null),d).removeChild(c);ki(a.b,b)}return true}function hj(c){if(c.length==0||c[0]>ao&&c[c.length-1]>ao){return c}var a=c.replace(/^(\s*)/,cn);var b=a.replace(/\s*$/,cn);return b}function qj(a){var b,c,d,e;b=0;d=a.length;e=d-4;c=0;while(c<e){b=a.charCodeAt(c+3)+31*(a.charCodeAt(c+2)+31*(a.charCodeAt(c+1)+31*(a.charCodeAt(c)+31*b)))|0;c+=4}while(c<d){b=b*31+a.charCodeAt(c++)}return b|0}function Bj(a){var b,c,d,e;e=this.v();a.length<e&&(a=Pd(a,e));d=a;c=this.p();for(b=0;b<e;++b){Ud(d,b,c.s())}a.length>e&&Ud(a,e,null);return a}function xl(a){var b,c,d;a.length<this.c&&(a=(c=a,d=Qd(0,this.c),Sd(c.aC,c.tI,c.qI,d),d));for(b=0;b<this.c;++b){Ud(a,b,this.b[b])}a.length>this.c&&Ud(a,this.c,null);return a}function Ud(a,b,c){if(c!=null){if(a.qI>0&&!ee(c.tI,a.qI)){throw wi(new ui)}if(a.qI<0&&(c.tM==gm||c.tI==2)){throw wi(new ui)}}return a[b]=c}function hi(a,b,c){var d,e;if(c<0||c>a.c){throw Qi(new Oi)}if(a.c==a.b.length){e=Rd(we,47,8,a.b.length*2,0);for(d=0;d<a.b.length;++d){Ud(e,d,a.b[d])}a.b=e}++a.c;for(d=a.c-1;d>c;--d){Ud(a.b,d,a.b[d-1])}Ud(a.b,c,b)}function th(b,c){var i;rh();var a,e,f,g,h;e=null;for(h=b.p();h.r();){g=fe(h.s(),8);try{c.q(g)}catch(a){a=Ge(a);if(ie(a,11)){f=a;!e&&(e=Fl(new Dl));i=Sj(e.b,f,e)}else throw a}}if(e){throw sh(new oh,e)}}function Tj(j,a,b,c){var d=j.b[c];if(d){for(var e=0,f=d.length;e<f;++e){var g=d[e];var h=g.y();if(j.x(a,h)){var i=g.z();g.A(b);return i}}}else{d=j.b[c]=[]}var g=Ul(new Sl,a,b);d.push(g);++j.e;return null}function bk(a){var b,c,d;if((a==null?null:a)===this){return true}if(!(a!=null&&de(a.tI,18))){return false}c=fe(a,18);if(c.v()!=this.v()){return false}for(b=c.p();b.r();){d=b.s();if(!this.u(d)){return false}}return true}function Cd(a,b,c){var d,e,f,g,h,i,j;g=b.j();d=(h=fe(Nj(a.b,g),4),!h?0:h.c);if(c){for(f=d-1;f>=0;--f){e=(i=fe(Nj(a.b,g),4),fe((Nk(f,i.c),i.b[f]),13));b.i(e)}}else{for(f=0;f<d;++f){e=(j=fe(Nj(a.b,g),4),fe((Nk(f,j.c),j.b[f]),13));b.i(e)}}}function Fb(a){var b,c,d,e,f,g;b=false;d=a.length;f=(new Date).getTime();while((new Date).getTime()-f<100){for(c=0;c<d;++c){g=a[c];if(!g){continue}if(!g[0].h()){a[c]=null;b=true}}}if(b){e=[];for(c=0;c<d;++c){if(!a[c]){continue}e[e.length]=a[c]}return e}else{return a}}function cf(){cf=gm;af={};bf=[];af[pn]=[lg,kg,mg];af[qn]=[tg,sg];af[rn]=[xg,wg];af[sn]=[Bg,Ag,Cg];_e(bf,se,pn);_e(bf,te,qn);_e(bf,ue,rn);_e(bf,ve,sn)}function Ok(a){var b,c,d,e,f;if((a==null?null:a)===this){return true}if(!(a!=null&&de(a.tI,4))){return false}f=fe(a,4);if(this.v()!=f.c){return false}d=Vk(new Sk,fe(this,4));e=Vk(new Sk,f);while(d.b<d.c.c){b=Xk(d);c=Xk(e);if(!(b==null?c==null:U(b,c))){return false}}return true}function Sg(a){var b;if(a.c){throw Ni(new Li,Rn)}a.c=true;a.f.__listener=a;b=a.d;a.d=-1;b>0&&(a.d==-1?_f(a.f,b|(a.f.__eventBits||0)):(a.d|=b),undefined);a.l();a.n()}
14
More like assembly-level JS
15
I can haz pretty print plz
Simply adjust the output style of the compiler via the plugin
function init(){ $GreetingService_Proxy(new GreetingService_Proxy); $add_0(($clinit_99() , get_0(null)), $Label(new Label, 'Foo')); $wnd.alert('foo');}
function caught_0(e){ if (e != null && canCast(e.typeId$, 11)) { return e; } return $JavaScriptException(new JavaScriptException, e);}
function $RemoteServiceProxy(this$static){ return this$static;}
function RemoteServiceProxy(){} 16
Yes, a Java to Javascript compiler
17
But wait...thereʼs more
18
A deeper dive
From Eclipse to your browser
19
package com.google.gwt.samples.eclipsecon.client;
import com.google.gwt.core.client.EntryPoint;import com.google.gwt.core.client.GWT;
@SuppressWarnings("unused")public class EclipseCon implements EntryPoint {
public void onModuleLoad() { Window.alert("foo"); }}
CodeServer
JettyServer
Eclipse
Bro
wse
r Plu
gins
TCP
HTTP
package com.google.gwt.samples.eclipsecon.client;
import com.google.gwt.core.client.EntryPoint;import com.google.gwt.core.client.GWT;
@SuppressWarnings("unused")public class EclipseCon implements EntryPoint {
public void onModuleLoad() { Window.alert("foo"); }}
From Eclipse to deployment
20
Generators Translators LinkersYour code...
package com.google.gwt.samples.eclipsecon.client;
import com.google.gwt.core.client.EntryPoint;import com.google.gwt.core.client.GWT;
@SuppressWarnings("unused")public class EclipseCon implements EntryPoint {
public void onModuleLoad() { Window.alert("foo"); }}
From Eclipse to deployment
21
Generators Translators LinkersYour code...
Generators
22
Provide the power behind your GWT app
Automate away boilerplate code
Foundation for permutations
Use Case: GWT RPCs
23
Client XHR
Serialization Code
Server
Serialization Code
Typical Ajax call
Use Case: GWT RPCs
24
Client XHR
Serialization Code
Server
Serialization Code
GWT-enabled AjaxG
WT
Pro
xyG
WT P
roxy
Use Case: GWT RPCs
25
• Serialization code begone
• RPCs like theyʼre meant to be - interface methods
• Make it fast to boot
Goals:
@RemoteServiceRelativePath("suggest")public interface SuggestService extends RemoteService { String getSuggestions(String str) throws IllegalArgumentException;}
26
You write code that looks like this:
Use Case: GWT RPCs
27
Simple enough.
28
He’s an Ajax pro
Behind the scenes
29
Eclipse plugin creates the scaffolding
GWTʼs RPC generator creates the implementation
Use Case #2: Creating UIs
30
• Utilize common dev practices
• Minimize boilerplate code interface methods
Goals:
• Remove a few other frustrations along the way
31
You write code that looks like this:
Use Case #2: Creating UIs
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <ui:style> .contactsViewButtonHPanel { margin: 5px 0px 0x 5px; } </ui:style>
<g:HorizontalPanel addStyleNames="{style.contactsViewButtonHPanel}"> <g:Button ui:field="addButton">Add</g:Button> <g:Button ui:field="deleteButton">Delete</g:Button> </g:HorizontalPanel>
</ui:UiBinder>
Behind the scenes
32
Eclipse plugin creates the scaffolding
GWTʼs UiBinder creates the implementation
package com.google.gwt.samples.eclipsecon.client;
import com.google.gwt.core.client.EntryPoint;import com.google.gwt.core.client.GWT;
@SuppressWarnings("unused")public class EclipseCon implements EntryPoint {
public void onModuleLoad() { Window.alert("foo"); }}
From Eclipse to your browser
33
Generators Translators LinkersYour code...
34
Javascript
Java
package com.google.gwt.samples.eclipsecon.client;
import com.google.gwt.core.client.EntryPoint;import com.google.gwt.core.client.GWT;
@SuppressWarnings("unused")public class EclipseCon implements EntryPoint {
public void onModuleLoad() { Window.alert("foo"); }}
From Eclipse to your browser
35
Generators Translators LinkersYour code...
36
Entry points for your GWT app
37
-gen will output a copy of the generated classes
GWT Tips and Tricks
GWT Tips and Tricks
-draftCompile• Skip all optimizations• Development only
Reduce optimizations, reduce compile time
GWT Tips and Tricks
-draftCompile• Skip all optimizations• Development only
Why worry about compiling at all?
Reduce optimizations, reduce compile time
A more efficient SDLC
Refresh Does it work?
Develop
No
Yes Compile
Deploy
40
We’re happy
41
But what about our users?
Optimize for the user
•Bundle resources•Split code
Resource Bundling
• Example - associating icons with a contact
Resource Bundling
Image image = new Image("images/image1.gif");image.setHeight("50px");image.setWidth("50px");imagesPanel.add(image);
One at a time
Resource Bundling
Initial download
Call to display images
Resource Bundling
public interface Resources extends ClientBundle { public static final Resources INSTANCE = GWT.create(Resources.class); @Source("Contacts.css") public ContactsCss contactsCss(); @Source("images0.gif") public ImageResource image0();
@Source("images1.gif") public ImageResource image1();
...
}
All at once
Resource Bundling
Call to display images
Initial download
Code splitting
Initial download
Not needed on startup
@UiHandler("showImagesButton")void onOkClicked(ClickEvent event) { GWT.runAsync(new RunAsyncCallback() { public void onSuccess() { showImagesDialog(); } });}
Code splitting
Split points - runAsync()
Code splitting
Initial download
Call to display images
Real world results - Google Wave
26-Nov 29-Apr 18-Jun 28-Jul 12-Sep 27-Oct 24-Dec 16-Mar
Siz
e of
Initi
al J
avaS
crip
t Dow
nloa
d (K
B)
375
750
1125
1500
0
7x Decrease InInitial Download Size
1400 KB
200 KB
Creating GWT apps - “Direct” approach
Write a bunch of widgets with self-contained logic
Problems:• Hard to test - need GWTTestCase• Mocks not encouraged - harder to write smaller tests• Platform specific UI code - limits code reuse• Too many dependencies - difficult to optimize
Creating GWT apps - MVP approach
Goals:• Be practical• Avoid rigid patterns• Put the complex logic in your Presenters• Put the widget code in your Views• Make the Views as dumb as possible
Cast:• Model - DTOs, and business logic• View - The display• Presenter - Application logic
MVC
MVP
MVP
The MVP Relationship
Model Presenter View
The MVP Relationship
Model Presenter View
The MVP Relationship
Model Presenter ViewHistory
The MVP Relationship
Model Presenter ViewHistory
RP
C
The MVP Relationship
Model Presenter ViewHistory
RP
C
Cac
he
The MVP Relationship
Model Presenter ViewHistory
RP
C
Event Bus
Cac
he
The MVP Relationship
Model Presenter ViewHistory
RP
C
Event Bus
Cac
he
History
Event Bus
RP
C
The MVP Relationship
Model Presenter ViewHistory
RP
C
Event Bus
Cac
he
History
Event Bus
RP
C
View
Making the Cloud a Reality
Making the Cloud a Reality
Calendar
Contacts
Sales Force Automation
CollaborationBankingSocial Network
Your next big idea
Making the Cloud a Reality
The right languages and tools are key
Making the Cloud a Reality