SlideShare a Scribd company logo
Scaling A/B testing 
on Netflix.com with 
_________ Alex Liu 
@stinkydofu
data driven 
product development
[NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
[NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
[NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
Test 1 Test 2 Test 3 Test 4 Test 5 Test 6 Test 7 
A 
B 
C 
D 
E 
F 
G 
A 
B 
C 
D 
E 
F 
G 
A 
B 
C 
D 
E 
F 
G 
A 
B 
C 
D 
E 
F 
G 
A 
B 
C 
D 
E 
F 
G 
A 
B 
C 
D 
E 
F 
G 
A 
B 
C 
D 
E 
F 
G
2,097,152 
unique experiences across 
seven tests
hundreds 
of new A/B tests per year
43351892955034 
94860861172181 
85493567650… 
72061153709996
2105 566 685 
templates CSS JS
2.5M 
unique packages 
every week
problem: 
conditional dependencies
Packaging
[NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
oldSearch 
app.js 
newSearch 
dep1 dep2 dep3 dep4 dep5 
sub-dep sub-dep sub-dep sub-dep sub-dep sub-dep
oldSearch 
app.js 
newSearch 
dep1 dep2 dep3 dep4 dep5 
sub-dep sub-dep sub-dep sub-dep sub-dep sub-dep
app.js 
import jquery from 'jquery'; 
import oldSearch from 'oldSearch'; 
import newSearch from 'newSearch'; 
export ...
oldSearch 
app.js 
newSearch 
dep1 dep2 dep3 dep4 dep5 
sub-dep sub-dep sub-dep sub-dep sub-dep sub-dep
[NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
685 files…? 
2.5M packages…?
oldSearch 
app.js 
newSearch 
dep1 dep2 dep3 dep4 dep5 
sub-dep sub-dep sub-dep sub-dep sub-dep sub-dep
problem: 
conditional dependencies
[NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
build request
require('nf-include-when')
oldSearch.js 
/* 
* @includewhen rule.notInNewSearch 
*/
newSearch.js 
/* 
* @includewhen rule.inNewSearch 
*/
anatomy of a rule 
var Rule = require('nf-rule-infrastructure'), 
inNewSearch; 
inNewSearch = new Rule('inNewSearch', function(context, cb) { 
var test = context.abtests.get(1534); 
cb(test && test.cell(1)); 
}); 
module.exports = inNewSearch;
require('nf-asset-registry')
app.js 
import jquery from 'jquery'; 
import oldSearch from 'oldSearch'; 
import newSearch from 'newSearch'; 
export ...
app.js 
jquery 
oldSearch.js 
newSearch.js 
registry
"app.js": { 
"deps": [ 
"jquery", 
"oldSearch.js", 
"newSearch.js", 
], 
"depsFull": [ 
"jquery", 
"oldSearchDep2.js", 
"oldSearchDep1.js", 
"oldSearch.js", 
"newSearchDep2.js", 
"newSearchDep1.js", 
"newSearch.js" 
], 
"fileSize": "4.41 kB", 
"fileSizeFull": "120.52 kB" 
}
"newSearch.js": { 
"rule": "inNewSearch", 
"deps": [ 
"jquery", 
"newSearchDep2.js", 
"newSearchDep1.js", 
], 
"depsFull": [ 
"jquery", 
"newSearchSubDep3.js", 
"newSearchSubDep2.js" 
"newSearchSubDep1.js" 
"newSearchDep2.js", 
"newSearchDep1.js" 
], 
"fileSize": "10.41 kB", 
"fileSizeFull": "40.52 kB" 
} 
nf-include-when
require('nf-packager')
var packager = require('nf-packager'), 
includeWhen = require('nf-include-when'), 
registries = require('nf-asset-registry'); 
function getScriptUrl() 
return packager.getPackageDefinition('app.js', 
registries, 
includeWhen); 
}
"app.js": { 
"deps": [ 
"jquery", 
"oldSearch.js", 
"newSearch.js", 
], 
"depsFull": [ 
"jquery", 
"oldSearchDep2.js", 
"oldSearchDep1.js", 
"oldSearch.js", 
"newSearchDep2.js", 
"newSearchDep1.js", 
"newSearch.js" 
], 
"fileSize": "4.41 kB", 
"fileSizeFull": "120.52 kB" 
} 
Step 1: 
Get the full dependency tree for the 
requested package from the registry.
[ 
"jquery", /* no rule */ 
"oldSearchDep2.js", /* no rule */ 
"oldSearchDep1.js", /* no rule */ 
"oldSearch.js", /* rules.notInNewSearch */ 
"newSearchDep2.js", /* no rule */ 
"newSearchDep1.js”, /* no rule */ 
"newSearch.js" /* rules.inNewSearch */ 
] 
Step 2: 
Determine which files have rules.
[ 
"jquery", /* no rule */ 
"oldSearchDep2.js", /* no rule */ 
"oldSearchDep1.js", /* no rule */ 
"oldSearch.js", /* rules.notInNewSearch */ 
"newSearchDep2.js", /* no rule */ 
"newSearchDep1.js”, /* no rule */ 
"newSearch.js" /* rules.inNewSearch */ 
] 
Step 3: 
Run the rules. Filter out all deps that 
resolved false. 
✓
[ 
"jquery", /* no rule */ 
"oldSearchDep2.js", /* no rule */ 
"oldSearchDep1.js", /* no rule */ 
"oldSearch.js", /* rules.notInNewSearch */ 
"newSearchDep2.js", /* no rule */ 
"newSearchDep1.js”, /* no rule */ 
"newSearch.js" /* rules.inNewSearch */ 
] 
Step 4: 
Filter out all extraneous 
sub deps. 
✓
Step 5: 
Concatenate the files. 
[ 
"jquery", /* no rule */ 
"newSearchDep2.js", /* no rule */ 
"newSearchDep1.js”, /* no rule */ 
"newSearch.js" /* rules.inNewSearch */ 
]
build 
javascript 
registry
request registry 
packager rules
Bonus Round
be creative 
with the registry
"account/bb/models/ratingHistoryModel.js": { 
"rule": null, 
"deps": [...], 
"depsFull": [...], 
"depsCount": { 
"underscore": 2, 
"backbone": 1, 
"jquery": 2, 
"common/requirejs-plugins.js": 4, 
"requirejs-text": 4, 
"utils/contextData.js": 1, 
"common/nfNamespace.js": 1 
}, 
"hash": "dd23b163", 
"fileSize": "1.21 kB", 
"fileSizeFull": "173.04 kB" 
} 
dependency 
counting 
dependency 
pruning 
file sizes
@import modules 
@import (reference) "/common/_nf_defs.less"; 
@import (reference) "/member/memberCore.less"; 
@import (reference) "/components/menu.less"; 
@import (reference) "/components/breadcrumbs.less";
"account/containerResponsive.css": { 
"rule": null, 
"deps": [...], 
"depsFull": [...], 
"depsCount": [...], 
"hash": "65a431f3", 
"fileSize": "709 B", 
"fileSizeFull": "709 B", 
"css": { 
"selectors": 8, 
"declarationBlocks": 6, 
"declarations": 17, 
"mediaQueries": 3 
} 
} 
css 
analysis
the 
best part
"cache": { 
"account/pin.js": "define('account/pin.js', ['member/memberC…", 
"account/bb/models/changePlanModel.js": "define('account/b…", 
"account/bb/models/ratingHistoryModel.js": "define('account…", 
"account/bb/models/viewingActivityModel.js": "define('account…", 
"account/bb/views/changePlanView.js": "define('account/bb/vi…", 
"account/bb/views/changePlanView.js": "define('account/bb/vi…", 
"account/bb/views/emailSubView.js": "define('account/bb/views…", 
"account/bb/views/viewingActivityView.js": "define('account…", 
"common/UITracking.js": "define('common/UITracking.js, ['me…", 
"common/UITrackingOverlay.js": "define('common/UITrackingOve…", 
… 
… 
…
templates templates 
mappings 
javascript 
css 
mappings 
javascript 
css
templates 
mappings 
javascript 
css 
UI Bundle
[NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
deploy UI bundles 
anytime
never 
touch the file system
< 5ms 
package response times
Takeaways 
▶ leverage the server 
▶ static analysis FTW 
▶ divide and conquer with modules
Our Learnings
learn by doing
fail fast 
move faster
“I have not failed. 
I’ve just found 10,000 ways 
that won’t work.” 
Thomas Edison
simplify
thanks! come find us! 
Alex Liu 
@stinkydofu 
Chris Saint-Amant 
@csaintamant 
Micah Ransdell 
@mjr578 
Kris Baxter 
@kristoferbaxter

More Related Content

PDF
Elasticsearch und die Java-Welt
PDF
Google App Engine Developer - Day4
PDF
mongoDB Performance
PDF
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
PDF
10 Key MongoDB Performance Indicators
PDF
New in MongoDB 2.6
PDF
아파트 정보를 이용한 ELK stack 활용 - 오근문
PDF
MongoDB Performance Tuning
Elasticsearch und die Java-Welt
Google App Engine Developer - Day4
mongoDB Performance
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
10 Key MongoDB Performance Indicators
New in MongoDB 2.6
아파트 정보를 이용한 ELK stack 활용 - 오근문
MongoDB Performance Tuning

What's hot (19)

KEY
Couchdb: No SQL? No driver? No problem
PPTX
Getting Started with MongoDB and NodeJS
PPTX
Mongo Sharding: Case Study
PDF
MySQL under the siege
DOCX
Book integrated assignment
PDF
VBA API for scriptDB primer
PDF
Getting Started With #Drools 6 Slides - JBUG Denmark
PDF
Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...
PPTX
MongoDB Roadmap
PDF
Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...
PDF
ニコニコ動画を検索可能にしてみよう
PDF
Java Persistence Frameworks for MongoDB
PDF
Apache CouchDB talk at Ontario GNU Linux Fest
PPTX
Webinar: Building Your First App in Node.js
PDF
Whats new in mongoDB 2.4 at Copenhagen user group 2013-06-19
PDF
Redis
PPTX
Elasticsearch 설치 및 기본 활용
PPTX
Building .NET Apps using Couchbase Lite
PDF
Replacing Oracle with MongoDB for a templating application at the Bavarian go...
Couchdb: No SQL? No driver? No problem
Getting Started with MongoDB and NodeJS
Mongo Sharding: Case Study
MySQL under the siege
Book integrated assignment
VBA API for scriptDB primer
Getting Started With #Drools 6 Slides - JBUG Denmark
Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...
MongoDB Roadmap
Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...
ニコニコ動画を検索可能にしてみよう
Java Persistence Frameworks for MongoDB
Apache CouchDB talk at Ontario GNU Linux Fest
Webinar: Building Your First App in Node.js
Whats new in mongoDB 2.4 at Copenhagen user group 2013-06-19
Redis
Elasticsearch 설치 및 기본 활용
Building .NET Apps using Couchbase Lite
Replacing Oracle with MongoDB for a templating application at the Bavarian go...
Ad

Similar to [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js (20)

PPTX
Netflix JavaScript Talks - Scaling A/B Testing on Netflix.com with Node.js
PPT
jQuery Objects
KEY
[Coscup 2012] JavascriptMVC
PPTX
Js tacktalk team dev js testing performance
PDF
Buildingsocialanalyticstoolwithmongodb
PDF
The new static resources framework
PDF
前端MVC之BackboneJS
PDF
The Heron Mapping Client - Overview, Functions, Concepts
PPT
Comprehensive Browser Automation Solution using Groovy, WebDriver & Obect Model
PDF
Everything as a Code / Александр Тарасов (Одноклассники)
PDF
Everything as a code
PDF
How to make Ajax Libraries work for you
PPTX
Webpack | Jakub Kulhan - Skrz.cz
PDF
Apache Calcite Tutorial - BOSS 21
PDF
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
PDF
Assetic (OSCON)
PDF
Specification-Driven Development of REST APIs by Alexander Zinchuk
PPTX
Harder, Better, Faster, Stronger
PDF
Webpack Encore - Asset Management for the rest of us
Netflix JavaScript Talks - Scaling A/B Testing on Netflix.com with Node.js
jQuery Objects
[Coscup 2012] JavascriptMVC
Js tacktalk team dev js testing performance
Buildingsocialanalyticstoolwithmongodb
The new static resources framework
前端MVC之BackboneJS
The Heron Mapping Client - Overview, Functions, Concepts
Comprehensive Browser Automation Solution using Groovy, WebDriver & Obect Model
Everything as a Code / Александр Тарасов (Одноклассники)
Everything as a code
How to make Ajax Libraries work for you
Webpack | Jakub Kulhan - Skrz.cz
Apache Calcite Tutorial - BOSS 21
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
Assetic (OSCON)
Specification-Driven Development of REST APIs by Alexander Zinchuk
Harder, Better, Faster, Stronger
Webpack Encore - Asset Management for the rest of us
Ad

Recently uploaded (20)

PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
L1 - Introduction to python Backend.pptx
PDF
AI in Product Development-omnex systems
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
top salesforce developer skills in 2025.pdf
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
How to Choose the Right IT Partner for Your Business in Malaysia
VVF-Customer-Presentation2025-Ver1.9.pptx
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
How Creative Agencies Leverage Project Management Software.pdf
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Which alternative to Crystal Reports is best for small or large businesses.pdf
L1 - Introduction to python Backend.pptx
AI in Product Development-omnex systems
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
top salesforce developer skills in 2025.pdf
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Navsoft: AI-Powered Business Solutions & Custom Software Development
Design an Analysis of Algorithms I-SECS-1021-03
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PTS Company Brochure 2025 (1).pdf.......
Wondershare Filmora 15 Crack With Activation Key [2025

[NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js

  • 1. Scaling A/B testing on Netflix.com with _________ Alex Liu @stinkydofu
  • 2. data driven product development
  • 6. Test 1 Test 2 Test 3 Test 4 Test 5 Test 6 Test 7 A B C D E F G A B C D E F G A B C D E F G A B C D E F G A B C D E F G A B C D E F G A B C D E F G
  • 7. 2,097,152 unique experiences across seven tests
  • 8. hundreds of new A/B tests per year
  • 10. 2105 566 685 templates CSS JS
  • 11. 2.5M unique packages every week
  • 15. oldSearch app.js newSearch dep1 dep2 dep3 dep4 dep5 sub-dep sub-dep sub-dep sub-dep sub-dep sub-dep
  • 16. oldSearch app.js newSearch dep1 dep2 dep3 dep4 dep5 sub-dep sub-dep sub-dep sub-dep sub-dep sub-dep
  • 17. app.js import jquery from 'jquery'; import oldSearch from 'oldSearch'; import newSearch from 'newSearch'; export ...
  • 18. oldSearch app.js newSearch dep1 dep2 dep3 dep4 dep5 sub-dep sub-dep sub-dep sub-dep sub-dep sub-dep
  • 20. 685 files…? 2.5M packages…?
  • 21. oldSearch app.js newSearch dep1 dep2 dep3 dep4 dep5 sub-dep sub-dep sub-dep sub-dep sub-dep sub-dep
  • 26. oldSearch.js /* * @includewhen rule.notInNewSearch */
  • 27. newSearch.js /* * @includewhen rule.inNewSearch */
  • 28. anatomy of a rule var Rule = require('nf-rule-infrastructure'), inNewSearch; inNewSearch = new Rule('inNewSearch', function(context, cb) { var test = context.abtests.get(1534); cb(test && test.cell(1)); }); module.exports = inNewSearch;
  • 30. app.js import jquery from 'jquery'; import oldSearch from 'oldSearch'; import newSearch from 'newSearch'; export ...
  • 31. app.js jquery oldSearch.js newSearch.js registry
  • 32. "app.js": { "deps": [ "jquery", "oldSearch.js", "newSearch.js", ], "depsFull": [ "jquery", "oldSearchDep2.js", "oldSearchDep1.js", "oldSearch.js", "newSearchDep2.js", "newSearchDep1.js", "newSearch.js" ], "fileSize": "4.41 kB", "fileSizeFull": "120.52 kB" }
  • 33. "newSearch.js": { "rule": "inNewSearch", "deps": [ "jquery", "newSearchDep2.js", "newSearchDep1.js", ], "depsFull": [ "jquery", "newSearchSubDep3.js", "newSearchSubDep2.js" "newSearchSubDep1.js" "newSearchDep2.js", "newSearchDep1.js" ], "fileSize": "10.41 kB", "fileSizeFull": "40.52 kB" } nf-include-when
  • 35. var packager = require('nf-packager'), includeWhen = require('nf-include-when'), registries = require('nf-asset-registry'); function getScriptUrl() return packager.getPackageDefinition('app.js', registries, includeWhen); }
  • 36. "app.js": { "deps": [ "jquery", "oldSearch.js", "newSearch.js", ], "depsFull": [ "jquery", "oldSearchDep2.js", "oldSearchDep1.js", "oldSearch.js", "newSearchDep2.js", "newSearchDep1.js", "newSearch.js" ], "fileSize": "4.41 kB", "fileSizeFull": "120.52 kB" } Step 1: Get the full dependency tree for the requested package from the registry.
  • 37. [ "jquery", /* no rule */ "oldSearchDep2.js", /* no rule */ "oldSearchDep1.js", /* no rule */ "oldSearch.js", /* rules.notInNewSearch */ "newSearchDep2.js", /* no rule */ "newSearchDep1.js”, /* no rule */ "newSearch.js" /* rules.inNewSearch */ ] Step 2: Determine which files have rules.
  • 38. [ "jquery", /* no rule */ "oldSearchDep2.js", /* no rule */ "oldSearchDep1.js", /* no rule */ "oldSearch.js", /* rules.notInNewSearch */ "newSearchDep2.js", /* no rule */ "newSearchDep1.js”, /* no rule */ "newSearch.js" /* rules.inNewSearch */ ] Step 3: Run the rules. Filter out all deps that resolved false. ✓
  • 39. [ "jquery", /* no rule */ "oldSearchDep2.js", /* no rule */ "oldSearchDep1.js", /* no rule */ "oldSearch.js", /* rules.notInNewSearch */ "newSearchDep2.js", /* no rule */ "newSearchDep1.js”, /* no rule */ "newSearch.js" /* rules.inNewSearch */ ] Step 4: Filter out all extraneous sub deps. ✓
  • 40. Step 5: Concatenate the files. [ "jquery", /* no rule */ "newSearchDep2.js", /* no rule */ "newSearchDep1.js”, /* no rule */ "newSearch.js" /* rules.inNewSearch */ ]
  • 44. be creative with the registry
  • 45. "account/bb/models/ratingHistoryModel.js": { "rule": null, "deps": [...], "depsFull": [...], "depsCount": { "underscore": 2, "backbone": 1, "jquery": 2, "common/requirejs-plugins.js": 4, "requirejs-text": 4, "utils/contextData.js": 1, "common/nfNamespace.js": 1 }, "hash": "dd23b163", "fileSize": "1.21 kB", "fileSizeFull": "173.04 kB" } dependency counting dependency pruning file sizes
  • 46. @import modules @import (reference) "/common/_nf_defs.less"; @import (reference) "/member/memberCore.less"; @import (reference) "/components/menu.less"; @import (reference) "/components/breadcrumbs.less";
  • 47. "account/containerResponsive.css": { "rule": null, "deps": [...], "depsFull": [...], "depsCount": [...], "hash": "65a431f3", "fileSize": "709 B", "fileSizeFull": "709 B", "css": { "selectors": 8, "declarationBlocks": 6, "declarations": 17, "mediaQueries": 3 } } css analysis
  • 49. "cache": { "account/pin.js": "define('account/pin.js', ['member/memberC…", "account/bb/models/changePlanModel.js": "define('account/b…", "account/bb/models/ratingHistoryModel.js": "define('account…", "account/bb/models/viewingActivityModel.js": "define('account…", "account/bb/views/changePlanView.js": "define('account/bb/vi…", "account/bb/views/changePlanView.js": "define('account/bb/vi…", "account/bb/views/emailSubView.js": "define('account/bb/views…", "account/bb/views/viewingActivityView.js": "define('account…", "common/UITracking.js": "define('common/UITracking.js, ['me…", "common/UITrackingOverlay.js": "define('common/UITrackingOve…", … … …
  • 50. templates templates mappings javascript css mappings javascript css
  • 53. deploy UI bundles anytime
  • 54. never touch the file system
  • 55. < 5ms package response times
  • 56. Takeaways ▶ leverage the server ▶ static analysis FTW ▶ divide and conquer with modules
  • 59. fail fast move faster
  • 60. “I have not failed. I’ve just found 10,000 ways that won’t work.” Thomas Edison
  • 62. thanks! come find us! Alex Liu @stinkydofu Chris Saint-Amant @csaintamant Micah Ransdell @mjr578 Kris Baxter @kristoferbaxter