livestand : learnings. yui conf 2011

49
Livestand Learnings Wednesday, November 9, 2011 52

Upload: sdezzi

Post on 11-May-2015

1.925 views

Category:

Technology


1 download

DESCRIPTION

A detailed look into the unique engineering challenges and solutions which went into delivering a key Yahoo! product that needed to provide a rich cross-device application without compromising on the 'native' experience.

TRANSCRIPT

Page 1: Livestand : Learnings. YUI Conf 2011

LivestandLearnings

Wednesday, November 9, 2011

52

Page 2: Livestand : Learnings. YUI Conf 2011

LivestandLearnings

http://blog.jeffreymcmanus.com/157/learnings-is-a-stupid-stupid-word/

Wednesday, November 9, 2011

52

Page 3: Livestand : Learnings. YUI Conf 2011

The next hour of your life*• Livestand

• WebApp, Native

• YUI

• JS

• CSS

• HTML

• YQL, Data

• Hybrid

Wednesday, November 9, 2011

2.49 (2min)

Page 4: Livestand : Learnings. YUI Conf 2011

The next hour of your life*• Livestand

• WebApp, Native

• YUI

• JS

• CSS

• HTML

• YQL, Data

• Hybrid

* I completely understand if this suddenly makes you rethink your path in life and you’d like to leave to catch the next flight to Hawaii

Wednesday, November 9, 2011

2.49 (2min)

Page 5: Livestand : Learnings. YUI Conf 2011

Livestand

• Rich Content Presentation

• Highly Customizable Content

• Publishers - Custom Content Experiences• Users - Personalized Experiences

• Shared Experience Across Devices

• Rich Ads

Wednesday, November 9, 2011

5.40 (3min), Demo (2min). Livestand - more than a “digital magazine”. Heavy duty Y! infrastructure driving content personalization. Target devices: Not just iOS, or even iOS + Android. Anything which runs a Web stack.

Page 6: Livestand : Learnings. YUI Conf 2011

Decisions, Decisions

Native?WebApp?

Wednesday, November 9, 2011

7.24

Page 7: Livestand : Learnings. YUI Conf 2011

Native

• Runtime(s) across which we couldn’t reuse code

• Runtime(s) we’d need to find developers for

• Closed runtime(s)

• Runtime(s) which can access device h/w

• Runtime(s) which may perform better

Wednesday, November 9, 2011

10:30 (3min)

Page 8: Livestand : Learnings. YUI Conf 2011

WebApp• A common runtime across devices - shared code

• A runtime we have (experienced) developers for

• An open runtime

• A runtime with limited access to the device h/w

• A runtime which may have performance constraints

Wednesday, November 9, 2011

12.41 (2min)

Page 9: Livestand : Learnings. YUI Conf 2011

• A common runtime across devices - shared code

• A runtime we have (experienced) developers for

• An open runtime

Hybrid

• A runtime with limited access to the device h/w

• A runtime which may have performance constraints• A runtime with limited access to the device h/w

• A runtime which may have performance constraints

Wednesday, November 9, 2011

12.41 (2min)

Page 10: Livestand : Learnings. YUI Conf 2011

Livestand• Virtually all of the UI and App Logic is JS, HTML, CSS

• Native Services Layer

Wednesday, November 9, 2011

14:40 (2min). Most UI/App Logic sits in the WebStack. This is the logic which is most likely to change on a weekly/monthly basis in reaction to UED/Product requirements. Native Layer is fairly stable/util layer. Doesn’t need to be modified (anywhere near) as frequently.

Page 11: Livestand : Learnings. YUI Conf 2011

Livestand• Virtually all of the UI and App Logic is JS, HTML, CSS

• Native Services Layer

• Multi-User Authentication

• YQL Caching

• Local URL Routing, Package Management

• Memory Management / Thread Control

• Multi-WebView

• Deployment Management

Wednesday, November 9, 2011

14:40 (2min). Most UI/App Logic sits in the WebStack. This is the logic which is most likely to change on a weekly/monthly basis in reaction to UED/Product requirements. Native Layer is fairly stable/util layer. Doesn’t need to be modified (anywhere near) as frequently.

