Transcript
Page 1: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

ProctorManaging A/B Tests and More

Page 2: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 3: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Tom BergmanProduct ManagerAggregation

Matt SchemmelSoftware Engineer

Resume

Page 4: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

We help people get jobs.

Page 5: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

What's best for thejob seeker?

Page 6: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Test & Measure EVERYTHING

Page 7: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

A/B Testing: Definition

A/B testing is an experimental methodology comparing at least two variants, a control group A and test group B, in a controlled experiment

Page 8: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

A/B Testing Key Points

1. Unbiased2. Independent3. Representative

Test and Control Groups should be:

Page 9: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 10: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 11: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 12: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

103 tests315 variations

2^147 combinations

Page 13: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 14: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 15: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 16: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Control

Page 17: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

10% test

10% test

10% test

10% test

10% test

10% test

Control

Page 18: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

+2.9%

+2.3%

+2.0%

+5.2%

+12.8%

+9.6%

Control

Page 19: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

+2.9%

+2.3%

+2.0%

+5.2%

+12.8%

+9.6%

+614M emails

Control

Page 20: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Why A/B Testing?

Page 21: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Before and After

Before and After is bad science.

Page 22: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Weekly TrafficV

isito

rs

ThurWedMon Tues Fri

Page 23: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Yearly TrafficV

isito

rs

Page 24: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Mid Year Test

A < B

AB

Vis

itors

Page 25: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

End of Year Test

AB

A > B

Page 26: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Obligatory XKCD Comic

Page 27: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

History of A/B Testing @Indeed

Page 28: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Next we tried ...

● Multiple Code Versions

● Separate Configuration

● "Sampling by Load Balancer"

Page 29: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Load Balancer: Multiple Versions

CONTROL TEST

Load Balancer

(Old Version Code) (New Version Code)

Page 30: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Load Balancer: Multiple Versions

1. Tedious2. Expensive3. Inflexible

It worked, but ...

Page 31: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Finally ...

1. Arbitrarily Group Users2. Select Test Groups3. Implement Variations

Built Libraries, hand-write code per test to:

Page 32: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Custom Coded Tests

1. Sophisticated Tests2. Scientifically Valid Methods3. Low Operational Overhead

Allowed us:

Page 33: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Custom Coded Tests: Stats

Page 34: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 35: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Goals:

1. Increase Engineering Velocity2. Standardize Representation3. Work Seamlessly Across Products

Page 36: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

ProctorIndeed’s Java Framework for

Managing A/B Tests and More

Page 37: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

ProctorIndeed's Open Source Java Framework for

Managing A/B Tests and More

github.com/indeedeng/proctor

Page 38: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Using Proctor

1. Background and Design

2. Running A/B Tests with Proctor

3. Beyond the Basics

Page 39: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Background and Design

Page 40: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Running a Test

1. Define the Experiment2. Select Groups3. Implement the Behavior4. Log the Results

Page 41: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Running a Test

1. Define the Experiment2. Select Groups3. Implement the Behavior4. Log the Results

Page 42: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Existing Behavior

Page 43: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Save Alert

Test Behavior

Page 44: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Define the Experiment

1. Buckets

2. Sample Sizes

Key characteristics:

Page 45: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Control: Gray Test: Blue

50% 50%

Page 46: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Define the Experiment

(global)

Division of Responsibilities

Test Definition

Apply the Experiment

(each product)

Proctor Library

Test Specification

Page 47: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Buckets Enumerate the Test Variations

● ID, for code

● Long Description, for people

● Short Name, for people

Page 48: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

0"Control Group"Gray

1"Test Group"

Blue

Page 49: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Sizing the Buckets

1. Buckets

2. Sample Sizes

Page 50: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Selecting a Test Bucket

Good user experience does, too:

● Fast● Consistent

Good science requires good sampling:

● Independent● Unbiased

Page 51: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Assign each subsequent visitor to the next bucket.

Round robin assignment

FastUnbiasedConsistent

Independent✓ ✓~✘

● Requires global state for "next bucket"

● Requires state for assigned buckets

Page 52: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

At small scale, you might need round-robin to ensure equal sample sizes.

At large scale, randomized assignment is uniform enough.

Randomized Assignment

FastUnbiasedConsistent

Independent✓ ✓??

Page 53: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Select a bucket at random at the point of execution.

Roll the dice as needed

FastUnbiasedConsistent

Independent✓ ✓✘✓

Page 54: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Roll Once and Cache in a Cookie

