Transcript
Page 1: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js

Scaling A/B testing on Netflix.com with

_________Alex Liu @stinkydofu

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

data driven product development

Page 3: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
Page 4: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
Page 5: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
Page 6: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js

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

Test 1 Test 2 Test 3 Test 4 Test 5 Test 6 Test 7

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

2,097,152 unique experiences across seven tests

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

hundreds of new A/B tests per year

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

433518929550349486086117218185493567650…72061153709996

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

2105 566 685templates CSS JS

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

2.5M unique packages every week

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

problem: conditional dependencies

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

Packaging

Page 14: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
Page 15: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js

oldSearch

app.js

newSearch

dep1 dep2 dep3 dep4 dep5

sub-dep sub-depsub-dep sub-dep sub-dep sub-dep

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

oldSearch

app.js

newSearch

dep1 dep2 dep3 dep4 dep5

sub-dep sub-depsub-dep sub-dep sub-dep sub-dep

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

app.js

import jquery from 'jquery'; import oldSearch from 'oldSearch'; import newSearch from 'newSearch';

export ...

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

oldSearch

app.js

newSearch

dep1 dep2 dep3 dep4 dep5

sub-dep sub-depsub-dep sub-dep sub-dep sub-dep

Page 19: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
Page 20: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js

685 files…?

2.5M packages…?

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

oldSearch

app.js

newSearch

dep1 dep2 dep3 dep4 dep5

sub-dep sub-depsub-dep sub-dep sub-dep sub-dep

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

problem: conditional dependencies

Page 23: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
Page 24: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js

requestbuild

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

require('nf-include-when')

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

/* * @includewhen rule.notInNewSearch */

oldSearch.js

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

/* * @includewhen rule.inNewSearch */

newSearch.js

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

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;

anatomy of a rule

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

require('nf-asset-registry')

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

import jquery from 'jquery'; import oldSearch from 'oldSearch'; import newSearch from 'newSearch';

export ...

app.js

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

newSearch.js

jquery

oldSearch.js

app.js

registry

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

"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" }

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

"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

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

require('nf-packager')

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

var packager = require('nf-packager'), includeWhen = require('nf-include-when'), registries = require('nf-asset-registry');

function getScriptUrl() return packager.getPackageDefinition('app.js', registries, includeWhen); }

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

"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.

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

[ "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.

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

[ "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.

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

[ "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.

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

Step 5: Concatenate the files.

[ "jquery", /* no rule */ "newSearchDep2.js", /* no rule */ "newSearchDep1.js”, /* no rule */ "newSearch.js" /* rules.inNewSearch */ ]

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

buildjavascript

registry

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

request registry

rulespackager

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

Bonus Round

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

be creative with the registry

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

"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

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

@import (reference) "/common/_nf_defs.less"; @import (reference) "/member/memberCore.less"; @import (reference) "/components/menu.less"; @import (reference) "/components/breadcrumbs.less";

@import modules

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

"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

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

the

best part

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

"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…", … … …

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

css

mappings

javascript

templates templates

mappings

javascript

css

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

templates

mappings

javascript

css

UI Bundle

Page 52: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js
Page 53: [NodeConf.eu 2014] Scaling AB Testing on Netflix.com with Node.js

deploy UI bundles

anytime

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

never touch the file system

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

< 5ms package response times

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

Takeaways▶ leverage the server ▶ static analysis FTW ▶ divide and conquer with modules

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

Our Learnings

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

learn by doing

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

fail fastmove faster

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

“I have not failed.I’ve just found 10,000 waysthat won’t work.”

Thomas Edison

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

simplify

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

thanks! come find us!

Alex Liu @stinkydofu

Chris Saint-Amant @csaintamant

Micah Ransdell @mjr578

Kris Baxter @kristoferbaxter


Top Related