Page 12: Livestand : Learnings. YUI Conf 2011

YUI• Modules, Dependencies

• JS Utils (oop, each, bind ...)

• Node

• Event

• Gestures - flick, move, tap*

• Intl

• IO

Wednesday, November 9, 2011

15:36 (1). Core areas of YUI used - Modules/Loader Dependency management (to drive composition of independently developed/custom modules onto a single page) and the abstraction layers - to not only drive the “Cross Device” product goal, but also so that as more and more (independently developed) module code is shipped, we don’t need to worry about whether or not module A has WebKit specific code and won’t port to Opera.

Page 13: Livestand : Learnings. YUI Conf 2011

Modules and DependenciesNews

Sports Stocks WeatherDevice

Cloud

Wednesday, November 9, 2011

20 (4.3min) Stocks, News, etc. are independent modular implementations (Mojits, as they are called in the Mojito world). Mojits are defined as YUI modules and have their own set of dependencies. Mojito uses Loader (either at run-time or build-time - configurable), to determine the composite set of dependencies which make up the page.

Page 14: Livestand : Learnings. YUI Conf 2011

Modules and DependenciesNews

Sports Stocks WeatherDevice

Cloud

Mojito MVC Framework YUIYChrome - Hybrid Bridge

Wednesday, November 9, 2011

20 (4.3min) Stocks, News, etc. are independent modular implementations (Mojits, as they are called in the Mojito world). Mojits are defined as YUI modules and have their own set of dependencies. Mojito uses Loader (either at run-time or build-time - configurable), to determine the composite set of dependencies which make up the page.

Page 15: Livestand : Learnings. YUI Conf 2011

Modules and DependenciesNews

Sports Stocks Weather

Package Repository YQL User Preferences

Device

Cloud

Mojito MVC Framework YUIYChrome - Hybrid Bridge

Wednesday, November 9, 2011

20 (4.3min) Stocks, News, etc. are independent modular implementations (Mojits, as they are called in the Mojito world). Mojits are defined as YUI modules and have their own set of dependencies. Mojito uses Loader (either at run-time or build-time - configurable), to determine the composite set of dependencies which make up the page.

Page 16: Livestand : Learnings. YUI Conf 2011

Modules and DependenciesNews

Sports Stocks Weather

Package Repository YQL User Preferences

StocksHTML

CSS

JS

StocksFeed Data

StocksPreferences

Internal and External Modules Internal and External Publisher Data User Preferences and Profiles

Device

Cloud

Mojito MVC Framework YUIYChrome - Hybrid Bridge

Wednesday, November 9, 2011

20 (4.3min) Stocks, News, etc. are independent modular implementations (Mojits, as they are called in the Mojito world). Mojits are defined as YUI modules and have their own set of dependencies. Mojito uses Loader (either at run-time or build-time - configurable), to determine the composite set of dependencies which make up the page.

Page 17: Livestand : Learnings. YUI Conf 2011

Modules and DependenciesNews

Sports Stocks Weather

Package Repository YQL User Preferences

StocksHTML

CSS

JS

StocksFeed Data

StocksPreferences

Internal and External Modules Internal and External Publisher Data User Preferences and Profiles

Device

Cloud

Mojito MVC Framework YUIYChrome - Hybrid Bridge

Wednesday, November 9, 2011

20 (4.3min) Stocks, News, etc. are independent modular implementations (Mojits, as they are called in the Mojito world). Mojits are defined as YUI modules and have their own set of dependencies. Mojito uses Loader (either at run-time or build-time - configurable), to determine the composite set of dependencies which make up the page.

Page 18: Livestand : Learnings. YUI Conf 2011

Modules and DependenciesNews

Sports Stocks Weather

Package Repository YQL User Preferences

StocksHTML

CSS

JS

StocksFeed Data

StocksPreferences

Internal and External Modules Internal and External Publisher Data User Preferences and Profiles

Mojito MVC Framework YUIYChrome - Hybrid Bridge

Stocks

YUI.add(“stocks.model”, fn() { }, ..., {requires:[io, json]})

YUI.add(“stocks.binder”, fn() { }, ..., {requires:[ls-vitality-looper]})

