Turbocharging Walmart.com - Speed without compromise

A presentation at #PerfMatters in April 2020 in by Vasanth Krishnamoorthy

Slide 1

Slide 1

Turbocharging Walmart.com: Speed without compromise Vasanth Krishnamoorthy vasanth_k vasanthk

Slide 2

Slide 2

Focus Areas Approaching Performance 7 Key Optimizations Guardrails for Performance

Slide 3

Slide 3

100 million+ customers per month Over 30% growth YoY

Slide 4

Slide 4

Performance as a Measure Of User Happiness

Slide 5

Slide 5

Typical Customer Journey Cart Checkout Product Home Page Page Search Tech Stack

Slide 6

Slide 6

Customer Journey 42% Improvement TTI - 95th %ile mobile web

Slide 7

Slide 7

PART 1 Approaching Performance

Slide 8

Slide 8

Where do you start?

Slide 9

Slide 9

“You can’t improve what you don’t measure”

Slide 10

Slide 10

Measure What Matters TTI – Time to interactive (custom) TTFB – Time to first byte TLOAD - Page is fully loaded (custom) TTFB TTI TLOAD

Slide 11

Slide 11

Define Your Scope

Slide 12

Slide 12

Define Your Scope & Constraints 01 02 03 No compromise to existing product features No slowdown on new product features being built No big rewrites or tech stack changes

Slide 13

Slide 13

Identify The Right Opportunities

Slide 14

Slide 14

Empathize With Your Users Understand common user flows Revenue distribution by browsers & platform Step progression User distribution by browsers/devices/connection Use data to understand user pain points

Slide 15

Slide 15

Audit Your Application Chrome’s Dev Tools WebPageTest & Lighthouse Make the invisible visible Webpack Bundle Analyzer

Slide 16

Slide 16

Apply First Principles

Slide 17

Slide 17

Principles of Web Performance 1 Do only what is needed 2 Minimize round trip time 3 Optimize Perceived Performance

Slide 18

Slide 18

PART 2 7 Key Optimizations

Slide 19

Slide 19

Do only what is needed

Slide 20

Slide 20

Reduce Bundle Size

Slide 21

Slide 21

1 Code Splitting & Lazy Loading “Get it when you need it” Component centric code splitting via dynamic imports (ES2020) TTI 18.2% Code split user/item specific feature code Lazy load components which are below the fold 18.2% Cumulative TTI Improvement

Slide 22

Slide 22

1 Code Splitting - Learnings Aggressive code splitting increased overall bytes downloaded Our sweet spot Duplicates in chunks Reduced Compression 18.2% Cumulative TTI Improvement < 15 split bundles

Slide 23

Slide 23

2 Slim Down Libraries Gains From Switch To Moment.js date-fns 50KB React v15 React v16 15KB React-Intl Custom utility 14KB Recompose React API / Hooks 5KB (compressed) Upgrade from Webpack v3 to v4 reduced bundle size by 10% TTI 9.7% 18.2% 26.1% Cumulative TTI Improvement

Slide 24

Slide 24

3 Differential Serving Enables us to serve modern JS code to users Why do we need it? TTI 3.3% • Transformed ES5 code is verbose (more KB) • Cut down on polyfills needed (~35KB for us) 28.5% 26.1% Cumulative TTI Improvement

Slide 25

Slide 25

3 Differential Serving Module No-Module Pattern 28.5% 26.1% Cumulative TTI Improvement

Slide 26

Slide 26

3 Differential Serving - Learnings Problem On a few browser versions both ES5 & ES6 scripts were downloaded/executed leading to degraded experience for those customers 28.5% 26.1% Cumulative TTI Improvement

Slide 27

Slide 27

3 Differential Serving - Learnings Solution On Server side, we check for the user agent passed and depending on whether the browser supports modern syntax or not we include the right bundle into the page. 28.5% 26.1% Cumulative TTI Improvement

Slide 28

Slide 28

Minimize round trip time

Slide 29

Slide 29

Sharing is caring for our users

Slide 30

Slide 30

4 Shared Bundles Webpack DLL Plugin 1P/3P bundles • Shared across whole site Functional shared bundles • Shared across Cart & Checkout TTI 10.2% 35.8% 25.8% Cumulative TTI Improvement

Slide 31

Slide 31

4 Shared Bundles - Learnings Functional shared bundles 1P/3P shared bundle Needs unification of package versions across applications Updates frequently and requires changes across all shared web-apps Updates to shared bundles require coordination with multiple teams Testing/validations & Release effort 35.8% 28.5% Cumulative TTI Improvement

Slide 32

Slide 32

5 Shared Header/Footer Problem Header/Footer package was bundled into each app leading to bloat Any change required testing/validation & deployments across for all teams

Slide 33

Slide 33

5 Shared Header/Footer Render Header/Footer & rest of the App in parallel during SSR Solution Endpoint returning header/footer HTML Fragment Markup & bundles get cached

