Slide 1

Slide 1 text

mobify.com @mobify [email protected] Performance and the mobile web: why it still matters & what you can do about it (we’re hiring!) 1

Slide 2

Slide 2 text

mobify.com @mobify [email protected] About me 2 Peter McLachlan chief architect & co-founder @ Mobify Research & Development

Slide 3

Slide 3 text

mobify.com @mobify [email protected] Mobify 3

Slide 4

Slide 4 text

mobify.com @mobify [email protected] Trusted by Leading Companies 4

Slide 5

Slide 5 text

mobify.com @mobify [email protected] Some questions for you: 5 Interactive -- ask some questions, solicit some responses.

Slide 6

Slide 6 text

mobify.com @mobify [email protected] Audience question What kinds of optimizations do you make for web performance? 6

Slide 7

Slide 7 text

mobify.com @mobify [email protected] Audience question What is different about mobile? 7 •Hope for the following answers: •Battery •CPU •screen DPI •latency

Slide 8

Slide 8 text

mobify.com @mobify [email protected] Trends in the mobile web 8

Slide 9

Slide 9 text

mobify.com @mobify [email protected] Latest Trends - Metrics 9

Slide 10

Slide 10 text

mobify.com @mobify [email protected] Latest Trends - International Mobile Growth Image Credit: Brad Frost 10

Slide 11

Slide 11 text

mobify.com @mobify [email protected] What about mobile design? 11

Slide 12

Slide 12 text

mobify.com @mobify [email protected] Responsive design Ethan Marcotte “Fluid grids, flexible images, and media queries are the three technical ingredients for responsive web design” RESPONSIVE WEB DESIGN 12 We won’t talk about Responsive web design in a couple of years. Not because it’s gone away but because it will just be “web design” and people won’t do it any other way!

Slide 13

Slide 13 text

mobify.com @mobify [email protected] Adaptive Web Image Credit: Brad Frost 13

Slide 14

Slide 14 text

mobify.com @mobify [email protected] Adaptive Web Image Credit: Brad Frost 14

Slide 15

Slide 15 text

mobify.com @mobify [email protected] What makes mobile websites slow 15

Slide 16

Slide 16 text

mobify.com @mobify [email protected] Blocking resources 16 External CSS CSS includes via @import (Most) Javascript

Slide 17

Slide 17 text

mobify.com @mobify [email protected] Non-blocking resources 17 Most images (sorta) Async or deferred scripts

Slide 18

Slide 18 text

mobify.com @mobify [email protected] Bandwidth 18 Not out of the woods yet ... most of us are between the first pillar and the second pillar. Actual speeds tend to be a lot slower than theoretical maximums.

Slide 19

Slide 19 text

mobify.com @mobify [email protected] Latency Source: Ilya Grigorik (Google) 19

Slide 20

Slide 20 text

mobify.com @mobify [email protected] Latency 20

Slide 21

Slide 21 text

mobify.com @mobify [email protected] What does this mean? 0%# 10%# 20%# 30%# 40%# 50%# 60%# 70%# 80%# 90%# 100%# 100ms# 1s# 2s# 3s# 4s# 5s# 6s# 7s# 8s# 9s# 10s# eCommerce'sales'lost'due'to'load'.me' Source: Amazon web team (1% sales lost per 100ms) 21

Slide 22

Slide 22 text

mobify.com @mobify [email protected] No problem, we’ll make c faster Image credit: XKCD - “relativistic baseball” 22

Slide 23

Slide 23 text

mobify.com @mobify [email protected] Parsing: HTML 23 Unfortunately Responsive HTML is usually even more complicated

Slide 24

Slide 24 text

mobify.com @mobify [email protected] Image Credit: Guy Podjarny 24 http://www.guypo.com/mobile/javascript-pre-execution-for-mobile-taking-scripts-out-of-the-loop/

Slide 25

Slide 25 text

mobify.com @mobify [email protected] Amount of JS 25 Phone slow JS execution. iPhone 4 -> iPhone 4s, 2x cpu, 15% better JS!

Slide 26

Slide 26 text

mobify.com @mobify [email protected] CSS Complexity html body.s_blog section#page div.entry-content span.entry-body, html body.s_blog body.indexB section#page div.entry-content .hentry div.text, html body.indexB body.s_blog section#page div.entry-content .hentry div.text, html body.s_blog body.indexB section#page .hentry div.entry-content div.text, html body.indexB body.s_blog section#page .hentry div.entry-content div.text, html body.s_blog body.indexB section#page div.entry-content .dragrace-holder section.feature.dragrace div.text, html body.indexB body.s_blog section#page div.entry-content .dragrace-holder section.feature.dragrace div.text, html body.s_blog body.indexB section#page .dragrace-holder section.feature.dragrace div.entry-content div.text, html body.indexB body.s_blog section#page .dragrace-holder section.feature.dragrace div.entry-content div.text, html body.s_blog body.indexB body.list.listC .container section#page div.entry-content .hentry div.main-column .item-inner #slideshow-description-outer div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.entry-content .hentry div.main- column .item-inner #slideshow-description-outer div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page .hentry div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page .hentry div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.entry-content .hentry div.main- column .item-inner #slideshow-description-outer div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.entry-content .hentry div.main-column .item-inner #slideshow-description-outer div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page .hentry div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page .hentry div.main-column .item-inner #slideshow- description-outer div.entry-content div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page div.entry-content div.main-column .item-inner #slideshow-description-outer .hentry div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.entry-content div.main-column .item- inner #slideshow-description-outer .hentry div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page div.main-column .item-inner #slideshow-description- outer .hentry div.entry-content div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.main-column .item-inner #slideshow-description-outer .hentry div.entry-content div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.entry-content div.main-column .item-inner #slideshow-description- outer .hentry div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.entry-content div.main-column .item-inner #slideshow-description- outer .hentry div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.main-column .item-inner #slideshow-description-outer .hentry div.entry- content div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.main-column .item-inner #slideshow-description-outer .hentry div.entry-content div.item- footer, html body.s_blog body.indexB body.list.listC .container section#page div.entry- content .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow- description-outer div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.entry-content .dragrace-holder section.feature.dragrace div.main- column .item-inner #slideshow-description-outer div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.entry- content div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.entry-content .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.entry-content .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.entry- content div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page div.entry-content div.main-column .item-inner #slideshow-description-outer .dragrace-holder section.feature.dragrace div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.entry-content div.main-column .item-inner #slideshow- description-outer .dragrace-holder section.feature.dragrace div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page div.main-column .item-inner #slideshow- description-outer .dragrace-holder section.feature.dragrace div.entry-content div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.main-column .item- inner #slideshow-description-outer .dragrace-holder section.feature.dragrace div.entry- content div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.entry-content div.main-column .item-inner #slideshow-description-outer .dragrace-holder section.feature.dragrace div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.entry-content div.main-column .item-inner #slideshow- description-outer .dragrace-holder section.feature.dragrace div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.main-column .item-inner #slideshow- description-outer .dragrace-holder section.feature.dragrace div.entry-content div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.main-column .item- inner #slideshow-description-outer .dragrace-holder section.feature.dragrace div.entry- content div.item-footer { font-size: 13px; display: block; margin-top: 10px; } 26 CSS Selector of shame Please never do this.

Slide 27

Slide 27 text

mobify.com @mobify [email protected] Layout reflow + Painting • Repaints -- also maybe raid some stuff from Ilya’s presentation 27

Slide 28

Slide 28 text

mobify.com @mobify [email protected] What causes these? • clientHeight • clientLeft • clientTop • clientWidth • focus • getBoundingClientRect • getClientRects • innerText • offsetHeight • offsetLeft • offsetParent • offsetTop • offsetWidth • outerText • scrollByLines • scrollByPages • scrollHeight • scrollIntoView • scrollIntoViewIfNeeded • scrollLeft • scrollTop • scrollWidth • MouseEvent • layerX • layerY • offsetX • offsetY • Window • getComputedStyle • scrollBy • scrollTo • scrollX • scrollY • Frame • Document & Image • height • width Any DOM modification or: 28

Slide 29

Slide 29 text

mobify.com @mobify [email protected] Making sites faster: strategy 29

Slide 30

Slide 30 text

mobify.com @mobify [email protected] Moving down is hard Image Credit: Brad Frost 30 This is the way we’ve usually done things. Time to turn it around.

Slide 31

Slide 31 text

mobify.com @mobify [email protected] The Web of the Future Mobile First: Smartphone *and* Tablet 31

Slide 32

Slide 32 text

mobify.com @mobify [email protected] Mobile first! Image Credit: Brad Frost 32