YUI.add(“stocks.controller”, fn() { }, ..., {requires:[mojito-partial-addon]})

Wednesday, November 9, 2011

20 (4.3min) Stocks, News, etc. are independent modular implementations (Mojits, as they are called in the Mojito world). Mojits are defined as YUI modules and have their own set of dependencies. Mojito uses Loader (either at run-time or build-time - configurable), to determine the composite set of dependencies which make up the page.

Page 19: Livestand : Learnings. YUI Conf 2011

Modules and DependenciesNews

Sports Stocks Weather

Package Repository YQL User Preferences

StocksHTML

CSS

JS

StocksFeed Data

StocksPreferences

Internal and External Modules Internal and External Publisher Data User Preferences and Profiles

Mojito MVC Framework YUIYChrome - Hybrid Bridge

Wednesday, November 9, 2011

20 (4.3min) Stocks, News, etc. are independent modular implementations (Mojits, as they are called in the Mojito world). Mojits are defined as YUI modules and have their own set of dependencies. Mojito uses Loader (either at run-time or build-time - configurable), to determine the composite set of dependencies which make up the page.

Page 20: Livestand : Learnings. YUI Conf 2011

Going Through 10,000 Lines of Code WithA Fine Toothed Comb

Node, Event, Gestures

Wednesday, November 9, 2011

As mentioned before - don’t want to have to weed through 10,000 lines of independently developed, 3rd party code, in order to figure out which Mojit may be hardcoding WebKit references, or Firefox references ... and so may not work in the next environment we need to support. That’s why it makes sense to have an abstraction layer to work against (Node, Event, Gestures, IO etc.) even if you think you may not need it today.

Page 21: Livestand : Learnings. YUI Conf 2011

Going Through 10,000 Lines of Code WithA Fine Toothed Comb

Going Through 10,000 Lines of Code WithA Fine Toothed Comb

Node, Event, Gestures

Wednesday, November 9, 2011

As mentioned before - don’t want to have to weed through 10,000 lines of independently developed, 3rd party code, in order to figure out which Mojit may be hardcoding WebKit references, or Firefox references ... and so may not work in the next environment we need to support. That’s why it makes sense to have an abstraction layer to work against (Node, Event, Gestures, IO etc.) even if you think you may not need it today.

Page 22: Livestand : Learnings. YUI Conf 2011

Node & NodeList

Wednesday, November 9, 2011

22:43 (2.4min) Aside from the abstraction, you also get sugar - NodeList iteration, setContent, ancestor, and even Array-like methods - push/pop/shift/unshift etc.

Page 23: Livestand : Learnings. YUI Conf 2011

Node & NodeList

item = e.target.ancestor('li[data-name]');

icon.getComputedStyle('backgroundImage');

Wednesday, November 9, 2011

22:43 (2.4min) Aside from the abstraction, you also get sugar - NodeList iteration, setContent, ancestor, and even Array-like methods - push/pop/shift/unshift etc.

Page 24: Livestand : Learnings. YUI Conf 2011

Node & NodeList

node.all('[data-image],[data-bg-image]').each(

function(node){

...

ancestor = ... ?

node : node.ancestor('[data-index]');

node.one('.summary').setContent(art.title);

...

}

)

Wednesday, November 9, 2011

22:43 (2.4min) Aside from the abstraction, you also get sugar - NodeList iteration, setContent, ancestor, and even Array-like methods - push/pop/shift/unshift etc.

Page 25: Livestand : Learnings. YUI Conf 2011

Node & NodeList

children = node.get('childNodes');

...

while (parent.get('scrollHeight') < h

&& children.size()){

lastChild = children.shift();

node.appendChild(lastChild);

}

Wednesday, November 9, 2011

22:43 (2.4min) Aside from the abstraction, you also get sugar - NodeList iteration, setContent, ancestor, and even Array-like methods - push/pop/shift/unshift etc.

Page 26: Livestand : Learnings. YUI Conf 2011

Event

Wednesday, November 9, 2011

24:00 (1.5 min) Same for event. Sugar: once, delegate, handle.detach()

Page 27: Livestand : Learnings. YUI Conf 2011

Event

this.handle = btn.on( 'click', onClickNextDay);

