Documentation ¶
Overview ¶
Package choices provides a library for simple a/b and multivariate testing.
choices uses hashing to uniquely assign users to experiments and decide the values the user is assigned. This allows us to quickly assign a user to an experiment with out having to look up what they were assigned previously. Most of the ideas in this package are based off of Facebook's Planout.
In choices there are three main concepts. Namespaces, Experiments, and Params. Namespaces split traffic between the experiments they contain. Experiments are the element you are testing. Experiments are made up of one or more Params. Params are a key value pair. The value can be either a Uniform Choice value or a Weighted Choice value.
In most cases you will want to create one namespace per experiment. If you have experiments that might have interactions you can use namespaces to split the traffic between them. For example, if you are running a test on a banner and another test that takes over the whole page, you will want to split the traffic between these two tests. Another example, is if you want to run a test on a small percent of traffic. Namespaces contain a list of TeamID's. These TeamID's are used to deterime which Experiments to return to the caller.
Experiments contain the Params for a running experiment. When a caller queries Namespaces, Namespaces will hash the user into a segment, It will then check if the segment is contained in an Experiment. If the segment is contained in the experiment then the experiment will be evaluated. An experiment will in turn evaluate each of it's Params.
Params are key-value pairs. They Options for value are Uniform choice or Weighted choice. Uniform choices will be selected in a uniform fashion. Weighted choices will be selected based on the proportions supplied in the weights.
Index ¶
- Constants
- Variables
- func HashExperience(namespace, experiment, param, userID string) (uint64, error)
- func InSegment(namespace, userID string, s segments) bool
- func SetGlobalSalt(s string) error
- type Config
- type ConfigOpt
- type ErrUpdateStorage
- type Experiment
- type ExperimentResponse
- type Namespace
- type Param
- type ParamValue
- type Uniform
- type Value
- type ValueType
- type Weighted
Constants ¶
const ( StorageEnvironmentBad = iota StorageEnvironmentDev StorageEnvironmentProd )
constants for storage environments. So far only support a staging and production.
Variables ¶
var ErrBadStorageEnvironment = errors.New("bad storage environment")
ErrBadStorageEnvironment is an error for when the storage environment is not set correctly.
var ( // ErrGlobalSaltAlreadySet is the error returned when a SetGlobalSalt // has been called more than once. ErrGlobalSaltAlreadySet = errors.New("global salt already set") )
var ( // ErrSegmentNotInExperiment occurs when a user is hashed into a // segment that has not been claimed by an experiment. ErrSegmentNotInExperiment = errors.New("Segment is not assigned to an experiment") )
var ( // 0, an unavailable segment. ErrSegmentUnavailable = errors.New("segment unavailable") )
Functions ¶
func HashExperience ¶
HashExperience takes the supplied arguments and returns the hashed uint64 that can be used for determining a segment.
func InSegment ¶
InSegment takes a namespace name, userID and segments and returns whether the userID is in a segment that is claimed. Typical use case for this is determining whether or not a user is in a given experiment.
func SetGlobalSalt ¶
SetGlobalSalt this sets the global salt used for hashing users. It should only ever be called once. It returns an error if it is called more than once.
Types ¶
type Config ¶
type Config struct { ErrChan chan error // contains filtered or unexported fields }
Config is the configuration struct used in an elwin server.
func NewChoices ¶
NewChoices sets the storage engine. It starts a ticker that will call s.Update() until the context is cancelled. To change the tick interval call SetUpdateInterval(d time.Duration). Must cancel the context before calling NewChoices again otherwise you will leak go routines.
func (*Config) IsHealthy ¶
IsHealthy returns an error if the time since the last successful update is longer than the max allowed time to fail. The interval for updates can be set by WithUpdateInterval. The time until failure can be set with WithMaxUpdateFailTime.
func (*Config) Namespaces ¶
Namespaces determines the assignments for the a given user's id based on the current set of namespaces and experiments. It returns a []ExperimentResponse if it is successful or an error if something went wrong.
type ConfigOpt ¶
ConfigOpt is a type that modifies Config. It is used when calling NewChoices to configure choices.
func WithGlobalSalt ¶
WithGlobalSalt is a configuration option for Config that sets the globalSalt to something other than the default.
func WithMaxUpdateFailTime ¶
WithMaxUpdateFailTime changes the max duration allowed for failing updates.
func WithStorageConfig ¶
WithStorageConfig is where you set the address and environment you'd like to point. This is used as a ConfigOpt in NewChoices.
func WithUpdateInterval ¶
WithUpdateInterval changes the update interval for Storage. Must call SetStorage after this or cancel context of the current Storage and call SetStorage again.
type ErrUpdateStorage ¶
type ErrUpdateStorage struct {
// contains filtered or unexported fields
}
ErrUpdateStorage is an error type that is returned when storage fails to update.
func (ErrUpdateStorage) Error ¶
func (e ErrUpdateStorage) Error() string
Error is to implement the error interface
type Experiment ¶
Experiment is a structure that represents a single experiment in elwin. It can contain multiple parameters. Experiments are evaluated through the call to Namespaces.
func FromExperiment ¶
func FromExperiment(s *storage.Experiment) Experiment
FromExperiment converts a *storage.Experiment into an Experiment
func NewExperiment ¶
func NewExperiment(name string) *Experiment
NewExperiment creates an experiment with the supplied name and no segments cliamed. In order for any traffic to be assigned to this experiment you will need to call Experiment.SetSegments or Experiment.SampleSegments.
func (*Experiment) MarshalJSON ¶
func (e *Experiment) MarshalJSON() ([]byte, error)
MarshalJSON implements the json.Marshaler interface for Experiments.
func (*Experiment) SampleSegments ¶
func (e *Experiment) SampleSegments(ns *Namespace, num int) *Experiment
SampleSegments takes a namespace and an amount of segments you want in your experiment and returns a random sample of the unclaimed segments from the namespace.
func (*Experiment) SetSegments ¶
func (e *Experiment) SetSegments(seg segments) *Experiment
SetSegments copies the segments supplied to the experiment.
func (*Experiment) ToExperiment ¶
func (e *Experiment) ToExperiment() *storage.Experiment
ToExperiment is a helper function that converts an Experiment into a *storage.Experiment.
type ExperimentResponse ¶
type ExperimentResponse struct { Name string Namespace string Params []ParamValue }
ExperimentResponse holds the data for an evaluated expeiment.
type Namespace ¶
type Namespace struct { Name string Segments segments Experiments []Experiment }
Namespace is a container for experiments. Segments in the namespace divide traffic. Units are the keys that will hash experiments.
func FromNamespace ¶
FromNamespace converts a *storage.Namespace into a Namespace.
func NewNamespace ¶
NewNamespace creates a new namespace with all segments available. It returns an error if no units are given.
func (*Namespace) MarshalJSON ¶
MarshalJSON implements the json.Marshaler interface for Namespaces.
func (*Namespace) ToNamespace ¶
ToNamespace is a helper function that converts a Namespace into a *storage.Namespace.
type Param ¶
Param is a struct that represents a single parameter in an experiment. Param is evaluated through the call to Namespaces.
func (*Param) MarshalJSON ¶
MarshalJSON implements the json.Marshaler interface for Params.
type ParamValue ¶
ParamValue is a key value pair returned from an evalated experiment parameter.
type Uniform ¶
type Uniform struct {
Choices []string
}
Uniform is a way to select from a list of Choices with uniform probability.
func (*Uniform) MarshalJSON ¶
MarshalJSON implements the json.Marshaler interface for Uniform choices.
type Value ¶
Value is the interface Param Values must implement. They take a hash value and return the string that represents the value or an error.
type ValueType ¶
type ValueType int
ValueType are the different types of Values a Param can have. This is used for parsing params in storage.
type Weighted ¶
Weighted is a way to select from a list of Choices with probability ratio supplied in Weights.
func (*Weighted) MarshalJSON ¶
MarshalJSON implements the json.Marshaler interface for Weighted choices.