● Single-domain, Single-device

● N cookies: Hard to evolve

● One cookie: Fragile to edit

● Size scales with # experiments

FastUnbiasedConsistent

Independent✓ ✓~~

Page 55: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Roll Once and Cache in Session

● Consistent only to length of session

● Tied to one server / data-center

● Many apps don’t use sessions

FastUnbiasedConsistent

Independent✓ ✓✘~

Page 56: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Roll Dice and Cache in DB

FastUnbiasedConsistent

Independent✓ ✓~✘

● DB hit on every request

● More infrastructure

Page 57: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

We can do better

Flaws stem from the need to record selected buckets.

What if we didn't?

Page 58: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

1. Assign each user a unique ID

2. Map that ID to a bucket

3. Store the ID, not the assignments

Don’t Record. Recalculate.

FastUnbiasedConsistent

Independent ??

??

Page 59: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Simple Mapping: Mod N

id mod N=> bucket

Doesn’t work:● Should provide uniform distribution;

mod N assumes it.

● Limited bucket distributions

Page 60: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Range Mapping

id / MAX_ID => bucket

testcontrol0 10.5

Page 61: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Buckets can be any size

1(inactive)

testcontrol0 10.5

testcontrol0 10.5

Page 62: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

testcontrol0 10.5

Sequential IDs No Longer UniformMAX_ID

2

Unbiased✘

Page 63: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Hashed Range Mapping

hash ( id ) => bucket

Kept:

● Arbitrary bucket allocations ok

testcontrolMIN_INT MAX_INT0

Page 64: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Unbiased Distribution for Any ID

50 / 50:

33 / 33 / 33:

Unbiased✓

Page 65: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

But is it independent?

Sign Up Activatevs

Sign Up Sign Upvs

Page 66: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Should look like this

25% 25%

25% 25%

Sign Up

Sign Up Activate

Activate

Page 67: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

But our inputs are consistent

hash ( id ) => bucket

testcontrolMIN_INT MAX_INT0

Page 68: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

So our buckets are identical

S A S S A S A A A S A S A

Col

or

S S S S S SA A A A A A AText

Page 69: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

And we look like this

50% 0%

0% 50%

Sign Up

Sign Up Activate

Activate

Independent✘

Page 70: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Add Salt to Test

hash ( id + test.salt ) => bucket

Kept:

● Arbitrary bucket allocations

● Uniform distribution

Page 71: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Uncorrelated Distribution

A S A S A S S A A A S S A

Col

or

A S A S A S S A A A S S A

Text

Independent✓

Page 72: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

But is it fast?

0.90

0.85

0.80

0.75

0.70

0.65

0.60

Resume Editor Resume Search

Page 73: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

But is it consistent?

Consistency bounded only by ID

Page 74: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

We Usually Use Tracking Cookies

● Easy

● Ubiquitous on the web

● Require no server-side storage

● Best we can do with no user action

Consistent~

Page 75: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

FastUnbiasedConsistent

Independent✓ ✓~✓

Best we’ve seen so far…

Page 76: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Definitions Map Buckets to ID Range

Bucket Range

gray 0.50

blue 0.50

Each bucket maps to a % of the hashed range

Page 77: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Sometimes, Though, Cookies Won't Do

● Cross-Domain● Some People Block Cookies

● Cross-Device● Cookies are Web-Only

Page 78: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Many Ways to ID a User

Account #12345

Tracking cookie:UID#1

Email [email protected]

Access Token:4/rymOMYE…

Session ID557206C363F…

Page 79: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Proctor Uses Any Set of IDs

ID Type... Tracked By...

USER Tracking Cookie

ACCOUNT Account ID

EMAIL Email Address

… …

We use…

Page 80: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Account ID

● Authenticated

● Consistent across domains

● Consistent across devices

● Consistent across visits

Page 81: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Email Address

● Sometimes available without account

● Identified, though not authenticated

Page 82: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Each Test Applies to One ID Type

● Test groups split by that identifier

● Visitors without that identifier are ignored

Page 83: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Running A/B Tests

Page 84: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Test Definitions Encoded in JSON

● Compact

● Simple and Flexible

● Editable by Humans

● Editable by Machines

Page 85: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Basic Data in the Test Definition

"description": "Button colors","salt": "buttonBgColorTst","type": "USER"

Page 86: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Buckets in the Test Definition

"buckets": [{"id": 0, "name": "gray","description": "Control group"

}, {"id": 1, "name": "blue","description": "Test group"

}]