...

this.handle.detach();

Wednesday, November 9, 2011

24:00 (1.5 min) Same for event. Sugar: once, delegate, handle.detach()

Page 28: Livestand : Learnings. YUI Conf 2011

Event

Y.one('window').on( 'webviewWillAppear', onWebviewAppeared);

Wednesday, November 9, 2011

24:00 (1.5 min) Same for event. Sugar: once, delegate, handle.detach()

Page 29: Livestand : Learnings. YUI Conf 2011

Event

Y.one('#foreground').once('contentready',

initView);

Wednesday, November 9, 2011

24:00 (1.5 min) Same for event. Sugar: once, delegate, handle.detach()

Page 30: Livestand : Learnings. YUI Conf 2011

Gestures• flick zodiac.on('flick', handleZodiacFlick);

• gesture movestart, move, moveend publications.delegate('gesturemovestart', startPubEdit, '[data-name]');

publication.on('gesturemove', movePub);

publication.once('gesturemoveend', endPubEdit);

• tap node.delegate('tap', handleTap, '[data-index]');

Wednesday, November 9, 2011

25.41 (1.5min) The sugar also works for gestures. Aside from using flick, gesturemove*, Livestand developed their own Tap gesture which needs to be rolled back into YUI, to work around the ~400ms click delay.

Page 31: Livestand : Learnings. YUI Conf 2011

Wednesday, November 9, 2011

27.20 (1:40min) What a gesture/synthetic event impl looks like. Ability to add low-level “gateway” criteria before notifying listeners - a right click is not a tap, two fingers is not a tap etc.

Page 32: Livestand : Learnings. YUI Conf 2011

Y.Event.define(EVENTS.TAP, {

})Wednesday, November 9, 2011

27.20 (1:40min) What a gesture/synthetic event impl looks like. Ability to add low-level “gateway” criteria before notifying listeners - a right click is not a tap, two fingers is not a tap etc.

Page 33: Livestand : Learnings. YUI Conf 2011

Y.Event.define(EVENTS.TAP, {

var EVENTS = TOUCH ? { START : 'touchstart' ...

} : { START : 'mousedown' ... };

on : function (...) { node.on(EVENTS.START, this.gestureStart ...); },

delegate : function (...) { ... },

...

})Wednesday, November 9, 2011

27.20 (1:40min) What a gesture/synthetic event impl looks like. Ability to add low-level “gateway” criteria before notifying listeners - a right click is not a tap, two fingers is not a tap etc.

Page 34: Livestand : Learnings. YUI Conf 2011

Y.Event.define(EVENTS.TAP, {

...

gestureStart : function(...) { // Right/middle clicks aren’t a tap gesture if (e.button && e.button !== 1) { return; } ... },

gestureEnd : function (...) { var endXY = TOUCHES ? [e.changedTouches[0].pageX,...] : [e.pageX,...]; ...

// If the mouse/finger moved, it’s not a tap gesture if (Math.abs(endXY[0] - startXY[0]) < THRESHOLD && Math.abs(endXY[1] - startXY[1]) < THRESHOLD) { e.type = EVENTS.TAP; e.pageX = endXY[0]; e.pageY = endXY[1]; ... notifier.fire(e); } }

})Wednesday, November 9, 2011

27.20 (1:40min) What a gesture/synthetic event impl looks like. Ability to add low-level “gateway” criteria before notifying listeners - a right click is not a tap, two fingers is not a tap etc.

Page 35: Livestand : Learnings. YUI Conf 2011

Feeding Back Into YUI

• Loader : Pre-compute dependencies off device

• Get : Parallel Dispatch Support

• Feature Testing : Cache Across Instances

• K-Weight Reduction : Lighter Passthrough

• Tap Gesture

• ScrollView

Wednesday, November 9, 2011

32.16 (5min) a) Moved Loader costs off-device, to a build-time step. Basically don’t do at run-time what you could do a build-time. b) Added Get parallel dispatch support to 3.4.0 Loader will be upgraded to work with it for 3.5.0 c) Maybe there’s some stuff we could cache across Y instances. e.g. Feature Test results. d). node-core - a passthrough abstraction layer, if you really just want to develop for iOS right now, but would like the safety net of being able to port to another environment down the road (see “10,000 lines of code”)

