The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

42

description

Google Web Toolkit is providing more and more information to developers in terms of how it is compiling your code, and how you can improve it. In this session, we will explain the tools available to you, how to interpret the results, and how you can guide this choose-your-own-adventure in the direction you want.Watch a video at http://www.bestechvideos.com/2009/06/09/google-i-o-2009-the-story-of-your-compile-reading-the-tea-leaves-of-the-gwt-compiler

Transcript of The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

Page 1: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler
Page 2: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler
Page 3: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

The Story of Your Compile:

Reading the Tea Leaves of the GWT Compiler for an Optimized FutureLex Spoon and Bruce JohnsonMay 28, 2009

Page 4: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

3

Would You Take This Deal?

Tweak your app for 1 hour

Reduce your startup script size by 50%

Page 5: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

Showcase startup size, zipped (KB)

56

108

4

Leverage, I Say!

• Initial download reduced by half

• Doesn't load code that doesn't run

• Amortize download delay

• Perfectly-cacheable fragments

Compiled with GWT trunk, r5406

Page 6: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

5

Topics

• Should we really care about optimization?• Stuff we should've said last year• Code splitting in GWT 2.0• Code splitting walkthrough• The story of your compile• Async package pattern

Page 7: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

6

Should We Really Care About Optimization?

YES

Page 8: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler
Page 9: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

Stuff We Should've Said Last Year

Page 10: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

8

Deciphering RPC

• As of GWT 1.6, pass -extra flag to the compiler for extras

• module.rpc.log explains the RPC code generator logic

• See dynatable.rpc.log

Page 11: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

9

Watching the Compiler Optimize

public class ShapeExample implements EntryPoint { private static final double SIDE_LEN_SMALL = 2; private final Shape shape = new SmallSquare();

public static abstract class Shape { public abstract double getArea(); }

public static abstract class Square extends Shape { public double getArea() { return getSideLength() * getSideLength(); } public abstract double getSideLength(); }

public static class SmallSquare extends Square { public double getSideLength() { return SIDE_LEN_SMALL; } }

public void onModuleLoad() { Shape shape = getShape(); Window.alert("Area is " + shape.getArea()); }

private Shape getShape() { return shape; }}

-Dgwt.jjs.traceMethods = "ShapeExample.onModuleLoad"

Page 12: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

10

Better, eh?

public class ShapeExample implements EntryPoint { public void onModuleLoad() { Window.alert("Area is 4.0"); }}

Page 13: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler
Page 14: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

Code Splitting in GWT 2.0

Page 15: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

“We strongly prioritize features that can make the biggest differences to end users. Obviously, we want to make developers' lives easier, too, but never at the expense of the user experience.”

"Making GWT Better"

Page 16: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

HTML JS Running

JS Running!

JS

Running!!HTML

JS

Running!!!

Time

Speedup

Without splitting

With splitting

13

Why Code Splitting?

Page 17: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

• Accessing unloaded code might need a delay• It can also fail

14

Partially Loaded as the Normal State