Page 87: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Mapping Buckets to Ranges

"ranges": [{"bucketValue": 0,"length": 0.5

}, {"bucketValue": 1,"length": 0.5

}]

Page 88: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Complete Test Definition{

"description": "Button colors",

"type": "USER",

"salt": "buttonBgColorTst",

"buckets": […],

"allocations": [{

"ranges": […]

}],

}

Page 89: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Define the Experiment

proctor data

Division of Responsibilities

Test Definition

Apply the Experiment

(each product)

Proctor Library

Test Specification

Page 90: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Proctor includes several modules

Proctor

Common

Ant Builder

Codegen

Maven Builder

Page 91: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Product Test Specification lists active tests

References into the global pool:

"tests": [{"buttonBgcolorTest": {"buckets": {"gray": 0, "blue": 1

}}

}]

Page 92: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Apply the Experiment

On every request…

1. Select Groups2. Render the Response

3. Log the Action

Page 93: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

On every request…

1. Collect identifiers

2. Select buckets for opted-in tests

Determining Buckets in Code

Page 94: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Collect identifiers for all ID Types

// Product codeString cookie = getTrackingCookie(request);String accountId = getAccountIdOrNull(request);

// Proctor preparationIdentifiers identifiers = Identifiers.of(

TestType.USER, cookie,TestType.ACCOUNT, accountId

);

Page 95: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

// Proctor preparationIdentifiers identifiers = Identifiers.of(

TestType.USER, trackingCookie,TestType.ACCOUNT, accountId

);

Select Buckets for Opted-In Tests

// Proctor assignmentsProctorResult assignments =

proctor.determineBuckets(identifiers);

Page 96: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Apply the Experiment

On every request…

1. Select Groups

2. Render the Response3. Log the Action

Page 97: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Choose behavior for selected bucket

int bgColorBucket;

/* … */

// Choose a background color for templatesif (bgColorBucket == 1) {

// Testmodel.put("buttonBgColor", "#00f");

} else {// Control groupmodel.put("buttonBgColor", "#ccc");

}

Page 98: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

ProctorResult exposes buckets

// Proctor assignmentsProctorResult assignments =

proctor.determineBuckets(identifiers);

// Get selected bucket for this userint bgColorBucket = assignments

// Map<String, TestBucket>: All tests.getBuckets()

// TestBucket: This assignment.get("buttonBgColorTst") // TestBucket

// int: Enumerated ID.getValue();

… verbosely

Page 99: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

"Redundant" names in test spec…

"buttonBgColorTest": {"buckets": {"gray": 0, "blue": 1

}}

Page 100: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

… are used to generate helper methods

// Choose a background color for templatesResumeSearchGroups groups =

new ResumeSearchGroups(assignments);

// Boolean accessors for each test & bucketgroups.isButtonBgColorTstGray();groups.isButtonBgColorTstBlue();

// Enumerated value by test namegroups.getButtonBgColorTstValue();

Page 101: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Helper designed for use in UI layer

This immutable bean is trivial to:

● Read from JSP/JSF● Read from Templates

○ Freemarker, Velocity, Closure, etc

● Serialize as JSON

Page 102: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Apply the Experiment

On every request…

1. Select Groups

2. Render the Response

3. Log the Action

Page 103: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Logging Bucket Assignments

Proctor just selects the buckets.

When and how you log are up to you:

● On related events only● On every event

Page 104: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Publication

Page 105: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Test Definitions in Source Control

● No new infrastructure● Lots of desirable features for free

History Diff Access Control

Page 106: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

App Servers

Test Definitions

Proctor Data

App

Publish

Artifact Periodic Refresh

Page 107: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Individual test changes pushed to a named branch:

Publication is also via Source Control

/trunk

/branches/production

Page 108: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Overwriting Tests on a Named Branch

Not required to use proctor, but beneficial:

● Same features for free History, Diff, ACL

● No merging● Easy roll-back, roll-forward

Page 109: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Build Servers

Test Definitions

Test Specifications

Project

Deliverable

App Servers

Publish

Artifact Periodic Refresh

Compile

Deploy

App

Proctor Data

Page 110: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Beyond the Basics

Page 111: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Test Segmentation

Page 112: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Segmentation

Test often apply to only certain users:

● Specific markets

● Specific languages

● Specific devices

Page 113: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Segmentation through Test Rules

● Test definition allows one optional rule

● A rule is simply a boolean expression

● If the rule passes, the user is assigned to a test bucket

Rules are written in Unified EL