Page 36: Livestand : Learnings. YUI Conf 2011

ScrollView

• Scale10’s of instances / page

• H/W Acceleration Memory UsageLimit GPU Composite layer size, by only maintaining N of M pages of content in the DOM at a time

Wednesday, November 9, 2011

35.06 (3min) Possible Lighter ScrollView, without custom events, for cases where you don’t need a rich API to work with (ala NodePlugins).

Page 37: Livestand : Learnings. YUI Conf 2011

Offline Loader5.2s

2.9s

Wednesday, November 9, 2011

36.56 (2min) Savings by moving Loader off-device

Page 38: Livestand : Learnings. YUI Conf 2011

JS Profiler

Wednesday, November 9, 2011

38:27 (1.5min), 3.00 demo: Awesome on-device profiling support (hoping to open source!). Hooks into JavaScript core on the native side to collect function call data, on-device, and dumps trace data which is viewable in a slightly modified version of Android’s TraceView (modified to show stack trace).

Page 39: Livestand : Learnings. YUI Conf 2011

JS

• Most JS cost impact is around retrieving and parsing code

• Minification reduces parsing costs - parsing costs

• File I/O is expensive - Combo’ing JS is valuable, even on device

• JIT compilation still not available for iOS UIWebViews

Wednesday, November 9, 2011

43.16 (2min)

Page 40: Livestand : Learnings. YUI Conf 2011

CSS• H/W Acceleration Has Its Price

• There’s a significant memory cost

• Flipping from 3D to 2D to try and free up memory introduces flicker

• visibility:hidden reduces memory cost, but still has a runtime cost

• Removing content from the DOM is better

• translateZ introduces stacking context

• Experimental/glitchy

• Inlined Structural CSS

• IO cost savings, and also to avoid CSS application race conditions with JS

• Surprising Reflow and Style Recalculation Triggers

Wednesday, November 9, 2011

47 (3.5min)

Page 41: Livestand : Learnings. YUI Conf 2011

Wednesday, November 9, 2011

50.47 (4min) Interesting Trace information. Hooks added to WebCore, show trace from JS layer to WebCore.

Page 42: Livestand : Learnings. YUI Conf 2011

willLayoutImpl: 1 WebCore WebCore::InspectorInstrumentation::willLayout(...) 2 WebCore WebCore::FrameView::layout(...) 3 WebCore WebCore::Document::updateLayout() 4 WebCore WebCore::Document::updateLayoutIgnorePendingStylesheets() 5 WebCore WebCore::Element::focus(...) 6 WebCore WebCore::jsElementPrototypeFunctionFocus(...) .. 9 JavaScriptCore JSC::Interpreter::execute(...)

elem.focus() causes layout()?

Wednesday, November 9, 2011

50.47 (4min) Interesting Trace information. Hooks added to WebCore, show trace from JS layer to WebCore.

Page 43: Livestand : Learnings. YUI Conf 2011

willRecalculateStyleImpl: 1 WebCore WebCore::InspectorInstrumentation::willRecalculateStyle(...) 2 WebCore WebCore::Document::recalcStyle(Node::StyleChange) 3 WebCore WebCore::Document::updateStyleIfNeeded() 4 WebCore WebCore::Document::updateLayout() 5 WebCore WebCore::Document::updateLayoutIgnorePendingStylesheets() 6 WebCore WebCore::Element::scrollLeft() const 7 WebCore WebCore::jsElementScrollLeft(...) 8 JavaScriptCore JSC::PropertySlot::getValue(...) const 9 JavaScriptCore JSC::JSValue::get(...) const

get scrollLeft cause style recalc?

Wednesday, November 9, 2011

50.47 (4min) Interesting Trace information. Hooks added to WebCore, show trace from JS layer to WebCore.

Page 44: Livestand : Learnings. YUI Conf 2011

