Monday, January 30, 2017

Netflix Hack Day - Winter 2017



We hosted another great Hack Day event a week ago at Netflix headquarters.  Hack Day is a way for our product development team to take a break from everyday work, have fun, experiment with new technologies, and collaborate with new people.


Each Hack Day, we see a wide range of ideas on how to improve the product and internal tools as well as some that are just meant to be fun.  This event was no different.   We’ve embedded videos below, produced by the hackers, to some of our favorites. You can also see more hacks from several of our past events: May 2016, November 2015, March 2015, Feb. 2014 & Aug. 2014.


While we’re excited about the creativity and thought put into these hacks, they may never become part of the Netflix product, internal infrastructure, or otherwise be used beyond Hack Day.  We are posting them here publicly to share the spirit of the event and our culture of innovation.


Thanks again to the hackers who, in just 24 hours, assembled really innovative hacks.  




Stranger Bling

MDAS (Mobile Demogorgon Alerting System) a.k.a Ugly Christmas Sweater
LEDs soldered to a Stranger Things sweater, controlled wirelessly with an Arduino, spelling out messages from the Upside Down!




MindFlix

Navigate and control Netflix with your mind (with help from a Muse headband).




Netflix for Good

After watching socially conscious titles on Netflix, Netflix for Good allows users to donate to related and well known organizations from inside the Netflix app.




Stranger Games

Stranger Things re-imagined as a home console video game collection created back in 1983, but with a twist.




Picture in Picture

See what other profiles on your account are watching via picture in picture.

Thursday, January 26, 2017

Coming Soon: Netflix Android Bootcamp

Mobile devices have had an incredible impact on people’s lives in the past few years and, as expected, Netflix members have embraced these devices for significant amounts of online video viewing. Just over a year ago, Netflix expanded from streaming in 60 countries to over 190 countries today. In many of our newer countries, mobile usage is outsized compared with other platforms. As Netflix has grown globally, we have a corresponding desire to invest more time and energy in creating great experiences on mobile.


Demand for Android engineers in the Bay Area has only increased over time and great mobile engineers are rare. To help develop great mobile talent, we’re excited to announce that we are sponsoring an upcoming Android bootcamp by CodePath. CodePath runs intensive training programs for practicing engineers who wish to develop knowledge and skill on a new platform (Android in this case).


We have chosen to partner with them for the following reasons:
  1. There are a number of CodePath graduates at Netflix who have demonstrated a thorough understanding of the new platform upon class completion. Each has testified to CodePath’s success as a challenging program that rapidly prepared them for mobile development.
  2. CodePath’s program requires a rigorous demonstration of aptitude and dedication. Both Netflix and CodePath seek excellence.
  3. The CodePath admissions process is blind to gender and race, creating a level playing field for people who are often underrepresented in tech. We share the goal of creating a diverse and inclusive environment for individuals from a variety of backgrounds.


There is no cost for participants to attend. For practicing software engineers, the primary requirement is dedicating your time and energy to learn a new platform. We aim to accept 15 engineers into the program on-site to keep the class size small. Additional seats will be available to remote students.


Sessions will be held at our headquarters in Los Gatos. Classes start March 6, 2017, continuing each Monday and Wednesday evening for 8 weeks. We look forward to having you there to develop your skills on this fun and exciting platform.






By Greg Benson, Android Innovation team

Thursday, January 12, 2017

Crafting a high-performance TV user interface using React


The Netflix TV interface is constantly evolving as we strive to figure out the best experience for our members. For example, after A/B testing, eye-tracking research, and customer feedback we recently rolled out video previews to help members make better decisions about what to watch. We’ve written before about how our TV application consists of an SDK installed natively on the device, a JavaScript application that can be updated at any time, and a rendering layer known as Gibbon. In this post we’ll highlight some of the strategies we’ve employed along the way to optimize our JavaScript application performance.

React-Gibbon

In 2015, we embarked on a wholesale rewrite and modernization of our TV UI architecture. We decided to use React because its one-way data flow and declarative approach to UI development make it easier to reason about our app. Obviously, we’d need our own flavor of React since at that time it only targeted the DOM. We were able to create a prototype that targeted Gibbon pretty quickly. This prototype eventually evolved into React-Gibbon and we began to work on building out our new React-based UI.

React-Gibbon’s API would be very familiar to anyone who has worked with React-DOM. The primary difference is that instead of divs, spans, inputs etc, we have a single “widget” drawing primitive that supports inline styling.

