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

The Surprising Path to a Faster NYTimes.com

The Surprising Path to a Faster NYTimes.com

The current mantra in performance thinking is “Tools not Rules.” The premise is simple: The path to faster websites is not only about fast requests, but how they interact with paints, animations, and script execution. But tools are only part of the solution. What The New York Times discovered is that performance is about truly understanding your product and users, and the sum total of your site. Following this approach can lead to surprising results.

The New York Times underwent a major redesign that involved a rewrite of the entire technology stack. The Product team not only bought into the idea that performance should be a goal, but mandated that it be part of the product’s success. While we implemented many of the community’s best practices, our biggest wins were a little surprising, and at first glance, counter to community best practices. Front-end software architect Eitan Koningsburg covers those changes, what worked, what didn’t, and how we got there.

(Presented at Velocity New York.)

The New York Times Developers

September 16, 2014
Tweet

More Decks by The New York Times Developers

Other Decks in Technology

Transcript

  1. Performance Golden Rule 80-90% of the end-user response time is

    spent on the frontend. Start there. - Steve Souders
  2. Back then... • Static pages ◦ Less processing server-side meant

    faster responses ◦ Very limited caching ◦ Needed a lot of servers to scale ◦ Handled traffic spikes caused by news events
  3. Back then... • Server-side dynamicism via a proprietary language called

    “Context” ◦ HTML macros ◦ Compiled to execute quickly ◦ Execution delegated to special server software ◦ Context server maintained “always on” database connections ◦ It was fast
  4. Back then... • Ultimately switched to PHP ◦ Never could

    match Context for live execution speed ◦ Relegated to server side templating ◦ Context remained to provide dynamic features
  5. We created a monster • Now have over 1 million

    static pages on disk ◦ Only way to change them is to republish them ◦ Would take ~90 days to re-publish all of them ◦ Not feasible to do this for every code change ◦ So we didn’t re-publish at all
  6. Permutations • New variations of page markup created with each

    deployment ◦ Older pages were not updated ◦ Extrapolate over 10 years of development ◦ Smallest code tweak created a lot of technical debt • We have an unknown number of permutations ◦ Maintenance nightmare!
  7. WPO? We tried… • Our unknown number of page permutations

    made optimizing the frontend almost impossible ◦ Combined files together, but couldn’t remove references from older pages ◦ Download sizes increased as we had to support older permutations ◦ Needed low cache TTLs to ensure files got updated in a timely manner • Made things worse, not better
  8. Isn’t that obvious? • Not mentioned often in performance discussions

    ◦ Who would have 1M static pages? • Didn’t become a barrier right away ◦ Not every page we have is intended to live forever ◦ Recent articles receive more traffic than older ones • No practical alternative available ◦ Couldn’t avoid the static page problem
  9. 2013: A Rare Opportunity • Given a product pause to

    fix major infrastructural debt ◦ This doesn’t happen very often (if at all) • Nothing was safe: ◦ Infrastructure ◦ Server configuration ◦ Code organization ◦ Development process ◦ Build process ◦ Deployment process
  10. Going dynamic • Slowly migrating all content into databases •

    Ongoing process ◦ Some things will be dynamic sooner than others • Use Varnish cache to hide backend slowness ◦ We get great TTFB times with Varnish ◦ Simple caching strategy ◦ All per-user customizations pushed client-side
  11. Supported from the top • First project to have a

    performance goal as part of its definition of success • Why all of a sudden? ◦ Performance became a factor in SEO ◦ NYT became an E-Commerce site since last redesign • Conservative goal ◦ A certain percentage faster than the old site ◦ Attainable, but wouldn’t risk shipping the product
  12. Conflicting advice • Basic rules sometimes contradict ◦ Reduce number

    of HTTP requests, but not all the way so you can take advantage of parallel downloads ◦ Combine files together, but soon, with HTTP/2.0 doing so will be less than optimal ◦ Set long cache TTLs, but remove unused code • “Tools, not rules” ◦ Create the product, then inspect, then optimize ◦ Need to have a product first
  13. Fundamental overhaul • RequireJS for non-blocking and asynchronous loading ◦

    One blocking script needed in the head • Modern build system to concatenate and minify files ◦ Automatic sprite atlas creation • New caching strategy ◦ Timestamp in the URL ◦ Inserted dynamically by the backend application ◦ New file downloaded after code push ◦ Far-future cache TTL
  14. Lazy loaded ads • Worthwhile investment • Before the redesign,

    ads were part of the markup and would block rendering ◦ Often the slowest part of our page load • Injected ads into iframes which worked surprisingly well • Minor issue: differences in browsers regarding how to track history in embedded frames • Blogged about this: http://nyti.ms/1qgoJ0b • Allowed us to hit DOMReady really quickly
  15. Don’t move the things • Want to avoid moving content

    around based on the ads • Preferable to show an ad above the fold, if present • If no ad, want to use the space for other content • Bonus: use NYT web fonts to make the headline look like the newspaper ◦ Browsers differ on how to handle text while a font downloads - FOUT • If we were fully asynchronous, the content could shift around during load which looks and feels slow
  16. Initial solution 1. Request the ads synchronously 2. Inspect the

    response to see if there is an ad to draw 3. Add a class to the HTML to determine which layout to show 4. Continue loading the page • Requires an intentionally (!) blocking script to achieve this • While it slowed down the page, things didn’t shift around • The perception mattered more than the numbers
  17. Even better solution • Some of the time, make room

    for an ad ◦ Otherwise, use full width for content • Allows for both goals: ◦ Prevents content shifting ◦ Maximizing ad placement • Ad request can be asynchronous again! • Drawback: sometimes space can be made for an ad that is never served ◦ Tweak the numbers to minimize this
  18. Measure and improve • Smoother animations ◦ Scroll event listeners

    causing jank ◦ Exploring patterns involving requestAnimationFrame ◦ Promoting some of our fixed position elements to the GPU ◦ Optimizing code paths to achieve better FPS ◦ Challenge: requires refactoring large portions of the codebase
  19. Measure and improve • Memory management ◦ We have to

    load a lot of content ◦ Approaching memory limits on some mobile devices ◦ There are a lot of candidates for things retaining too much memory ◦ Challenge: tools are complex but getting better ◦ Challenge: sometimes the memory issue is difficult to track down
  20. Measure and improve • Above-the-fold, critical path optimizations ◦ Inlining

    of critical CSS ◦ Lazy loading of other resources ◦ Keeping 3rd-party code out of <head> ◦ Challenge: editorial desire to put nice interactive material above the fold ◦ Challenge: A/B testing support
  21. Other things we’re following • HTTPS ◦ Interested in using

    HTTPS by default ◦ Huge hurdles to overcome to make this a reality ◦ All that static content is still holding us back • <picture> ◦ Will be a huge help to our responsive site • Web Components ◦ Following development on this closely ◦ Interested in seeing whether this can be used for ads • ServiceWorker (pretty please???) ◦ Better offline access