Page 114: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Simple Things are Simple

{"description": "Button colors","rule": "country == ‘CA’""buckets": […]

}

● No deployment needed

● Changes live within minutes

Page 115: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Primitive and rich data types

"userAgent.phone || userAgent.tablet"

"userAgent.supports.html5"

"userAgent.supports.geolocation"

"userAgent.supports.fileUpload"

Page 116: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Commons EL is Easily Extended

JSTL Standard Functions

Custom code

"rule": "fn:endsWith( account.email, '@indeed.com')"

"rule": "proctor:contains(

['US', 'CA'], country)"

Page 117: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Arbitrary Complexity

Sometimes rules are unavoidably complex:

"Android v2.1+":userAgent.android && ( userAgent.OS.majorVersion gt 2 || ( userAgent.OS.majorVersion == 2

&& userAgent.OS.minorVersion gte 1

))

Page 118: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

What context is available?

So far we've seen:● country● language● userAgent● account

What's the full list of available context variables?

Page 119: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Context Defined in Test Specification

● Test spec declares available context variables

● This is a contract to provide values at runtime

{"tests": […],"providedContext": {

"country": "String","language": "String""userAgent":

"com.indeed.web.UserAgent"}

}

Page 120: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

// Proctor assignmentsProctorResult assignments =

proctor.determineBuckets(identifiers,country,language,userAgent);

Provided While Determining Buckets

private ResumeSearchProctor proctor;

Also generated from test specification:

Page 121: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Payloads

Page 122: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Even Tiny Changes Need Deploys

// Choose a background color for templatesif (bgColorBucket == 1) {

// Testmodel.put("btnBgcolor", "#00f");

} else {// Control groupmodel.put("btnBgcolor", "#ccc");

}

Page 123: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Many tests have no behavioral change:● CSS Colors

● Display Text

● Algorithm Weights

Some Tests Just Vary Data

Page 124: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Payloads

● Values added for each bucket in a test

● Proctor verifies payloads are "all or none"

Control: Gray Test: Blue

Page 125: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Payloads

● Values added for each bucket in a test

● Proctor verifies payloads are "all or none"

Control: Gray Test: Blue

"#ccc" "#00f"

Page 126: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Part of Test Definition

"buckets": [{"id": 0, "name": "gray","description": "Control group","payload": {"stringValue": "#ccc"

}}, …]

● No deployment needed

● Changes live within minutes

Page 127: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Declared in Project Test Specification

● Type definition only

● Must match test definition

"buttonBgColorTst": {"buckets": […],"payload": {"type": "stringValue"

}}

Page 128: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Cleaner Code, Only Data Deploy

// Choose a background colormodel.put("btnBgcolor", groups.getButtonBgColorTstPayload()

);

Page 129: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Cross-Product Tests

Page 130: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Cross-Product Tests

Many flavors of cross-product test, including

● Peer webapps

● Client / Service

● Mobile Native / Web

Page 131: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Proctor offers an interesting alternative

Cross-Product Tests

Even more ways to coordinate tests

● Tracking parameters on links, requests

● Service response metadata

● Different service calls

Page 132: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Two products can share test groups

As long as both products

● Share the test’s identifier● Provide the context variables it uses

Deterministic selection guarantees identical bucket assignment.

Page 133: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Evolving Tests

Page 134: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Evolving Tests

testcontrol

Page 135: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Evolving Tests

testcontrol (inactive)

10%

Page 136: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

control

Changed allocations, not ID mapping

testOOPS!

● Inconsistent experience● Polluted results

Page 137: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Evolving Tests Smoothly

[ 10%, 10%]

testcontrol (inactive)

[ 10%, 10%, 80% ]

Page 138: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Evolving Tests Smoothly

[ 10%, 10%, 80% ]

[ 10%, 10%, 40%, 40%]

testcontrol (inactive)

testcontrol testcontrol

Page 139: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Evolving Tests Smoothly

[ 10%, 80%, 10% ]

[ 50%, 50% ]

testcontrol (inactive)

control test

Page 140: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Evolving Tests… Turbulently

hash ( uid + test.salt ) => bucket

Any ID:

testcontrol

Test range:

test

1te

st1

After re-salt:

Page 141: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Contextual Sampling

Page 142: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Contextual Allocation

testcontrol (inactive)

10% (US):

50% (Rest of World):testcontrol

testcontrol

20% (CA):(inactive)

Page 143: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Allocations

Each test definition ● has one or more allocations