willRecalculateStyleImpl: 1 WebCore WebCore::InspectorInstrumentation::willRecalculateStyle(...) 2 WebCore WebCore::Document::recalcStyle(Node::StyleChange) 3 WebCore WebCore::Document::updateStyleIfNeeded() 4 WebCore WebCore::Document::updateLayout() 5 WebCore WebCore::Document::updateLayoutIgnorePendingStylesheets() 6 WebCore WebCore::Element::offsetWidth() 7 WebCore WebCore::jsElementOffsetWidth(...) 8 JavaScriptCore JSC::PropertySlot::getValue() const 9 JavaScriptCore JSC::JSValue::get() const

get offsetWidth causes style recalc?

Wednesday, November 9, 2011

50.47 (4min) Interesting Trace information. Hooks added to WebCore, show trace from JS layer to WebCore.

Page 45: Livestand : Learnings. YUI Conf 2011

HTML

• Templating - Handlebars/Mustache

• Pre-build Templates : HTML t0 JS

• Many Templates, Single Use : Mustache may be better

• <VIDEO> appears to have a memory leak, when resetting src

• <VIDEO>, like <INPUT>, swallows touch events

• Time Analysis

• 200-300 ms after assigning a URL to a webview, before any io

Wednesday, November 9, 2011

2min

Page 46: Livestand : Learnings. YUI Conf 2011

YQL - Data• Pre-generated Data

• Offload Join/Aggregation costs to Mojito Server

• Offload Schema Normalization to YQL

• Local, Native, Offline Cache

• Work Around Promptless 5MB Web Storage Limit

• Leverage Native Thread Management

• Segregate Multi-User Databases

• Down The Road

• Pre-generated Seed SQL

• Support Sparse Records

• Native Connection Limit

• YQL Connection - 4 connection limit (same as browser)Wednesday, November 9, 2011

3min. This is Huge! Mojito can run mojits on either the client or the (nodejs) server. So same mojit code can be used to dispatch YQL requests on the server, to offload YQL request combination/aggregation costs from device to the cloud. Huge!. Other than that, also makes sense to offload data normalization costs from device to YQL. Chose native layer offline caching to work around 5MB limit in Web SQL storage. Also allowed us to distribute workload to native thread.

Page 47: Livestand : Learnings. YUI Conf 2011

Hybrid• Bridging Technique/Costs

• XHR/Background URL access• Modifying window.location url• Native Object/Class exposed to JS

• Caching YQL/Data Natively

• Multi Webviews

• Threading Concerns

• Experiments

• Using WebViews as WebWorkers

• Native JSON Parsing

Wednesday, November 9, 2011

Livestand used XHR, to have the JS client call the Native layer. Aside from not having to deal with window navigation, also allowed Native layer to avoid memory copy. XHR response pointer could just be moved to the payload created by the Native layer. Multi-WebViews were used to prime the basic stack for the page and user was switched between WebViews when moving from one type of page to the next, reducing time to initial view. However only 1 JS thread across WebViews, so had to be careful about when they were primed.

Page 48: Livestand : Learnings. YUI Conf 2011

Aside from “Wear Sunscreen”

• (Really) Understand the technologies you’re working with

• IO, Data Access costs and DOM are still the key performance pieces

• Progressive Enhancement is your friend

• Don’t do at run time what you can do at build time

• Think twice, tattoo once. If it’s on your face, thrice really wouldn’t hurt.

Wednesday, November 9, 2011

2min JS/Web Developer moving from the one-step up formalization from a few years ago (OO development, separation of concerns, JS performance analysis) to areas where you really need to understand what the JS engines and browsers are doing (e.g. H/W acceleration). Overall IO/Parsing/DOM/Data Access turned out to be the biggest chunk of cost while rendering the page (as opposed to pure run-time JS costs). Progressive enhancement is still valid and can be used to provide a low-fidelity, but quick experience while the richer infrastructure is booting up.

Page 49: Livestand : Learnings. YUI Conf 2011

Livestand Content Thanks To:

Andres GarzaCurtis HarveyDaryl LowGanesan SriramKris GiesingRic AllinsonRob Simutis

Me:

Satyen Desai ([email protected])

Wednesday, November 9, 2011

1min These folks not only provided a lot of the meaty content for this talk, but they along with many others contributed to Mojito, Livestand, YUI and YQL to deliver the experience as you see it today.