React.createClass({
   render() {
       return <Widget style={{ text: 'Hello World', textSize: 20 }} />;
   }
});

Performance is a key challenge

Our app runs on hundreds of different devices, from the latest game consoles like the PS4 Pro to budget consumer electronics devices with limited memory and processing power. The low-end machines we target can often have sub-GHz single core CPUs, low memory and limited graphics acceleration. To make things even more challenging, our JavaScript environment is an older non-JIT version of JavaScriptCore. These restrictions make super responsive 60fps experiences especially tricky and drive many of the differences between React-Gibbon and React-DOM.

Measure, measure, measure

When approaching performance optimization it’s important to first identify the metrics you will use to measure the success of your efforts. We use the following metrics to gauge overall application performance:

  • Key Input Responsiveness - the time taken to render a change in response to a key press
  • Time To Interactivity - the time to start up the app
  • Frames Per Second - the consistency and smoothness of our animations
  • Memory Usage


The strategies outlined below are primarily aimed at improving key input responsiveness. They were all identified, tested and measured on our devices and are not necessarily applicable in other environments. As with all “best practice” suggestions it is important to be skeptical and verify that they work in your environment, and for your use case. We started off by using profiling tools to identify what code paths were executing and what their share of the total render time was; this lead us to some interesting observations.

Observation: React.createElement has a cost

When Babel transpiles JSX it converts it into a number of React.createElement function calls which when evaluated produce a description of the next Component to render. If we can predict what the createElement function will produce, we can inline the call with the expected result at build time rather than at runtime.


// JSX
render() {
   return <MyComponent key='mykey' prop1='foo' prop2='bar' />;
}

// Transpiled
render() {
   return React.createElement(MyComponent, { key: 'mykey', prop1: 'foo', prop2: 'bar' });
}

// With inlining
render() {
   return {
       type: MyComponent,
       props: {
           prop1: 'foo',
           prop2: 'bar'
       },
       key: 'mykey'
   };
}


As you can see we have removed the cost of the createElement call completely, a triumph for the “can we just not?” school of software optimization.

We wondered whether it would be possible to apply this technique across our whole application and avoid calling createElement entirely. What we found was that if we used a ref on our elements, createElement needs to be called in order to hook up the owner at runtime. This also applies if you’re using the spread operator which may contain a ref value (we’ll come back to this later).

We use a custom Babel plugin for element inlining, but there is an official plugin that you can use right now. Rather than an object literal, the official plugin will emit a call to a helper function that is likely to disappear thanks to the magic of V8 function inlining. After applying our plugin there were still quite a few components that weren’t being inlined, specifically Higher-order Components which make up a decent share of the total components being rendered in our app.

Problem: Higher-order Components can’t use Inlining

We love Higher-order Components (HOCs) as an alternative to mixins. HOCs make it easy to layer on behavior while maintaining a separation of concerns. We wanted to take advantage of inlining in our HOCs, but we ran into an issue: HOCs usually act as a pass-through for their props. This naturally leads to the use of the spread operator, which prevents the Babel plug-in from being able to inline.

When we began the process of rewriting our app, we decided that all interactions with the rendering layer would go through declarative APIs. For example, instead of doing:

componentDidMount() {
   this.refs.someWidget.focus()
}

In order to move application focus to a particular Widget, we instead implemented a declarative focus API that allows us to describe what should be focused during render like so:

render() {
   return <Widget focused={true} />;
}

This had the fortunate side-effect of allowing us to avoid the use of refs throughout the application. As a result we were able to apply inlining regardless of whether the code used a spread or not.


// before inlining
render() {
   return <MyComponent {...this.props} />;
}

// after inlining
render() {
   return {
       type: MyComponent,
       props: this.props
   };
}
This greatly reduced the amount of function calls and property merging that we were previously having to do but it did not eliminate it completely.

Problem: Property interception still requires a merge

After we had managed to inline our components, our app was still spending a lot of time merging properties inside our HOCs. This was not surprising, as HOCs often intercept incoming props in order to add their own or change the value of a particular prop before forwarding on to the wrapped component.

We did analysis of how stacks of HOCs scaled with prop count and component depth on one of our devices and the results were informative.


Screenshot 2017-01-11 12.31.30.png


They showed that there is a roughly linear relationship between the number of props moving through the stack and the render time for a given component depth.

