evaluation

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2022 License: Apache-2.0 Imports: 10 Imported by: 0

README

SimpleFlags Evaluation Engine


Simple flags which introduce variables, expressions and rule engine

Overview


This is experimental project, do not use it in production!!!

  1. No Variations
  2. No Clauses
  3. No configuration kind (bool, number ...)
  4. No states (on, off)
  5. No segments (target groups)
  6. No private attributes or anonymous target
1. No variations

More than 80% of flags are bool flags and there is no reason to have just two values as variation. Many companies use variation "true" and "false" but on my engine true and false are reserved keywords. Following JSON and swagger spec engine use data types from specification. If we talk about multivariate flags like strings, number etc. than probably there is a reason to have variation but if we look into flags there is no variations sharing between flags, so I don't see a reason to have variations at all.

2. No custom rules and clauses

Clauses are hard to read and to maintain so IMO I think there are better ways like rule engine evaluations. instead of maintaining schema for complex clauses better use expression language.

dev:
    value: true
    expression: target.identifier in beta
3. No configuration kind (bool, number ...)

No reason to have flag/configuration kind and engine supports dynamic nature of flags, so if flag serves bool than the flag is boolean. One thing why engine is different from others it can serve any values as you wish:

  • Bool
  • Number
  • String
  • Map
  • Slice
evaluate("some_flag", target).Bool(defaultValue)

if some_flag serves string values 'true' or 'false' you can call bool or string methods it will give same results.

4. No states (on, off)

Instead of "on" or "off" there is simple bool field on: bool, if flag is on then 'on' will be true.

5. No segments (target groups)

This is the most interesting part there are no target groups or segments. So we are introducing concept of variables why variables? Because feature flags are remote "if" or online "if" and if is part of the language so variables are more suitable. Variable can have any data type like bool, string, number, slice, map. Variables can be used as serving values and values used in rule engine. Variables can be global and local. Local variables are used in the project and globals outside of the project. Imagine if you have paid customers and you want to share among different projects then you can specify global variable paidCustomers.

paidCustomers = [
    'enver', 'bisevac'
]

and in flag rule expr:

target.name in paidCustomers

Global variables and local variables can have the same name.

6. No private attributes or anonymous target

All targets are private so they are never stored and doesn't require any required field, you can put any property.

Documentation

Index

Constants

View Source
const (
	CreateFlagEvent = "create_flag"
	PatchFlagEvent  = "patch_flag"
	DeleteFlagEvent = "delete_flag"
	CreateVariable  = "create_var"
	PatchVariable   = "patch_var"
	DeleteVariable  = "delete_var"
)

Variables

View Source
var (
	// ErrQueryProviderMissing ...
	ErrQueryProviderMissing = errors.New("query field is missing in evaluator")
)

Functions

func SetLogger

func SetLogger(logger Logger)

func Variables

func Variables(expression string) ([]string, error)

Types

type Configuration

type Configuration struct {
	Project       string         `json:"project"`
	Environment   string         `json:"environment"`
	Identifier    string         `json:"identifier"`
	Deprecated    bool           `json:"deprecated"`
	On            bool           `json:"on"`
	OnValue       interface{}    `json:"onValue"`
	OffValue      interface{}    `json:"offValue"`
	Rules         []Rule         `json:"rules"`
	Prerequisites []Prerequisite `json:"prerequisites"`
	Version       uint           `json:"version"`

} // @name Configuration

type Configurations

type Configurations []Configuration // @name Configurations

type DataProvider

type DataProvider interface {
	GetVariable(key string) (Variable, error)
	GetConfiguration(key string) (Configuration, error)
}

DataProvider provides methods for segment and flag retrieval

type Distribution

type Distribution struct {
	BucketBy   string              `json:"bucketBy" validate:"required"`
	Variations []WeightedVariation `json:"variations" validate:"required"`

} // @name Distribution

func (Distribution) IsEmpty

func (d Distribution) IsEmpty() bool

type Evaluation

type Evaluation struct {
	Project     string      `json:"project"`
	Environment string      `json:"environment"`
	Identifier  string      `json:"identifier"`
	Value       interface{} `json:"value"`
	// contains filtered or unexported fields

} // @name Evaluation

func (Evaluation) Bool

func (v Evaluation) Bool(defaultValue bool) bool

func (Evaluation) Int

func (v Evaluation) Int(defaultValue int) int

func (Evaluation) IsNone

func (v Evaluation) IsNone() bool

func (Evaluation) Map

func (v Evaluation) Map(defaultValue map[string]interface{}) map[string]interface{}

func (Evaluation) Number

func (v Evaluation) Number(defaultValue float64) float64

func (Evaluation) String

func (v Evaluation) String(defaultValue string) string

type Evaluations

type Evaluations []Evaluation // @name Evaluations

type Evaluator

type Evaluator struct {
	// contains filtered or unexported fields
}

Evaluator engine evaluates flag from provided query

func NewEvaluator

func NewEvaluator(provider DataProvider) (*Evaluator, error)

NewEvaluator constructs evaluator with query instance

func (*Evaluator) Evaluate

func (e *Evaluator) Evaluate(key string, target Target) Evaluation

type Logger

type Logger interface {
	Debug(args ...interface{})
	Debugf(template string, args ...interface{})
	Info(args ...interface{})
	Infof(template string, args ...interface{})
	Warn(args ...interface{})
	Warnf(template string, args ...interface{})
	Error(args ...interface{})
	Errorf(template string, args ...interface{})
	Panic(args ...interface{})
	Panicf(template string, args ...interface{})
	Fatal(args ...interface{})
	Fatalf(template string, args ...interface{})
}

type PercentageRollout

type PercentageRollout struct {
	Expression string `json:"expression"`
	Serve      map[interface{}]interface{}

} // @name PercentageRollout

type Prerequisite

type Prerequisite struct {
	Feature string      `json:"feature" validate:"required"`
	Value   interface{} `json:"value" validate:"required"`

} // @name Prerequisite

type Rule

type Rule struct {
	Expression string      `json:"expression"`
	Value      interface{} `json:"value"`

} // @name Rule

type Serve

type Serve struct {
	Distribution *Distribution `json:"distribution,omitempty"`
	Variation    *string       `json:"variation,omitempty"`

} // @name Serve

func (Serve) IsEmpty

func (s Serve) IsEmpty() bool

type Target

type Target map[string]interface{} // @name Target

func (Target) GetAttrValue

func (t Target) GetAttrValue(attr string) reflect.Value

GetAttrValue returns value from target with specified attribute

type Variable

type Variable struct {
	Identifier string      `json:"identifier"`
	Value      interface{} `json:"value"`

} // @name Var

type WeightedVariation

type WeightedVariation struct {
	Variation string `json:"variation" validate:"required"`
	Weight    int    `json:"weight" validate:"required"`

} // @name WeightedVariation

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL