Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Building Web Apps Sanely - EclipseCon 2010

2,292 views

Published on

An overview of GWT that includes new 2.0 features, as well as some of the compiler and plugin internals.

  • Be the first to comment

  • Be the first to like this

Building Web Apps Sanely - EclipseCon 2010

  1. 1. Google Web Toolkit Building Web Apps Sanely Chris Ramsdale Developer Relations, Google
  2. 2. Agenda • Overview • Demo • Deeper dive • Optimizations for developers • Optimizations for users • Testing and deployment
  3. 3. 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
  4. 4. The GWT Family GWT SDK Google Plugin Speed Tracer For Eclipse
  5. 5. It’s a loving relationship
  6. 6. It’s a loving relationship Develop
  7. 7. It’s a loving relationship Develop Debug
  8. 8. It’s a loving relationship Develop Debug Optimize
  9. 9. 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
  10. 10. Different Goals Developers Customers • Next killer feature • Make it fast • Making it look good • ...oh, and don’t charge my credit card twice • Code refactoring
  11. 11. Different Goals Developers Customers • Next killer feature • Make it fast • Making it look good • ...oh, and don’t charge my credit card twice • Code refactoring
  12. 12. No plugins required Silverlight VML Flash
  13. 13. Nothing against them, but... Foo Player not available for your device We restrict use of technologies required by products like Foo Player...
  14. 14. Quirkiness Firefox Webkit (Safari) Opera IE Typical portable 2876 ms 1276 ms 2053 ms 4078 ms setInnerText() textContent=... - 908 ms 1386 ms - innerText=... 2477 ms 918 ms 1520 ms 2469 ms DOM manipulation 7148 ms 1997 ms 4836 ms 14800 ms
  15. 15. Quirkiness Firefox Webkit (Safari) Opera IE Typical portable 2876 ms 1276 ms 2053 ms 4078 ms setInnerText() textContent=... - 908 ms 1386 ms - innerText=... 2477 ms 918 ms 1520 ms 2469 ms DOM manipulation 7148 ms 1997 ms 4836 ms 14800 ms Improvement 14% 29% 32% 39%
  16. 16. Quirkiness Firefox Webkit (Safari) Opera IE Typical portable 2876 ms 1276 ms 2053 ms 4078 ms setInnerText() textContent=... - 908 ms 1386 ms - innerText=... 2477 ms 918 ms 1520 ms 2469 ms DOM manipulation 7148 ms 1997 ms 4836 ms 14800 ms Improvement 14% 29% 32% 39% http://quirksmode.org/blog/
  17. 17. 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; }
  18. 18. 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; } Hint: Javascript is a dynamic language
  19. 19. Our plugin can Java is a static language
  20. 20. Demo time To see this in action, letʼs: • Create a new web app • Debug within the browser • Update, refresh, run 13
  21. 21. Simple enough. 14
  22. 22. He’s an Ajax pro 15
  23. 23. A Java to Javascript compiler right? 16
  24. 24. More like assembly-level JS 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() 17
  25. 25. I can haz pretty print plz Simply adjust the output style of the compiler via the plugin 18
  26. 26. Yes, a Java to Javascript compiler function init(){ !!$stats && $stats({moduleName:$moduleName, sessionId:$sessionId, subSystem:'startup', evtGroup:'moduleStartup', millis:(new Date).getTime(), type:'onModuleLoadStart', className:'com.google.gwt.samples.eclipsecon.client.EclipseCon'}); $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(){ } 19
  27. 27. But wait...thereʼs more 20
  28. 28. Let’s take a look under the hood 21
  29. 29. From Eclipse to your browser Eclipse Browser Plugins package com.google.gwt.samples.eclipsecon.client; TCP import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; @SuppressWarnings("unused") Code public class EclipseCon implements EntryPoint { Server public void onModuleLoad() { Window.alert("foo"); } HTTP } Jetty Server 22
  30. 30. From Eclipse to deployment Your code... Generators Translators Linkers 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"); } } 23
  31. 31. From Eclipse to deployment Your code... Generators Translators Linkers 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"); } } 24
  32. 32. Generators Provide the power behind your GWT app Automate away boilerplate code Foundation for permutations 25
  33. 33. Use Case #1: GWT RPCs Typical Ajax call Serialization Serialization Code Code Client XHR Server 26
  34. 34. Use Case #1: GWT RPCs GWT-enabled Ajax Serialization Serialization GWT Proxy GWT Proxy Code Code Client XHR Server 27
  35. 35. Use Case #1: GWT RPCs Goals: • Serialization code begone • RPCs like theyʼre meant to be - interface methods • Make it fast to boot 28
  36. 36. Use Case #1: GWT RPCs You write code that looks like this: @RemoteServiceRelativePath("suggest") public interface SuggestService extends RemoteService { String getSuggestions(String str) throws IllegalArgumentException; } 29
  37. 37. Use Case #2: Creating UIs Goals: • Utilize common dev practices • Minimize boilerplate code interface methods • Remove a few other frustrations along the way 30
  38. 38. Use Case #2: Creating UIs You write code that looks like this: <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> 31
  39. 39. From Eclipse to your browser Your code... Generators Translators Linkers 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"); } } 32
  40. 40. Java Javascript 33
  41. 41. From Eclipse to your browser Your code... Generators Translators Linkers 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"); } } 34
  42. 42. Entry points for your GWT app 35
  43. 43. GWT Tips and Tricks -gen will output a copy of the generated classes 36
  44. 44. Question: What’s up with those compile times? 37
  45. 45. Question: What’s up with those compile times? Answer: Permutations 37
  46. 46. Question: What’s up with those compile times? Answer: ...and optimizations 38
  47. 47. Permutations Each *.cache.html is a browser and language specific version of the app
  48. 48. Permutations They’re a matrix, and will grow fast
  49. 49. GWT Tips and Tricks Reduce permutations, reduce compile time EclipseCon.gwt.xml <extend-property name="locale" values="en_US" /> <set-property name="user.agent" value="gecko" /> Now a single permutation targeting US versions of English in Firefox browsers
  50. 50. GWT Tips and Tricks Reduce optimizations, reduce compile time -draftCompile • Skip all optimizations • Development only
  51. 51. GWT Tips and Tricks Reduce optimizations, reduce compile time -draftCompile • Skip all optimizations • Development only Why worry about compiling at all?
  52. 52. Is it done yet?
  53. 53. A more efficient SDLC Refresh Does it work? Yes Compile No Develop Deploy
  54. 54. We’re happy 45
  55. 55. But what about our users? 46
  56. 56. Optimize for the user • Bundle resources • Split code
  57. 57. Resource Bundling • Example - associating icons with a contact
  58. 58. Resource Bundling One at a time Image image = new Image("images/image1.gif"); image.setHeight("50px"); image.setWidth("50px"); imagesPanel.add(image);
  59. 59. Resource Bundling Initial download Call to display images
  60. 60. Resource Bundling All at once 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(); ... }
  61. 61. Resource Bundling Initial download Call to display images
  62. 62. Code splitting Initial download Not needed on startup
  63. 63. Code splitting Split points - runAsync() @UiHandler("showImagesButton") void onOkClicked(ClickEvent event) { GWT.runAsync(new RunAsyncCallback() { public void onSuccess() { showImagesDialog(); } }); }
  64. 64. Code splitting Initial download Call to display images
  65. 65. Real world results - Google Wave 1500 1400 KB Size of Initial JavaScript Download (KB) 1125 750 7x Decrease In Initial Download Size 375 200 KB 0 26-Nov 29-Apr 18-Jun 28-Jul 12-Sep 27-Oct 24-Dec 16-Mar 56
  66. 66. Testing • Can be run as vanilla JRE tests • Can be run as GwtTestCase(s) - Requires a headless browser - 15 sec vs 15 ms runtime - Rely on design patterns such as MVP
  67. 67. Deployment and App Engine
  68. 68. Deployment and App Engine Stick around for the next talk
  69. 69. Google Plugin for Eclipse 1.3 • Configurable WAR directory • Transparent program and VM args • Minor bug fixes
  70. 70. Takeaways 1. Large Javascript projects can get messy 2. Browsers can be a bit quirky at times 3. Web developers haven’t always had the best tools 4. Ajax tends to require a fair amount of boilerplate code 5. With GWT, you can forget 1-4 and focus on the next killer feature
  71. 71. </presentation> Chris Ramsdale cramsdale@google.com Twitter: @cramsdale http://googlewebtoolkit.blogspot.com/

×