GWT@Jazoon08 - Part 1/6 - First Impressions Count

Preview:

DESCRIPTION

A presentation about GWT which I presentaed at Jazoon '08Part 1/6 - First Impressions Count

Citation preview

LOGO SPEAKER‘S COMPANY

# 1first impressions count.

LOGO SPEAKER‘S COMPANY

checking in at a hotel ...

LOGO SPEAKER‘S COMPANY

choosing a puppy ...

LOGO SPEAKER‘S COMPANY

unboxing your iPhone ...

LOGO SPEAKER‘S COMPANY

unboxing your iPhone ...

LOGO SPEAKER‘S COMPANY

unboxing your iPhone ...

LOGO SPEAKER‘S COMPANY

start fast.“Every web usability study I have conducted since 1994 has shown the same thing: Users beg us to speed up page downloads.”

- Jakob Nielsen

LOGO SPEAKER‘S COMPANY

human attention.0.1 seconds - perceived as instantaneous

1 second - maintains the feeling that a single task is being carried out

10 seconds - limit for keeping user’s attention

LOGO SPEAKER‘S COMPANY

annoying.

slow apps are annoying

buggy apps are annoying

slow, buggy apps are not worth using

LOGO SPEAKER‘S COMPANY

irrelevant.

source code elegance and maintainability

how much fun it is to develop

choice of programming language

LOGO SPEAKER‘S COMPANY

GWT manifesto.

“To radically improvethe web experience for usersby enabling developersto use existing Java toolsto build no-compromise Ajaxfor any modern browser.”

LOGO SPEAKER‘S COMPANY

page load.

1. download resources

2. run JavaScript startup code

3. render layout

LOGO SPEAKER‘S COMPANY

LOGO SPEAKER‘S COMPANY

resource issues.

50kb = 1200ms

25kb = 950ms

2 x 25kb = 2 x 950 ms

50kb = 1900ms

ms

kb

LOGO SPEAKER‘S COMPANY

startup issues.

lazy loading

lazy loading

lazy loading

lazy loading

lazy loading

LOGO SPEAKER‘S COMPANY

rendering issues.

LOGO SPEAKER‘S COMPANY

GWTto the rescue

LOGO SPEAKER‘S COMPANY

goal.

reduce # HTTP request by reducing file count

cache until the sun explodes

cross browser, cross platform at no cost

min usability compromises due to impl changes

extreme JavaScript code optimizations

LOGO SPEAKER‘S COMPANY

compiler.

“Seperate maintainability of the source codefrom the effectiveness of the executable.”

- Bruce Johnson

LOGO SPEAKER‘S COMPANY

compiler.

handwritten JavaScript has a conflict of interest

long, useful identifiers = bigger, slower apps nice formatting = bigger, slower apps comments = bigger, slower apps

zero-cost abstraction

LOGO SPEAKER‘S COMPANY

compiler.

user feedback and usability testing are vital

you will never get it right the first N times

being able to iterate quickly is key

developers need tools with lots of leverage

LOGO SPEAKER‘S COMPANY

compiler.

again, JavaScript has a conflict of interest

JavaScript = difficult to refactorrefactoring difficulty = maintenance worrymaintenance worry = the need to “get it right” the first time (framework-itis)

LOGO SPEAKER‘S COMPANY

stop! no more GWT introduction stuff

please...

LOGO SPEAKER‘S COMPANY

so what makesGWT so fast?

LOGO SPEAKER‘S COMPANYis it magic?

LOGO SPEAKER‘S COMPANY

deferred binding.

LOGO SPEAKER‘S COMPANY

only payfor what you see

LOGO SPEAKER‘S COMPANY

LOGO SPEAKER‘S COMPANY

right code.user agentlocaledebug vs. productionnetwork characteristicsloggingdebug id on html elements…anything that can make a difference for the user

LOGO SPEAKER‘S COMPANY

modularize.

DOMImplIE6

DOMImplMozilla

DOMImplSafari

DOMImpl…

DOM

LOGO SPEAKER‘S COMPANY

problems.

dynamic modules over HTTP suckslow to start

awful network utilizationslow to execute

requires polymorphic dispatch at runtimeimpossible to eliminate dead code

hard to maintain“DLL Hell” for the web

LOGO SPEAKER‘S COMPANY

magic.DOMImpl dom = GWT.create(DOMImpl.class);

generates permutations at compile time: DOMImpl dom = new DOMImplMozilla(); DOMImpl dom = new DOMImplIE6(); DOMImpl dom = new DOMImplSafari();

LOGO SPEAKER‘S COMPANY

DOMIMPL EXAMPLE

abstract class DOMImpl {

abstract void setInnerText(Element e, String s);

}

public class DOMImplMozilla extends DOMImpl {

native void setInnerText(Element e, String s)

/*-- { e.textContent = s; } --*/

}

public class DOMImplIE6 extends DOMImpl {

native void setInnerText(Element e, String s)

/*-- { e.innerText = s; } --*/

}

LOGO SPEAKER‘S COMPANY

advantages.right code

smaller code

better optimizations

fewer network roundtrips

metaprogramming

LOGO SPEAKER‘S COMPANY

BETTER OPTIMIZATIONS

example

Label label = new Label(“test”);

output (not obfuscated)

Firefox e.textContent = s;

IE6 e.innerText = s;

LOGO SPEAKER‘S COMPANY

deferred binding.[ dependency injection ]

LOGO SPEAKER‘S COMPANY

CREATE AN INTERFACE / BASE CLASS

public interface Animal {

String makeSound();

}

CREATE IMPLEMENTATIONS

public class Dog implements Animal {

public String makeSound() { return “bark”; }

}