Each allocation● has a rule and ranges totaling 1.0● except the last, which has no rule.

Page 144: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Allocation Rules

● Use Unified EL, same as test rules.

● Use the same context variables as test rules.

● Choose the first matching allocation.

Page 145: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Allocations in the Test Definition{ "description": "Button colors","type": "USER","salt": "buttonBgColorTst","buckets": [ … ],"allocations": [{"rule": "country == 'US'","ranges": [ … ]

}, {"ranges": [ … ]

}]}

Page 146: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Pre-Production

Page 147: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Environments

Local

Integration

QA

Production

commit

push

push

Page 148: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Show test matrix

/private/showTestMatrix

Page 149: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Show test bucket assignments

/private/showGroups/private/showGroups

Page 150: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Privileged users can force assignments

Page 151: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Privileged users can force assignments

?prforceGroups=buttonColorTst1

Page 152: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Beyond A/B TestingProctor Patterns for Managing Behavior

Page 153: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Kill SwitchWhen ● New Feature

How● 'Active' bucket @ 100%

Page 154: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Phased RolloutWhen ● Experimental Feature

How● 'Active' bucket @ 0%● 'Active' → 1% → 5% → 100%

Page 155: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

When ● Downsampling

○ trace logging○ survey

How● 'Active' bucket @ 0%● 'Active' → 1% → 10% → 5% → ??

Throttle

Page 156: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Feature TogglesWhen ● Localized Behavior● Device-Specific Behavior● Logged-in, w/ Resume, etc.

How● Multiple Allocations ● Targeted Rules

Page 157: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Dark DeploysWhen ● Partial Implementations● Additional QA is needed

How● 'Active' bucket @ 0%● 'Active' → 100%

Page 158: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

When ● Dependencies between products

○ Resume Wizard feature

How● 'Active' bucket at 0%● Resume Wizard allocation: → 100%● Home page promo allocation: → 100%

Cross-Product Coordination

Page 159: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Pre-Proctor Tests

Page 160: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Post-Proctor Tests

Proctor

42

103

Page 161: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Post-Proctor Tests + Toggles

Proctor

42

10

103

65

Page 162: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Proctor WebappA/B Test Change Management

(Coming Soon to github)

Page 163: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 164: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Proctor Webapp

Page 165: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Proctor Webapp

Page 166: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Proctor Webapp

Page 167: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Proctor Webapp

Page 168: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Building On Proctor(Not Open Source)

Page 169: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 170: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor
Page 171: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Description: Group 0: control - Job alert label: Save Alert (control) Group 1: labelSubscribe - Job alert label: Subscribe Group 2: labelSignUp - Job alert label: Sign up Group 3: labelGetJobs - Job alert label: Get jobs Group 4: labelSendMeNewJobs - Job alert label: Send me new jobs Group 5: labelActivate - Job alert label: Activate Group 6: labelSave - Job alert label: Save

Page 172: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

History:

jack @ 2013-03-12 (r203267): Promoting jasxjabtnlbltst (trunk r203089) to

production JASX-11365: jasxjabtnlbltst disabled

ketan @ 2012-12-11 (r190675): merged r190418: JASX-10663: Stop

jasxjabtnlbltst in all languages except nl

will @ 2012-11-29 (r188801): merged r187452: JASX-10457: exclude US from

jasxjabtnlbltst

ketan @ 2012-10-25 (r182881): merged r182688: JASX-10234 - Adding new

langauges to job alert button label test

ketan @ 2012-10-25 (r182876): merged r181938: JASX-10234 - Adding test

definition and allocations for job alert button label test

Page 173: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

DEMOGet out your Phones and Tablets

Page 174: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

http://go.indeed.com/demo

Simple: test different background colors 25% 25%

25%25%

50%

Page 175: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

http://go.indeed.com/demo

Let’s increase our bucket size...

50%

50%

Page 176: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

http://go.indeed.com/demo

We have a winner! 50%

100%

Page 177: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

http://go.indeed.com/demo

Let’s do something wacky!

Android >= 4 iOS >= 7

iOSAndroid

Page 178: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

http://go.indeed.com/demo

Also a reference implementation

Running on heroku -- feel free to clone!http://indeedeng-hello-proctor.herokuapp.com

Source:github.com/indeedeng/proctor-demo

Page 180: [@IndeedEng] Managing Experiments and Behavior Dynamically with Proctor

Next @IndeedEng Talk

BoxcarSelf-balancing distributed services

Wednesday, October 30R.B. Boyer