Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Embracing the network - Web Directions

Embracing the network - Web Directions

This version of the talk was originally presented at Web Directions in Sydney, Australia on the 30th October 2015. The video for the talk is also now online: https://www.webdirections.org/blog/video-week-patrick-hamann-embracing-network/

The network is intrinsically unreliable. More so, the network is out of your control as a developer. Therefore, we must design systems which embrace the unpredictability of the network and defend against it all costs. How can you prioritise the delivery of your core content? What best-practices can you use to optimise your assets? How can we design interfaces which adapt and respond to changing network conditions? And finally, how are new APIs such as ServiceWorker changing the way we think about the network?

During this talk Patrick will share his experiences delivering high-performance websites to millions of users over the past 3 years at The Guardian and Financial Times. Which – most importantly – are resilient to the network.

Patrick Hamann

October 30, 2015
Tweet

More Decks by Patrick Hamann

Other Decks in Programming

Transcript

  1. Embracing the network
    Patrick Hamann — Web Directions, October 2015

    @patrickhamann
    Modern techniques for building resilient front ends
    !

    View Slide

  2. View Slide

  3. View Slide

  4. Why?

    View Slide

  5. https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing
    FT.com

    View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing
    1. The network is reliable.
    2. Latency is zero.
    3. Bandwidth is infinite.
    4. The network is secure.
    5. Topology doesn't change.
    6. There is one administrator.
    7. Transport cost is zero.
    8. The network is homogeneous.

    The fallacies of distributed computing 

    PETER DEUTSCH — SUN MICROSYSTEMS, 1994
    https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing

    View Slide

  10. Multiple points of failure
    Dmytrii Shchadei — http://www.slideshare.net/metrofun/reduce-mobile-latency
    " # #
    #
    $
    Internal latency
    Firewalls, Load Balancers,
    Servers
    %
    Internet routing latency
    CDNs, ISPs, Caches, Proxies
    Control plane latency
    ~600ms on average UK 3G connection ~200ms

    View Slide

  11. The radio state machine
    http://developer.android.com/training/efficient-downloads/efficient-network-access.html
    Radio standby Radio low power Radio full power
    2s latency
    1.5s latency
    Radio idle for
    5 seconds
    Radio idle for
    12 seconds

    View Slide

  12. Title Text

    View Slide

  13. Title Text
    Request Map: http://requestmap.webperf.tools/

    View Slide

  14. Failure is inevitable
    • 1,000,000 page views a day
    • 3 years product life-time
    • (1000000*360)*3 = 1,080,000,000
    • 1 billion opportunities for something to go wrong.

    View Slide

  15. Baking in the assumption that everything can and will fail
    leads you to think differently about how you solve problems.

    SAM NEWMAN — BUILDING MICROSERVICES, O’REILLY 2015
    http://shop.oreilly.com/product/0636920033158.do

    View Slide

  16. 1. Testing and monitoring failure
    2. Designing for failure
    3. Embracing failure
    4. The future

    View Slide

  17. Testing and monitoring failure

    View Slide

  18. A single point of failure (SPOF) is a part of a system that, if it
    fails, will stop the entire system from working. SPOFs are
    undesirable in any system with a goal of high availability or
    reliability, be it a business practice, software application, or
    other industrial system.
    https://en.wikipedia.org/wiki/Single_point_of_failure

    View Slide

  19. Front end SPOFs
    http://www.stevesouders.com/blog/2010/06/01/frontend-spof/
    Chrome Firefox IE Opera Safari
    External script Blank below Blank below Blank below Blank below Blank below
    Stylesheet Flash Flash Blank below Flash Blank below
    inlined 

    @font-face
    Delayed Flash Flash Flash Delayed
    Stylesheet
    @font-face
    Delayed Flash Totally blank Flash Delayed
    Script then

    @font-face
    Delayed Flash Totally blank Flash Delayed

    View Slide

  20. http://uk.businessinsider.com/doubleclick-for-publishers-down-2014-11

    View Slide

  21. http://uk.businessinsider.com/doubleclick-for-publishers-down-2014-11

    View Slide

  22. http://uk.businessinsider.com/doubleclick-for-publishers-down-2014-11

    View Slide

  23. View Slide

  24. https://twitter.com/scottjehl/status/636303029533282304

    View Slide

  25. https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing

    View Slide

  26. Comcast - https://github.com/tylertreat/Comcast
    $ comcast --device=eth0 --latency=250 --target-bw=1000 --packet-loss=10%

    View Slide

  27. Facebook 2G Tuesdays - www.businessinsider.com.au/facebook-2g-tuesdays-to-slow-employee-internet-speeds-down-2015-10?op=1

    View Slide

  28. Jeremy Keith — https://flic.kr/p/o9thWy

    View Slide

  29. Resource timing API
    http://www.w3.org/TR/resource-timing/
    var resourceList = window.performance.getEntriesByType(‘resource');
    for (i = 0; i < resourceList.length; i++) {
    if (/link|script/.test(resourceList[i].initiatorType)) {
    navigator.sendBeacon('https://stats.ft.com/', {
    resource: resourceList[i].name,
    timing: (resourceList[i].responseEnd - resourceList[i].startTime)
    });
    }
    }

    View Slide

  30. View Slide

  31. • Test 1st and 3rd party dependencies for SPOFs
    • Use network shaping to simulate mobile conditions
    • Monitor all response times, timeouts and errors
    • Alert if metrics pass their thresholds

    View Slide

  32. 1. Testing and monitoring failure
    2. Designing for failure
    3. Embracing failure
    4. The future

    View Slide

  33. Designing for failure

    View Slide

  34. View Slide

  35. There seems to be an excessive amount of waiting around for
    pages to refresh and load -it doesn't seem as quick as the
    previous version.
    Luke Wroblewski – http://www.lukew.com/ff/entry.asp?1797

    View Slide

  36. View Slide

  37. View Slide

  38. View Slide

  39. View Slide

  40. Little big details — http://littlebigdetails.com/post/56782380031/pinterest-before-image-is-loaded-the-background

    View Slide

  41. Time and perception
    Delay User perception
    0 - 100ms Instant
    100 - 300ms Small perceptible delay
    300 - 1000ms Machine is working
    1000+ ms Likely mental context switch
    10,000+ ms Task is abandoned

    View Slide

  42. View Slide

  43. View Slide

  44. View Slide

  45. • Respond within a 1000ms
    • Avoid loading spinners
    • Consider using skeleton screens
    • Re-use familiar UI patterns within error messaging
    • Use human friendly copy, especially in error states

    View Slide

  46. 1. Testing and monitoring failure
    2. Designing for failure
    3. Embracing failure
    4. The future

    View Slide

  47. Embracing failure

    View Slide

  48. Pre-connect
    Ilya Grigorik — Eliminating roundtrips wth pre-connect: https://www.igvita.com/2015/08/17/eliminating-roundtrips-with-preconnect/
    socket setup

    View Slide

  49. Pre-connect


    function preconnectTo(url) {
    var hint = document.createElement("link");
    hint.rel = "preconnect";
    hint.href = url;
    document.head.appendChild(hint);
    }
    Ilya Grigorik — Eliminating roundtrips wth pre-connect: https://www.igvita.com/2015/08/17/eliminating-roundtrips-with-preconnect/

    View Slide

  50. When should I use resource hints?
    Method Use case Examples Frequecy
    preconnect
    Initiating an early connection to
    critical resources
    Image hosts, CDNs and
    analytics
    Often
    prefetch Fetch individual resource
    CSS or JS required for next
    page
    Limited
    prerender Fetch and execute HTML page Next page in a checkout flow Use with care

    View Slide

  51. View Slide

  52. Caching
    Libraries Utilities Application
    Rarely change Frequent change

    View Slide

  53. Caching
    Libraries Utilities Application
    Rarely change Frequent change

    View Slide

  54. Caching
    Libraries Utilities Application
    Rarely change Frequent change
    &
    core.js
    &
    app.js

    View Slide

  55. HTTP/2
    R.U.M data sampled over 1 month from https://next.ft.com/
    H2 Capable
    H2 Enabled
    Unsupported
    Mobile user load event
    0ms 2,000ms 4,000ms 6,000ms 8,000ms
    7,200
    5,325
    6,160

    View Slide

  56. View Slide

  57. View Slide

  58. Loading fonts
    https://tabatkins.github.io/specs/css-font-rendering/
    Chrome Opera Safari Firefox IE
    Timeout 3s 3s no timeout 3s 0
    Fallback Yes Yes n/a Yes Yes
    Swap Yes Yes n/a Yes Yes

    View Slide

  59. CSS Font Rendering Controls Module
    https://tabatkins.github.io/specs/css-font-rendering/
    @font-face {
    font-family: 'MyShinyFont';
    src: url('http://fonts.ft.com/async.woff2');
    font-display: swap;
    }
    @font-face {
    font-family: 'MyBlockingFont';
    src: url: url('http://fonts.ft.com/blocking.woff2');
    font-display: block;
    }

    View Slide

  60. '
    ServiceWorker
    & (
    %

    View Slide

  61. '
    ServiceWorker
    & (
    %

    View Slide

  62. '
    ServiceWorker
    & (
    %

    View Slide

  63. Cache only
    self.addEventListener('install', function(event) {
    event.waitUntil(
    caches.open(cacheName).then(function(cache) {
    return cache.addAll([
    ‘http://fonts.ft.com/fonts.css',
    'http://fonts.ft.com/serif',
    'http://fonts.ft.com/sans-serif'
    ]);
    })
    );
    });
    https://jakearchibald.com/2014/offline-cookbook

    View Slide

  64. Cache only
    https://jakearchibald.com/2014/offline-cookbook
    self.addEventListener('fetch', function(event) {
    // If this is a request for font file
    if (/fonts\.ft\.com/.test(event.request)) {
    // If a match isn't found in the cache, the response
    // will look like a connection error
    event.respondWith(caches.match(event.request));
    }
    });

    View Slide

  65. X
    Cache only
    '
    & (
    %

    (
    X
    (
    (
    &

    View Slide

  66. Loading CSS
    https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp?hl=en
    Request page
    Network
    Render
    GET html
    Build DOM
    response
    Build CSSOM Render page
    GET css
    GET js
    response
    response
    idle idle
    Render blocking
    Run JS
    Render blocking

    View Slide

  67. Loading CSS
    Request page
    Network
    Render
    GET html
    Build DOM
    response
    Build CSSOM Render page
    GET css
    GET js
    response
    response
    idle idle
    Async
    Render blocking
    Run JS
    https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp?hl=en

    View Slide

  68. https://github.com/filamentgroup/loadCSS

    View Slide

  69. Loading CSS
    Request page
    Network
    Render
    GET html
    Build DOM
    response
    Build CSSOM Render page
    GET css response
    idle idle
    Async
    https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp?hl=en
    Reflow

    View Slide

  70. Stale-while-revalidate
    self.addEventListener('fetch', function(event) {
    // Get stale from cache
    event.respondWith(
    caches.open(cacheName).then(function(cache) {
    return cache.match(event.request).then(function(response) {
    // If in cache relvalidate
    var network = fetch(event.request).then(function(response){
    if(response.status < 400) {
    cache.put(event.request, response.clone());
    }
    });
    // Return stale or network if none
    return response || network;
    });
    })
    );
    });
    https://jakearchibald.com/2014/offline-cookbook

    View Slide

  71. Stale-while-revalidate
    '
    & (
    %

    (

    View Slide

  72. Stale-if-error
    self.addEventListener('fetch', function(event) {
    // Always fetch response from the network
    event.respondWith(
    fetch(event.request).then(function(response) {
    return caches.open(cacheName).then(function(cache) {
    // If we received an error response
    if(!response.ok) {
    return cache.match(event.request)
    } else {
    // Response was healthy so update cached version
    cache.put(event.request, response.clone());
    return response;
    }
    });
    })
    );
    });

    View Slide

  73. Timeouts
    '
    & (
    %
    X *
    X

    View Slide

  74. Timeout race
    function timeout(delay) {
    return new Promise(function(resolve, reject) {
    setTimeout(function() {
    resolve(new Response('', {
    status: 408,
    statusText: 'Request timed out.'
    }));
    }, delay);
    });
    }
    self.addEventListener('fetch', function(event) {
    // Attempt to fetch with timeout
    event.respondWith(Promise.race([timeout(2000), fetch(event.request)]));
    });

    View Slide

  75. Dead letter queue
    '
    & (
    %
    X
    +
    offline

    View Slide

  76. Dead letter queue
    '
    & (
    %
    +
    Online

    View Slide

  77. Dead letter queue
    var queue = {};
    function queueFailedRequest(request) {
    queue[Date.now()] = request;
    }
    self.addEventListener('fetch', function(event) {
    if(/track\.ft\.com/.test(event.request.url) {
    event.respondWith(
    fetch(event.request).then(function(response){
    if(response.status >= 500) {
    return Response.error();
    } else {
    return response;
    }
    }).catch(function() {
    queueFailedRequest(event.request);
    })
    );
    }
    });

    View Slide

  78. Dead letter queue
    self.addEventListener('sync', function(event) {
    event.waitUntil(
    return Promise.all(queue.map(function(request) {
    return fetch(request)
    }))
    );
    });

    View Slide

  79. • Pre-connect sockets
    • Pre-fetch and cache critical resources
    • Bundle resources by their frequency of change
    • Serve stale and revalidate
    • Serve stale if error
    • Always use timeouts
    • Treat the network as an enhancement!

    View Slide

  80. 1. Testing and monitoring failure
    2. Designing for failure
    3. Embracing failure
    4. The future

    View Slide

  81. The future

    View Slide

  82. View Slide

  83. Offline
    Network unavaliable

    View Slide

  84. Push notifications

    View Slide

  85. Background sync
    navigator.serviceWorker.ready.then(function(registration) {
    regitration.periodicSync.register({
    tag: 'get-latet-news', // default: ''
    minPeriod: 12 * 60 * 60 * 1000, // default: 0
    powertState: 'avoid-draining', // default: 'auto'
    networkState: 'avoid-cellular' // default: 'online'
    }).then(function(periodicsyncReg) {
    // success
    }, function() {
    // failure
    });
    });

    View Slide

  86. 1. Testing and monitoring failure
    2. Designing for failure
    3. Embracing failure
    4. The future

    View Slide

  87. Conclusion

    View Slide

  88. Thanks
    @patrickhamann
    speakerdeck.com/patrickhamann

    github.com/Financial-Times
    !
    ,
    -
    Do you want to help build this stuff? Join in.
    [email protected]

    View Slide