Download - Google Developer Fest 2010
Between us and lunch
• 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
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
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
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
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
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
From Eclipse to your browser
20
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
21
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
22
Generators Translators LinkersYour code...
Generators
23
Provide the power behind your GWT app
Automate away boilerplate code
Foundation for permutations
Use Case: GWT RPCs
25
Client XHR
Serialization Code
Server
Serialization Code
GWT-enabled AjaxG
WT
Pro
xyG
WT P
roxy
Use Case: GWT RPCs
26
• 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;}
27
You write code that looks like this:
Use Case: GWT RPCs
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
30
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 your browser
32
Generators Translators LinkersYour code...
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
Resource Bundling
Image image = new Image("images/image1.gif");image.setHeight("50px");image.setWidth("50px");imagesPanel.add(image);
One at a time
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
@UiHandler("showImagesButton")void onOkClicked(ClickEvent event) { GWT.runAsync(new RunAsyncCallback() { public void onSuccess() { showImagesDialog(); } });}
Code splitting
Split points - runAsync()
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
Making the Cloud a Reality
Calendar
Contacts
Sales Force Automation
CollaborationBankingSocial Network
Your next big idea