public class Cat implements Animal {

public String makeSound() { return “miauuwww”; }

}

LOGO SPEAKER‘S COMPANY

USE IT

Animal animal = GWT.create(Animal.class);

Window.alert(animal.makeSound());

DECLARE REBIND RULES

<replace-with class=“org.animal.Cat”>

<when-type-is class=“org.animals.Animal”/>

</replace-with>

LOGO SPEAKER‘S COMPANY

DECLARE PROPERTY / ENUMERATED SET OF VALUES

<define-property name=“animal” values=“cat,dog”/>

DECLARE REBIND RULES

<replace-with class=“org.animal.Cat”>

<when-type-is class=“org.animals.Animal”/>

<when-property-is name=“animal” value=“cat”/>

</replace-with>

<replace-with class=“org.animal.Dog”>

<when-type-is class=“org.animals.Animal”/>

<when-property-is name=“animal” value=“dog”/>

</replace-with>

LOGO SPEAKER‘S COMPANY

DECLARE REBIND RULES (other conditions)

<when-type-is class=“...”/><when-type-assignable class=“...”/>

<when-property-is name=“...” value=“...”/><any><all><none>

EXTEND PROPERTY VALUES (optional / inheritance)

<extend-property name=“animal” values=“fish”/>

SET DEFAULT PROPERTY VALUE (optional)

<set-property name=“animal” values=“dog”/>

LOGO SPEAKER‘S COMPANY

SET PROPERTY VALUE AT RUNTIME (optional)

<property-provider name=“animal”><!CDATA[

return isCat(document.cookie) ? “cat” : “dog”/>

]]></property-provider>

LOGO SPEAKER‘S COMPANY

deferred binding.[ generators ]

LOGO SPEAKER‘S COMPANY

CREATE A NEW GENERATOR

public class CatGenerator extends Generator {

public String generate(TreeLogger logger, GeneratorContext ctx, String requestedClass) {

PrintWriter pw = ctx.tryCreate(logger, “test”, “EvilCat”); pw.println(“package test;”); pw.println(“public class EvilCat implements Animal {“); pw.println(“public String makeSound() { return “Gshhh”; }”); pw.println(“}”);

return “test.EvilCat”; }

LOGO SPEAKER‘S COMPANY

DECLARE REBIND RULES

<generate-with class=“org.animals.CatGenerator”>

<when-type-is class=“org.animals.Animal”/>

</generate-with>

DECLARE REBIND RULES (other conditions)

<when-type-is class=“...”/>

<when-type-assignable class=“...”/>

<when-property-is name=“...” value=“...”/>

<any>

<all>

<none>

LOGO SPEAKER‘S COMPANY

GWT REFLECTION VS JAVA REFLECTION

TypeOracle oracle = generatorContext.getTypeOracle();

LOGO SPEAKER‘S COMPANY

deferred binding.[ demystified ]

LOGO SPEAKER‘S COMPANY

runtime.request generated selection script .nocache.js

property providers run to decide prop values

property values imply a permutation:

map([‘de, ‘ie6’, …], ‘blabla.cache.html’) map([‘nl’, ‘ie6’, …], ‘ababab.cache.html’) map([‘nl’, ‘safari’, …], ‘xyxyxy.cache.html’) strongName = answers[computePropValue(‘locale’)] [computePropValue(‘’user.agent)]

LOGO SPEAKER‘S COMPANY

permutations..cache.html allows for perfect caching

cache until the sun explodes

never fail to get the newest when updated

never ask if it hasn’t been updated

not even an If-Modified-Since check

disk space is cheap

bandwith and user attention is expensive

LOGO SPEAKER‘S COMPANY

deferred binding.[ use case: form generation ]

LOGO SPEAKER‘S COMPANY

GOAL

less boilerplate code no more listener overhead / memory leaks alternative for traditional MVC + GWTX (PropertyChangeListener)

DATA OBJECT + FORM ANNOTATIONS

@form.service (value=“com.WishService”)

public class Wish implements FormDataObject {

@form.field (length = 50, label = “name”, order = 2, required = true)

private String name;

@form.field (length = 200, label = “description”, order = 1, required = true)

private String description;

}

LOGO SPEAKER‘S COMPANY

BINDING

<generate-with class=“com.FormGenerator”>

<when-type-assignable class=“com.FormDataObject”/>

</generate-with>

USAGE

public void onModuleLoad() {

Form wishForm = GWT.create(Wish.class);

RootPanel.get().add(wishForm);

}

LOGO SPEAKER‘S COMPANY

deferred binding.[ pages versus modules ]

LOGO SPEAKER‘S COMPANY

SEARCH

100%

SEARCHEDIT

95%

ACCOUNT

5%

LOGO SPEAKER‘S COMPANY

extreme graphics.

LOGO SPEAKER‘S COMPANY

problems.

DOM operations are slow

CANVAS bails out at 1000 - 10000 DIV moves

JavaScript VM no match for JVM

LOGO SPEAKER‘S COMPANY

solutions.display lists (OpenGL concept)

recorded + compiled sequence of callsreplay sequence like a macro

fastest method to draw static datacompiler can do performance optimizationscache results as bitmap where possible

LOGO SPEAKER‘S COMPANY

solutions.dual compile

measure average client side thresholdif too slow render on server bare HTML (StringBuffer) / Java2D

SVG / VML / flash

LOGO SPEAKER‘S COMPANY

solutions.small enhancements

replace DOM.setStyleAttribute with CSS filesdon’t use widgets when all you need is HTMLavoid many listenerssingle listener on root -> DOM.sinkEvents

LOGO SPEAKER‘S COMPANY

MAARTENVOLDERS.comPASSIONATE ABOUT PEOPLE AND TECHNOLOGY