GWT.runAsync(new RunAsyncCallback() { public void onSuccess() { // runs when code loads } public void onFailure(Throwable reason) { // runs on failure } }

Page 18: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler
Page 19: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

Code Splitting Walkthrough

Page 20: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

16

Simple Example: Composing Email

public static void onComposeEmailButtonClicked() { EmailCompositionView.show(); }

Page 21: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

App code for reading email

Library code used by (1)

App code for composing email

Library code used by (3)

Compiled JavaScript

1

2

3

4

17

Not All Functionality is Created Equal

Page 22: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

18

Splitting Out "Compose" With runAsync

public void onComposeEmailButtonClicked() { GWT.runAsync(new RunAsyncCallback() { public void onSuccess() { // This will run once the necessary fragment is loaded EmailCompositionView.show(); } public void onFailure(Throwable reason) { // This will run if the necessary fragment cannot be loaded Window.alert("failed to load"); }}); }

Page 23: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

App code for reading email

Library code used by (1)

App code for composing email

Library code used by (3)

Compiled JavaScript

1

2

3

4

X window.alert("Load failed")

19

w00t!

Available immediately

Deferred until "Compose" button clicked

Page 24: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

20

A Week Later, un-w00t :-(

// This is reachable directly // from onModuleLoad()public void onComposeKeystrokeClicked() { EmailCompositionView.show();}

But then the new guy on the team does this

Recall splitting out "Compose" code like this

public void onComposeEmailButtonClicked() { GWT.runAsync(new runAsyncCallback() { public void onSuccess() { EmailCompositionView.show(); } public void onFailure(Throwable e) { Window.alert("failed to load"); }}); }

Split point...good!

Direct reference...bad!

Page 25: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

App code for reading email

Library code used by (1)

App code for composing email

Library code used by (3)

Compiled JavaScript

1

2

3

4

21

Back to Where We Started

Page 26: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler
Page 27: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

The Story of Your Compile

Page 28: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

23

Story of Your Compile (SOYC)

• What code downloads when?• How big is each part?• Why can't a particular method be deferrred?• Let's take a look...

Page 29: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

24

The Whack-a-Mole Solutionpublic void onComposeEmailButtonClicked() { GWT.runAsync(new runAsyncCallback() { public void onSuccess() { EmailCompositionView.show(); } public void onFailure(Throwable e) { Window.alert("failed to load"); } }); }

public void onComposeKeystrokeClicked(){ GWT.runAsync(new runAsyncCallback() { public void onSuccess() { EmailCompositionView.show(); } public void onFailure(Throwable e) { Window.alert("failed to load"); } }); }

...repeat everywhere this recurs...

Page 30: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

App code for reading email

Library code used by (1)

App code for composing email

Library code used by (3)

Compiled JavaScript

1

2

3

4

X window.alert("Load failed")

25

re-w00t! (+ Uneasiness About Maintainability)

Available immediately

Deferred until "Compose" button clicked

Page 31: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler
Page 32: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

The Async Package Pattern

Page 33: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

27

Async Package Pattern

• Only the library developer needs to be careful, not the client• Carefully isolate classes within a package• Have exactly one "gateway class"• Make its constructor private • Remove static methods• Instantiate the gateway class only within a runAsync call

Page 34: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

28

Async Package Pattern: Gateway Classpublic class EmailCompositionView { private EmailCompositionView() { }

public interface Callback { void onCreated(EmailCompositionView view); void onCreateFailed(); }

// Only callable once a client gets an instance public show() { // Use lots of other code that has restricted visibility ... }

public static void createAsync(final Callback callback) { GWT.runAsync(new RunAsyncCallback() { public void onSuccess() { callback.onCreated(new EmailCompositionView()); } public void onFailure(Throwable e) { callback.onCreateFailed(); } }); }}

Page 35: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

29

Callers Can't Get it Wrong

public void onComposeKeystrokeClicked(){ EmailCompositionView.createAsync( new EmailCompositionView.Callback() { public void onCreated(EmailCompositionView view) { // "show" is only callable once client has an instance view.show(); } ... } ); ...

Page 36: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

30

Keep the Module Instance

public class MyModule { private final Expensive expensive; public MyModule(Expensive expensive) { this.expensive = expensive; } public void randomMethod() { expensive.doSomethingExpensive(); } }

Page 37: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler
Page 38: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

Wrap-up

Page 39: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

32

Summary of Suggestions

• Think about performance early, and track it as your app grows• Use .rpc.log to understand size costs of RPC• Identify less-used functionality and use runAsync() to split it out• Use SOYC to understand code size and to debug splitting• Find a splitting pattern to keep split points working reliably• Think about what to do while fragments are being loaded and

what to do if fragment loading fails• In other words, put yourself in the end-user's shoes

Page 40: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler
Page 41: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler

Q & A

Page 42: The Story of Your Compile: Reading the Tea Leaves of the GWT Compiler