Slide 33

Slide 33 text

mobify.com @mobify [email protected] Performance anti- patterns 33

Slide 34

Slide 34 text

mobify.com @mobify [email protected] Anti-pattern: domain sharding 34 Domain sharding is now an anti-pattern. At best it provides neutral results and adds complexity. Complexity is bad. In the future it will probably be a very significant anti-pattern.

Slide 35

Slide 35 text

mobify.com @mobify [email protected] Anti-pattern: blocking JavaScript at the top of the document 35

Slide 36

Slide 36 text

mobify.com @mobify [email protected] Anti-pattern: Large library dependencies 36

Slide 37

Slide 37 text

mobify.com @mobify [email protected] Anti-pattern: Naive lazy loading Wait, isn’t being lazy good? 37 Wait, isn’t lazy-loading good? Sorta. We’re not taking advantage of browser optimizations!

Slide 38

Slide 38 text

mobify.com @mobify [email protected] Performance patterns 38

Slide 39

Slide 39 text

mobify.com @mobify [email protected] Remove unneeded resources • The best optimization there is! • Difficult to do, ex post facto • Developer time is precious • Greedy browsers don’t help us out here 39 The best optimization there is! Only load things when we have to! * This sounds pretty easy, but it’s tricky in practice developer time is precious, there’s always another bug to squash usual approach is to throw everything in and hope to have time to wean it down later. This seldom happens. async vs defer

Slide 40

Slide 40 text

mobify.com @mobify [email protected] Compress assets 40 Again -- seems easy. So why don’t more sites do it? * It’s a pain. Easy to do once, difficult to maintain * Even if you write scripts that do it for you, changes can break those deployment scripts * Even sites maintained by large, capable web teams seem not to get this right. Need proof? I’m not going to shame anyone in public, just go visit some top retailer site with developer tools running.

Slide 41

Slide 41 text

mobify.com @mobify [email protected] Pre-fetching 41 * Nobody has done a really great job of this * DNS pre-fetching * Page pre-fetching * Image / JS pre-fetching + localStorage

Slide 42

Slide 42 text

mobify.com @mobify [email protected] Pre-fetching Homepage Signup Studio Services DNS HTML JS CSS Images 42

Slide 43

Slide 43 text

mobify.com @mobify [email protected] Intelligent radio warmup 43 DCH = Dedicated channel FACH = Forward access cannel may be able to transmit small data packets on the random access channel (RACH)

Slide 44

Slide 44 text

mobify.com @mobify [email protected] Making use of localStorage and “smart” caching: localStorage performance 44 Instantiating a 20kb javascript from localStorage

Slide 45

Slide 45 text

mobify.com @mobify [email protected] Making use of localStorage and “smart” caching: native cache performance 45

Slide 46

Slide 46 text

mobify.com @mobify [email protected] Generic optimizations • CDN • Limit number of hosts • Set good caching headers • Far future expires • Cookieless domains 46 * Why limit number of hosts: Tie back to 3-way handshake & domain sharding example * Why cookieless domains make a difference

Slide 47

Slide 47 text

mobify.com @mobify [email protected] Some resources for performance • https://developers.google.com/speed/ • http://www.igvita.com/ (Gregorik Ilya, Google Performance team) • http://stevesouders.com/ (Author of "High Performance Websites, O'reilly & Associates" ) (author of YSlow) • Recommendations? 47

Slide 48

Slide 48 text

mobify.com @mobify [email protected] Final thoughts 48

Slide 49

Slide 49 text

mobify.com @mobify [email protected] Performance - we could spend weeks on this • There are no shortcuts. To really get into mobile performance you need an engineer who understands: • HTTP/1.1 • pipelining • cacheing rules • TCP/IP • 3-way handshake • congestion control • packet-loss impacts • Web servers • c10k problem & solutions • cacheing • concurrency models • Content Delivery Networks • DNS • latency • cacheing • IP Anycast • DNS • Georouting • Asynchronous network communications • 3G+4G radio behavior ... • Browser concurrency models • what is threaded what is not • synchronous & asynchronous operations • Browser rendering processes • what forces a repaint? • Modern web design • workflow • content • marketing requirements 49

Slide 50

Slide 50 text

mobify.com @mobify [email protected] 50

Slide 51

Slide 51 text

mobify.com @mobify [email protected] Thank you! (are you a unicorn? we are hiring!) 51