Slide 34

Slide 34

5 Shared Header/Footer 70% Optimization reduction in client side JS Reuse existing code and render with React on Server Side TTI 8.1% Use Vanilla JS for handling events on client 41% 35.8% Cumulative TTI improvement

Slide 35

Slide 35

6 Brotli Compression “It’s like GZIP on steroids” 12% smaller bundles than GZIP TTI 9.8% 46.7% 41% Cumulative TTI Improvement

Slide 36

Slide 36

6 Brotli Compression – Learnings Dynamic compression can be slow For Best Perf - Pre-build compressed assets and serve it from a CDN to save the runtime cost. 46.7% 41% Cumulative TTI Improvement

Slide 37

Slide 37

6 Brotli Compression - Learnings For Differential Serving Brotli compressed ES5 bundles pretty well ES6 vs ES5 bundle difference dropped from 10% to 4%* *YMMV 46.7% 41% Cumulative TTI Improvement

Slide 38

Slide 38

Optimize Perceived Performance

Slide 39

Slide 39

7 Leverage Priorities & Resource Hints <script> <script async> defer> HTML parsing Script download HTML parsing paused Script execution TTI 5.7% 49.7% 46.7% Cumulative TTI improvement

Slide 40

Slide 40

7 Leverage Priorities & Resource Hints Tells the browser to download and cache a resource to have them available for execution when it is needed 49.7% 46.7% Cumulative TTI Improvement

Slide 41

Slide 41

7 Leverage Priorities & Resource Hints dns-prefetch preconnect DNS lookup DNS lookup, TLS negotiation, and TCP handshake 49.7% 46.7% Cumulative TTI Improvement

Slide 42

Slide 42

Can we make it faster?

Slide 43

Slide 43

“The fastest HTTP request is the one not made”

Slide 44

Slide 44

8 Prefetch Downloads scripts with lower priority & stores it in prefetch cache TTI 12.1% Cached for at least 5mins Does not execute JS 49.7% 55.8% Cumulative TTI Improvement

Slide 45

Slide 45

8 Prefetch - Learnings Workaround Problem Impacts current page’s load times • We include prefetch tags into the page after onLoad event is fired • We do not prefetch if the user has data saver on 49.7% 55.8% Cumulative TTI Improvement

Slide 46

Slide 46

Video Comparison Before After

Slide 47

Slide 47

Key Takeaways

Slide 48

Slide 48

Perf Optimizations – Key Takeaways Reduce Bundle Size • Code Splitting & Lazy Loading • Slim down libraries • Differential Serving Shared bundles • 1P/3P & functional shared bundles • Header/Footer HTML fragment Font Optimization • Remove unused glyphs & styles • WOFF & WOFF2 for better compression Image • • • Lazy load images WEBP SVG Better compression • Brotli Redux State transfer optimization • Send state to client in an inert tag Priorities & resource hints • Prefer defer over async • dns-prefetch & preconnect • Prefetch Other Cleanup • Code which you have always wanted to delete. You know what they are J 55.8% 60% Cumulative TTI Improvement

Slide 49

Slide 49

Perf Improvements Over Time TTI What you think it was What it actually was Time (months)

Slide 50

Slide 50

Challenges Performance Regressions Time to complete A/B Tests 3rd Party Scripts: Ads, Marketing Tags Cross-team initiatives

Slide 51

Slide 51

PART 3 Guardrails For Performance

Slide 52

Slide 52

Performance Budgets TTFB Speed Index TTI Page Complete

Slide 53

Slide 53

Performance Metrics Per PR Bundle Size check at PR

Slide 54

Slide 54

Performance Metrics Per PR Lighthouse metrics for each PR View perf metrics over time

Slide 55

Slide 55

Compare Metrics Across Branches Teams can compare branch performance to production performance Click through commits and see what caused the degradation Results used to accept or reject release

Slide 56

Slide 56

Sustaining A Performance Culture Embed performance thinking early in the product development process Use tooling and data to help drive decisions on performance tradeoffs Maintain gains by monitoring key metrics, tooling and having guardrails Recognize performance is hard and there will be tradeoffs

Slide 57

Slide 57

The Team Bryan Morgan Denys Mikhalenko Cory Dang Ah Hyun Cho Hiren Patel Madhav Deverkonda Test Armada & Torbit Team Gauri Shankar Rodrigo Delgado Jon Campbell Uma Mahesh Meet Parikh Megha Gupta Patrick Stapleton Vijay Muniswamy

Slide 58

Slide 58

Future Plans 01 Progressive Web App (PWA) 02 Experimenting with alternative UI libraries 03 Streaming SSR 04 Different experiences based on Speed Profiles

Slide 59

Slide 59

Performance Is A Journey, Not A Destination

Slide 60

Slide 60

THANK YOU vasanth_k vasanthk