Netflix: Removing client-side React.js improved performance by 50%
twitter.com
twitter.com
The full talks are available here if people want to watch them:
https://www.youtube.com/watch?v=V8oTJ8OZ5S0&t=11m30s
Thought I'd also provide some more context on some common questions that people have asked.
### Why are you using React to render a landing page?
The Netflix landing page is a lot more dynamic than most people think it is.
It's our most heavily A/B-tested page in the signup flow, with even some machine learning models being used to customize the messaging and imagery that you get depending on location, whether or not you were a previous Netflix member, device type, and a lot more. Even beyond that, Netflix supports almost 200 countries now, and there's a different combination of localization, legal challenges, and value messaging for each one. We end up sharing a lot of the logic and UI for these A/B testing and localization challenges throughout the signup flow, mainly through React components.
The example I always love to give is the <TermsOfUse/> component that we have, which to a Netflix customer signing up is literally one or two checkboxes on the UI, but has some of the most complicated logic in the codebase due to the vast number of countries and user states we support. Because of all this, it's more valuable for us to share these common React components across the entire signup process, both the landing page and the rest of the flow, which is a single-page React and Redux application.
We've seen a lot of conversion value though in improving the performance of the landing page, especially in countries with slower connections, but we don't also want to re-duplicate a lot of the shared UI logic that we have.
The tradeoff that we decided to make is to server-render the landing page using React, but also pre-fetching React / Redux / the code for the rest of the signup flow while on it. This optimizes first load performance, but also optimizes the time to load for the rest of the signup flow, which has a much larger JS bundle size to download since it's a single-page app.
### What's the performance metric that's being used?
It's TTI (Time to Interactive), when the user can fully interact with the page. This is different than TTR (Time to Render) for us, when the user can fully view the page. There's more information in the talk about the differences.
### Why not Service Workers or some other pre-loading / caching mechanism?
We have been experimenting with it, but it's mainly the lack of some browser support - Safari is the main one. Generally the Netflix signup flow needs to have more legacy browser support than the Netflix member experience. Lots of people sign up on a pretty old browser, but only ever watch Netflix on the native mobile apps or a TV device.
#####
Feel free to comment here or tweet at Tony (https://twitter.com/tedwards947) or me (https://twitter.com/clarler) if there's any other questions that we can help answer.
Though from a lot of experience, 140 characters isn't always enough to provide enough context for JavaScript framework discussions. ;)
If these sort of performance and UI challenges seem interesting to you, our team is also hiring for UI engineers and an engineering manager!
* Senior Software Engineer (React, Node): https://jobs.netflix.com/jobs/864767
* Senior Software Engineer (Android): https://jobs.netflix.com/jobs/864766
* Engineering Manager: https://jobs.netflix.com/jobs/865119
Cheers!
I'd love to sit and talk React with you and your team. We're always particularly interested in performance optimizations so maybe we can swap some knowledge.
Not aware of any team that is actively avoiding React but we're a fairly prolific bunch when it comes to public speaking and knowledge sharing so perhaps I missed some announcement from another UI team. A few of my colleagues will be speaking at the SFHTML5 meetup[1] in a few weeks if you'd like to come hang out and talk shop or feel free to drop me a line at jem@netflix.com :).
Did I miss something? I see some `measureLifecycleperf` functions in the react source but those look like dead ends.
It's not React that's slow, it's the logic needed to render the page?
1- https://www.youtube.com/watch?time_continue=1297&v=M1qm-AWWu...
I think the win here is less about react and more about not running as much javascript on the client. I hypothesize that the traces will show this, but it is impossible to know for sure without them :)
Thanks in advance!
There was nothing personal or malicious in that slide at all. Do we need a safe space to talk about performance metrics now?
Why should any more work be put into keeping React or improving it if their solution of removing it entirely already works?
It doesn't "work", it's a hack.
50% isn't data. It's a claim without evidence. The evidence in this case may help fix React.
Does it really matter how much JS there is if it's loaded after HTML and the user can already move to the sign up step without it?
And going to the front page of Netflix, clicking the Search icon is not a pretty experience. What happens next is a chuggy chuggy animation of the textbox gliding out, and typing in it is a disaster of input lag.
I bet you fire an event for each key I press while in there? Perhaps wait with that until the rest of the page has loaded?
Do you simply use Nodejs to do the SSR? I've seen some complaints about the difficulty of scaling node to run well in a cluster, and about security things. Have you had to deal with that?
I'd honestly love to see what you did there. People use Java for the reason that all of those questions have decent answers by now.
Last year, I was building a simple SVG based chart dashboard for internal usage. Being a NoJS guy, I would sometimes disable JS while developing, on purpose or otherwise, and aside from forcing me to manually hit refresh in the browser, things generally worked. I added a couple links (styled as buttons) for zooming, to supplement the JS based drag-window zoom, and let the browser scroll the potentially very wide SVG chart within a div. If necessary, I could have even embedded the whole thing in an iframe, to avoid triggering whole page reloads, but our caching story was tight enough to compensate. Also, the React-rendered SVG represented the bulk of the markup on the page anyway.
Interactive visualisation, no JS needed. It added maybe an extra 10% to my workload (we already had the SSR stack), and helped me to avoid a variety of little glitches that plague many client-only apps, glitches that users learn to tolerate with mild disgust. The satisfaction of seeing our in-house dashboard pop up "instantly" with data, while Parsely and New Relic were still churning spinners or stuttering while waiting on JS, or even waiting for initial data after waiting on JS, was very cathartic. TTI can equal TTR, we have the technology, we've had it for a decade or so.
Every country has different regulations, and therefore would require different wording and agreements as a Terms of Use. Anyone that has worked at a multi-national company understands this is just The Way It Is.
At Nike there is a ton of logic on a per-country basis. For example, they might own the copyright of the word "FlyKnit" in most countries, but in Italy they don't and get fined if it's ever misused. There's a TON of development work that caters to legal / regulation problems like this.
It was enlightening. The size of your front-end application is generally dominated by view code. So, they precompile views into a super simple set of binary VM instructions (making your views very compact). These views don't go through the JS compile / parse phase on the client (saving hundreds of ms, up to seconds on slow devices). They are instantly executable by a small VM written as a JS library, and can be streamed in and rendered as they arrive (the way plain ol' HTML pages do). Turns out to be hella fast, but still gives the benefit of rich client-side rendering capabilities.
In a nod to The Net, you can click the π symbol in the bottom right corner where you'll get a debug view of the disassembled binary bytecode.
Edit: so does Vue if you're using vueify (https://github.com/vuejs/vue/issues/4272).
What Glimmer does is it converts your views into bytecode (not JavaScript) which can be streamed and run without a JavaScript compilation / parsing phase in the browser. Vue, React, and Angular views all ultimately are translated into JavaScript which has to be compiled / parsed in each browser.
Guess you have download the VM on initial page load.
Word of advice / wisdom from having built multiple platforms / sites with it:
Don't.
I think this is a fairly common use case for server-side rendering in React and I wonder how much of this improvement they would have seen just by SSRing the page and putting the React scripts at the end instead of the header (or using defer). This is the strategy I use with any React marketing type pages.
Edit:
Just to give more detail incase anyone is wondering, usually marketing pages are relatively the same for every user (unless you are doing identity based personalization or a/b testing) so often you can get away with pre-rendering all the HTML generated by the React. Then you don't even need to load React server side, you just serve up a static file.
I'm always amazed at those devs who load entire applications framework when their end goal is to have a slider at the top of a page.
Sorry for being sarcastic but don't you also find this too obvious?
Thought I'd share a bit more context on the reasons that we did this beyond a picture from a tweet:
https://news.ycombinator.com/item?id=15568305
Let me know if you have any questions!
Also, that 50% is only measuring the time to interactive on what I imagine is the first page visit. After everything becomes cached, I would think that the the benefit is dramatically lower.
So, the developer experience trumps the user experience, in an industry where fractions of a second of load time can cost a company customers and conversions?
Landing Page: Make it load instantly so that a new user clicking on it doesn't get frustrated and close the window before it's ready to go. This is typically a static page. Note the tiny and heavily optimized google.com
Other Pages: It's sometimes necessary to load larger js libs gradually, but generally once they are loaded the browser cache makes their size a non-issue.
In summary: It's worthwhile to pay the cost of libraries, but that cost should not be paid by visitors to the landing page, and if the cost is high it might be necessary to load them in phases to preserve a good UX.
And yes, I've seen a lot of landing pages which are not viewable, let alone interactable, for 5+ seconds, an effect exacerbated by mobile.
Ultimately many businesses will sacrifice polish and dev testing for features and deadlines on the skull-encrusted alter of short sprint cycles and rapid iteration.
Does React really eliminate the potential for buggy implementations? Also I'm fairly certain that UX has more to do with design than your choice of frameworks.
Now, we reviewed a handful of iOS/Android abstractions, and React Native seemed competent - so we're using it for our first pass. Likely, we'll use it for the web frontend too, because we're using React Native. More familiarity can be a good thing.
As I discussed internally when we were choosing frameworks, if I was just choosing a web frontend it would never be React. It's not that I think React is bad, it's just that there are a dozen frameworks similar to it that are faster. It popularized a new good idea (vdom), but it's just not best in breed imo. Yet, having the same concepts and very similar codebase between mobile apps and frontend is a pretty big deal for us.
I think it's smart to include performance requirements in your specifications before starting a project (or when taking on the maintenance of one too). Set an upper limit on your TTI or server response times. Turn it into a budget. That's not optimization that's just engineering.
Not to mention that some infrastructure choices make it really hard to optimize later, if not impossible (sans re-writes).
Also worth noting: the phrase "Premature optimization is the root of all evil" had a very different connotation when first uttered:
https://medium.com/@okaleniuk/premature-optimization-is-the-...
http://ubiquity.acm.org/article.cfm?id=1513451
http://www.joshbarczak.com/blog/?p=580
http://scottdorman.github.io/2009/08/28/premature-optimizati...
It's basically an excuse to not think about the performance or implementation of your entire product until the end and then, when you use a profiler and chop away "10%" here and "20%" there, you still end up with a slow-as-piss program with every function taking less than 1% total time. Then what do you do?
Oh yeah, what you should have done in the first place. _Think_ about how your program actually functions so you can remove all of the insane systemic, architecture decisions you made that all bleed a fixed amount of time every single function call. That's the difference between an engineer, and script kid. If you're not reasoning about _the entire platform_ (all the way down to the cache lines), you're not engineering. You can abstract all you want, but those abstractions don't magically prevent the underlying hardware and architectural decisions from affecting the product. Abstractions tools (read: approximations!) for high-level reasoning. They're not magic "you don't have to think [about low level implementation]" spells.
Actual experts keep trying to warn you guys about abusing that quote, but nobody apparently ever listens. Stop quoting it like a bible verse, because just like bible verses, everyone forgets the entire context and just uses it like a bloody bumper-sticker slogan.
In the words of Saul Williams: "You have wandered too far from the original source, and are emitting a lesser signal."
The full Donald Knuth quote:
>The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.
That quote sounds much less like a law handed down by God, and more a guideline from experience, no?
Optimizing the wrong things (things that get thrown away when you change your program as you work toward your goal) ends up wasting time. But just because that was applicable _in the 70's_ doesn't mean modern programmers have the same mentality of "optimize optimize optimize." Modern programmers have the opposite. They're so afraid of having to learn how cachelines work, they use that quote to prevent having to do any optimization (or understanding of architectural layout tradeoffs). I can't count how many programmers I've met that hear "cache" and their eyes glaze over like it's some magical, incalculable thing.
Watch a lecture from Mike Acton, where on consoles, they don't have the luxury of writing poorly written, un-optimized code. They _do_ have to understand the entire platform to ship a competitive title. Because any optimizations they do, for a fixed platform, means they can pump out a better experience with those extra CPU cycles. An experience that elevates them above their competitors.
A rather unnecessary statement, don't you think?
> This is for a single, static landing page.
Which at one point wasn't a static landing page. Netflix has something of a captive market at this point in time; but could a newer startup scrambling to gain users afford to make the same choices?
If I'm not particularly interested, I'm not going to wait around for mountains of JS to download and execute, and the typical content-free startup landing page full of hero images, stock photos, and vague bullet points to load up.
Please don't break the HN guidelines by being uncivil. Your comment would be much better without that bit.
If this comment section is any clue, clearly it's not going to change a React programmers opinion because they completely loose their shit if you mention a flaw in React.
React is designed to allow a server-side render and an async load of the js library to allow it to be used in this kind of scenario without impacting perceived load time or "time to interaction".
If we pay attention to how bloated most web pages are, it seems it is not obvious at all.
> Removing an advanced library
They made it clear they didn't remove the library. They still load it later, and still use it.
> from a simple project
They make it clear it's not a simple project. In fact, it's probably one of the more complex pieces of the project.
> increases performance.
No, it increased specific metrics that they cared about.
> Sorry for being sarcastic but don't you also find this too obvious?
Your comment, or their results? Your comment is incorrect based on a single slide and taken out of context. As for the actual reasons, no, they are not obvious at all. Incredibly intelligent people didn't find it obvious, as this was something they clearly didn't see at the beginning, and instead relied on measurements.
Premature optimization and all that.
The library that slow down the UX terribly is "advanced" while the project that is being the victim is "simple".
React on a landing page sounds like an overkill to begin with.
Seems like with this speed JS frameworks are going full-circle back to back-end rendering soon enough.
And so the cycle continues, with old ideas dusted off or rediscovered, the original flaws in them rediscovered, the reaction to those flaws, traveling well-trodden paths, then the reaction to the reaction, "best practices" shaking out, an explosion of complexity, and then someone burns down the baroque cathedral of ideas with, if we're lucky, a slightly less flawed version of the original old idea.
I've now done ASP.NET long enough to see WebForms come in, reach high tide, recede before the new hotness of MVC, MVC decline in favor of WebApi with monstrosities of JS frameworks in front of it, and now Razor Pages are coming back in as a simpler alternative, with concepts that an old WebForms developer from fifteen years ago wouldn't raise an eyebrow at.
I really like .NET Core but this RazorPages is just single worst "improvement" for the .NET Core platform.
I even remember watching the presentation on BUILD conference and nobody applauded at this "feature" when they graciously introduced it and you could feel the cringe. Scott even had to say "Isn't this awesome!?? Come on!".
No, Scott, it's not awesome. It's going backwards.
As some people who have been paying attention said from day one: other than the component model and unidirectional data flow, what makes React stand out is that it's ultimately a way to describe a UI in terms of functions that output a component tree. Whether you apply that component tree to the browser DOM or use it to generate static markup makes no difference (or to glue together native components as with React Native).
A lot of the more complex features only make sense in an interactive context (i.e. when rendering in the browser) but React is a great choice for server-side rendering too. And unless your initial rendering logic is as complex as the Netflix landing page's and the interaction logic is as trivial, you can just hydrate what the server spits out and go on from there.
The difference is that historically we used one code base to generate the initial markup and another to breathe life into it. With React we can do both with the same code. And in this case Netflix just skips the client-side rendering in favour of a tiny bit of JS (which means they're still using the same language which is still better than the mess we had in the early '00s).
The statement was meant to provoke people, and honestly if it wasn’t Netflix nobody would give a damn. Because the real headline is “We chose the wrong tool for the job! Even pros make mistakes”.
We avoid fancy tools as much as possible and use basics as much as possible.
Laravel + Bootstrap + JQuery + MySQL works pretty well then this modern stuff.
Easy to implement, deploy and manage.
P.S. Use knife which you really need. Try to use simple knife as much as possible.
It's interesting to remember that Facebook started out as a PHP application. I imagine that Facebook's original tech stack closely resembled the stack you're recommending. And scaling that stack is what led to the creation of React. If you choose to build a rich user interface (like Facebook or Netflix) on top of that stack, you will likely find yourself creating abstractions to manage the complexity. Those abstractions will be equivalent in their utility to React, Ember, Angular, etc.
I agree that a website does not always need or benefit from a React or an Ember. Small dynamic behaviors behaviors can be implemented with less powerful tools. But, the power of your abstractions will need to scale with the complexity of your UI behavior. That's why, at a certain point, the abstractions provided by React _are_ the right choice and jQuery is not.
Regardless, the slide featured in this tweet does not comment on React working or not working well. As they say in a reply to that tweet, the application still loads React and renders React components. What they are presenting is an interesting optimization that has to do with the unique performance constraints of Netflix's UI.
I've built both SPA and traditional fullstack applications similar to the mentioned architecture (although I prefer Python over PHP).
Fullstack is a fraction of the complexity, with much more power. You can even use a simple library like PJAX to get all the same speed boosts an SPA offers without introducing any of the additional complexity.
To be honest, I don't see what React offers beyond what you get with a templating language like Handlebars, and a few lines of jQuery for initializing components.
This is, of course, for database heavy applications where each action requires the backend. If you're building a game, or an app that's mostly offline, SPA can be helpful.
Having worked on a ui in this setting, built with erb, jquery, and pjax... It is not about the degree of difficulty building it, but extending/modifying it, and collaborating with multiple crews in the same codebase. These are problems enough teams have experienced that they have moved away from the approach of jquery+handlebars.
Now granted, SPAs have a bandwagon effect because of where the job opportunities are, so you get people using them not to solve those problems, but to align their technical skills with employable skills.
There's just inherent complexity in software, so it's like suggesting that you built an application without ever writing code outside of main() (functions are for hipsters).
An example of how I put together a component is here https://github.com/IEMLdev/Intlekt-editor/blob/master/src/sc...
- My "view" function takes a template string and replaces the node's content whenever "render" is triggered.
- I create a "model" object which triggers a "render" event anytime it changes. You can also give the model object methods which act as Redux-style reducers.
- The controller method is a shorthand for registering multiple jQuery events at once.
That's pretty much all you need for a complex app. It's the entire React-Redux architecture à la jQuery + ES6.
If that's "just jQuery", then React is "just ES6". I don't understand the distinction. Every abstraction is built on the layer below. You just rolled your own bespoke one instead of using one that already existed.
> I don't see what React offers beyond what you get with a templating language like Handlebars, and a few lines of jQuery for initializing components.
You say that like that's all your framework does, but I see more than that.
Seems you're mistaking different trade-offs for objective improvements, something that almost rarely exists in software despite what you read in HN comments.
There's no need for a vdom for the most part, template strings and innerHTML are fast enough on their own.
I just find React to be an overly complicated way to achieve its goals.
var model = { text: '' }
var component = $( '.component' ).on( 'render', function() {
$(this).html( `<div>${ model.text }</div>` )
})
update( 'text', 'Hello world' )
function update( key, val ) {
model[ key ] = val;
component.trigger( 'render' )
}
That's React in 8 lines of jQuery. My framework is just a minor extension to this concept.No sir, that doesn't include server side rendering or diff rendering either (meaning changing a bit on the top component would re render all markup, not just what has changed)
Stop trying to over-simplify. The problem being discussed here is not React vs jQuery. It's what we do and the decisions we make as engineers to provide a good experience based on performance which is OUR side of UX.
I'm not convinced by arguments such as "when you're a large team it's necessary". Scaling teams has more to do with project structure than what rendering library you use.
Likewise, it's much easier to tweak performance when you aren't depending on a monolith like React or Angular.
And you've created your own abstraction beyond "jquery bits for each component".
This is proper vanillaJS engineering, I do the same, it's just not what you're selling here.
I prefer to keep my abstractions simple and light, and preferably built using lower level libraries. If I can build a powerful component system in 150 lines of jQuery (and it would be barely more in vanilla js), I much rather do that than than import a 30kb + library.
There are plenty of 4kb react alternatives to choose from. Most with vastly simpler APIs. Choo.js or Mithril come to mind :)
It sounds like the sites you've worked on didn't have enough UI complexity to make something like React necessary. Even for a relatively simple admin or dashboard type site, using a more modern framework/library will make it much easier to build and maintain.
What constitutes their landing page? The un-authenticated page or the authenticated page? If the latter, is the page with all the title art cards?
Anybody know how drop-in this is for existing react code ?
Not a chance that they were just, you know, using it wrong?
If you have a substantive point to make, make it thoughtfully; if you don't, please don't comment until you do.
This project did not go well. It took months to develop, has 0 test coverage, numerous bugs and doesn't work on edge or IE and isn't rendered on the server so it's a bad experience.
Everyone on the team was either fired or quit less than 6 months after it launched.
After evaluating the level of effort it would take to get the code base in a maintainable state, it was decided to migrate it over to a more traditional stack (plain js, static html, html forms) and that was completed in less than 2 weeks. Customer metrics across the board also improved.
The lesson here is to use the appropriate technology for the appropriate problem. Unless your application is very complex, requires real-time updates and you can afford the extra maintenance costs -- react is probably the wrong choice.
Which is not to say I'm not sympathetic to bandwagoning having a negative impact on engineering teams. Just that in this case, I find it hard to believe that react specifically was the problem.
I've only done very basic web development during my career, and absolutely no javascript. But, I've been learning React for a week or so and that's something I could do in a few minutes. 6 months is insane, hyperbolic, and probably untrue.
If that team took 6 months to develop such a simple site with a framework that basically does everything for you, I'd fire them all, too. I guarantee the problem was not with the framework.
...that actually exists? Seems crazy.
> My experience with React has not been good.
Certainly from your story it sounds like you had a bad experience, but it seems to be in the "had a bad experience with a hammer, terrible for hammering in screws" type of experience.
As if ThreeJS is too hard or cumbersome without React.
Or this: https://github.com/FormidableLabs/react-game-kit
Or this: https://www.npmjs.com/package/react-audio (a relatively unknown library, but it's surprising how often projects will import packages like this)
I generally do what I can to avoid software snobbery, but it's examples like those that really cause me to scratch my head and exclaim "Why?"
React makes sense when you actually have a DOM to deal with, but as soon as you start trying to write something that goes beyond that model, well, I really don't get you. ("you" being rhetorical)
Generally, though, I think a lot of junior programmers or those new to React get very enthusiastic about it and try to solve whatever problem they can with a tool that works well for them, and that does speak quite a bit to how good React is. In general, I would avoid using React for things it was not designed for.
> It took months to develop, has 0 test coverage, numerous bugs and doesn't work on edge or IE and isn't rendered on the server
This has nothing to do with React and everything to do with implementation. It does not take months to develop a dozen pages in React. React makes test coverage easier to write, works cross platform and supports server side rendering.
While I agree that using React everywhere is a dumb choice, so is ruling out a technology because your company implemented it horribly.
What's interesting is that, despite regurgitating the writing on the wall, OP still blames a JavaScript framework.