Death by a thousand props

Based on our findings we realized that we could improve the performance of our app substantially by limiting the number of props passed through the stack. We found that groups of props were often related and always changed at the same time. In these cases, it made sense to group those related props under a single “namespace” prop. If a namespace prop can be modeled as an immutable value, subsequent calls to shouldComponentUpdate calls can be optimized further by checking referential equality rather than doing a deep comparison. This gave us some good wins but eventually we found that we had reduced the prop count as much as was feasible. It was now time to resort to more extreme measures.

Merging props without key iteration

Warning, here be dragons! This is not recommended and most likely will break many things in weird and unexpected ways.

After reducing the props moving through our app we were experimenting with other ways to reduce the time spent merging props between HOCs. We realized that we could use the prototype chain to achieve the same goals while avoiding key iteration.


// before proto merge
render() {
   const newProps = Object.assign({}, this.props, { prop1: 'foo' })
   return <MyComponent {...newProps} />;
}

// after proto merge
render() {
   const newProps = { prop1: 'foo' };
   newProps.__proto__ = this.props;
   return {
       type: MyComponent,
       props: newProps
   };
}

In the example above we reduced the 100 depth 100 prop case from a render time of ~500ms to ~60ms. Be advised that using this approach introduced some interesting bugs, namely in the event that this.props is a frozen object . When this happens the prototype chain approach only works if the __proto__ is assigned after the newProps object is created. Needless to say, if you are not the owner of newProps it would not be wise to assign the prototype at all.

Problem: “Diffing” styles was slow

Once React knows the elements it needs to render it must then diff them with the previous values in order to determine the minimal changes that must be applied to the actual DOM elements. Through profiling we found that this process was costly, especially during mount - partly due to the need to iterate over a large number of style properties.

Separate out style props based on what’s likely to change

We found that often many of the style values we were setting were never actually changed. For example, say we have a Widget used to display some dynamic text value. It has the properties text, textSize, textWeight and textColor. The text property will change during the lifetime of this Widget but we want the remaining properties to stay the same. The cost of diffing the 4 widget style props is spent on each and every render. We can reduce this by separating out the things that could change from the things that don't.

const memoizedStylesObject = { textSize: 20, textWeight: ‘bold’, textColor: ‘blue’ };


<Widget staticStyle={memoizedStylesObject} style={{ text: this.props.text }} />

If we are careful to memoize the memoizedStylesObject object, React-Gibbon can then check for referential equality and only diff its values if that check proves false. This has no effect on the time it takes to mount the widget but pays off on every subsequent render.

Why not avoid the iteration all together?

Taking this idea further, if we know what style props are being set on a particular widget, we can write a function that does the same work without having to iterate over any keys. We wrote a custom Babel plugin that performed static analysis on component render methods. It determines which styles are going to be applied and builds a custom diff-and-apply function which is then attached to the widget props.


// This function is written by the static analysis plugin
function __update__(widget, nextProps, prevProps) {
   var style = nextProps.style,
       prev_style = prevProps && prevProps.style;


   if (prev_style) {
       var text = style.text;
       if (text !== prev_style.text) {
           widget.text = text;
       }
   } else {
       widget.text = style.text;
   }
}


React.createClass({
   render() {
       return (
           <Widget __update__={__update__} style={{ text: this.props.title }}  />
       );
   }
});


Internally React-Gibbon looks for the presence of the “special” __update__ prop and will skip the usual iteration over previous and next style props, instead applying the properties directly to the widget if they have changed. This had a huge impact on our render times at the cost of increasing the size of the distributable.

Performance is a feature

Our environment is unique, but the techniques we used to identify opportunities for performance improvements are not. We measured, tested and verified all of our changes on real devices. Those investigations led us to discover a common theme: key iteration was expensive. As a result we set out to identify merging in our application, and determine whether they could be optimized. Here’s a list of some of the other things we’ve done in our quest to improve performance:

  • Custom Composite Component - hyper optimized for our platform
  • Pre-mounting screens to improve perceived transition time
  • Component pooling in Lists
  • Memoization of expensive computations

Building a Netflix TV UI experience that can run on the variety of devices we support is a fun challenge. We nurture a performance-oriented culture on the team and are constantly trying to improve the experiences for everyone, whether they use the Xbox One S, a smart TV or a streaming stick. Come join us if that sounds like your jam!