• Stars
    star
    202
  • Rank 193,691 (Top 4 %)
  • Language
    JavaScript
  • License
    Other
  • Created over 12 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Implementations of a variants (experiments, mods) system. Allows for dynamic flag evaluation based on conditions.

Variants

Background

In web applications it is common to provide varying experiences to unique sets of users. A flexible design should allow implementations of common patterns in web development like:

  • A/B testing
  • Experimental features
  • Trusted tester groups
  • Gradual feature rollouts

Overview

Variants provide an expressive way to define and conditionally modify experimental features, which can also be forcefully adjusted (for development).

Note that the following README only provides a general overview of variants, and is language independent. Currently, there are ports written for Node.js and Go. See the implementation-specific READMEs for more information.

To conditionally gate certain features, they must be protected by variant flags. Variant flags are globally unique strings that can point to a language primitive, array or object. Most commonly, variant flags are simple boolean values so that the below code is possible:

if (variants.getFlagValue('enable_product_access')) {
  throw Error('Authenticated failed.')
}

Design

  • Each service contains variants
  • Variants contain 0 or more conditions and 1 or more mods
  • Conditions evaluate the current request based on the condition type and values
  • Mods modify variant flags
  • Variant flags are checked in code to gate control flow

Variant

Variants are globally defined objects that may optionally modify values based on some conditions. All variants are evaluated on a per request basis, which means that they are scoped to request-based values such as: user ip, specific users, groups of users, query parameters, etc.

Variants must have an id and a list of conditions and mods. A variant must contain at least one mod to be valid.

variant: {
  required string id
  optional string conditional_operator
  optional condition[] conditions
  required mod[] mods
}

Condition

Conditions return true or false based on the current request object. If more than one condition is supplied, then the conditional_operator (either "OR" or "AND") must be supplied.

Below is a list of condition types:

USER_ID

User id is a condition that evaluates the given condition based on a list of usernames in the "values" field.

E.g.

{
  "type": "USER_ID",
  "values": [
    "somedude74",
    "anotherdude323",
    "hax0r1337"
  ]
}

USER_ID_MOD

User id mods use a hashed value of the current user’s username mapped onto a range from 0-99. It allows the properties "range_start" and "range_end", which contain values between 0-99 and range_end must be greater than range_start.

By default, this uses the unique user id of an authenticated user. However, the "cookie_type" field can be set to "NSID" to refer to unauthenticated users.

E.g.

{
  "type": "USER_ID_MOD",
  "values": [ 0, 9 ]
}

Note: This is useful for rolling out new features, such as to 1% -> 10% -> 50% -> 100% of users.

RANDOM

Random will randomly determine whether or not a given request is eligible for the variant.

E.g.

{
  "type": "RANDOM",
  "value": 0.25
}

Mod

Mods are triggered when the conditions are met on the given variant. The format of a mod is simply a key and a value. The key must refer to a global identifier for the variant flag.

Full spec

Spec in pseudo-protobuf format:

message Variants {
  repeated Variant variants;
}

message Variant {

  enum Operator {
    AND, // "AND"
    OR   // "OR"
  }

  // Unique identifier.
  required string id;

  // Readable description of the feature.
  optional string description;

  // Optional operator to evaluate the conditions.
  optional Operator conditional_operator;

  // List of conditions to evaluate.
  repeated Condition conditions;

  // List of mods to be triggered.
  repeated Mod mods;
}

message Condition {

  enum Type {
    RANDOM,
    USER_ID,
    USER_ID_MOD,
    USER_IP
  };

  // Type of condition.
  required Type type;

  // Single value.
  optional * value;

  // List of values.
  repeated * values;
}

message Mod {
  // Name of the variant flag to modify.
  required string flag;

  // Value to set.
  required * value;
}

Appendix

Contributing

Questions, comments, bug reports, and pull requests are all welcome. Submit them at the project on GitHub.

Bug reports that include steps-to-reproduce (including code) are the best. Even better, make them in the form of pull requests that update the test suite. Thanks!

Author

David Byttow supported by The Obvious Corporation.

License

Copyright 2012 The Obvious Corporation.

Licensed under the Apache License, Version 2.0. See the top-level file LICENSE.txt and (http://www.apache.org/licenses/LICENSE-2.0).

More Repositories

1

medium-api-docs

Documentation for Medium's OAuth2 API
2,235
star
2

phantomjs

NPM wrapper for installing phantomjs
JavaScript
1,419
star
3

snowflake

Medium's engineering growth visualization tool
JavaScript
725
star
4

sus

simple data-uri stylesheet generator
JavaScript
693
star
5

matador

an MVC framework for Node
JavaScript
604
star
6

medium-sdk-nodejs

A NodeJS SDK for Medium's OAuth2 API https://medium.com
JavaScript
345
star
7

opensource

Umbrella project for open source efforts at Medium
290
star
8

medium-policy

Medium’s Policies and Guidelines.
245
star
9

shepherd

Asynchronous dependency injection for node
JavaScript
233
star
10

dynamite

A promise-based DynamoDB client
JavaScript
212
star
11

kew

a lightweight promise library optimized for node.js
JavaScript
211
star
12

medium-wordpress-plugin

The official WordPress plugin for cross-posting to Medium.
PHP
207
star
13

medium-sdk-python

Python SDK for Medium's OAuth2 API
Python
187
star
14

medium-sdk-go

A Golang SDK for Medium's OAuth2 API
Go
139
star
15

sculpt

Manipulate streams.
JavaScript
130
star
16

falkor-archived

HTTP Level Functional Testing Library (nodeunit compatible)
JavaScript
124
star
17

soynode

Utility for working with Closure Templates, aka Soy, from with a node.js application.
JavaScript
91
star
18

local-dynamo

A Node.js wrapper of AWS DynamoDB Local and utilities
JavaScript
88
star
19

pipette

Stream and pipe utilities for Node
JavaScript
43
star
20

oid

Utilities for object identity and hashing
JavaScript
40
star
21

node-bloomd

A NodeJS client for BloomD
JavaScript
35
star
22

medium-logos

Versions of the Medium logo and wordmark in popular formats.
23
star
23

pbnj

JavaScript protocol buffer schema parser and template based code generator
JavaScript
20
star
24

canoe

Node.js 0.10-friendly S3 utility library
JavaScript
20
star
25

picchu

Medium Picchu Kubernetes Operator
Go
18
star
26

daemonsauce

Node module to make it easy to be a proper *nix daemon
JavaScript
17
star
27

draccus

A tool for stashing messages queued up in Amazon's SQS.
JavaScript
10
star
28

zcache

Multi-layer cache API
JavaScript
9
star
29

typ

Type predicates and assertions for Node.
JavaScript
8
star
30

asdf-operator-sdk

Operator SDK plugin for asdf version manager https://github.com/asdf-vm/asdf
Shell
7
star
31

brigade

An S3 bucket proxy (think “bucket brigade”)
Go
2
star
32

nodeunitq

Utilities for nodeunit with promises
JavaScript
2
star
33

medium-transparency

1
star