npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

opticks

v5.1.3

Published

FindHotel Toggle Flag JavaScript SDK

Downloads

3,922

Readme

Feature toggles and A/B tests are wonderful, but can easily introduce debt in your codebase.

This project allows you to experiment and automatically clean up your JavaScript experimentation code after the experiment concludes using JSCodeShift codemods.

The library consists of two related concepts:

  • The Toggle library, a simple API for introducing toggles and A/B tests in your codebase
  • Codemods for cleaning up toggle code

Toggle Library

At the heart of our experimentation framework is the toggle function.

A toggle allows you to switch between multiple experiment variants (a/b/c/...) and also turn functionality on or off (feature flags)

It can be used in a variety of ways:

  1. Reading the value of the toggle (boolean, or a/b/c for multi toggles )
  2. Execute code or for a variant of a multi toggle
  3. Execute code when a boolean toggle is on

We use React at vio.com and some of the code examples use JSX, but the code and concept is compatible with any front-end framework or architecture.

Opticks vs other experimentation frameworks

The main reason for using the Opticks library is to be able to clean your code afterwards by providing a predictable experimentation API.

We don't intend to reinvent the wheel and aim to keep it easy to integrate existing frameworks and services such as Optimizely, LaunchDarkly and Conductrics behind a simple facade.

Usage and Integrations

Currently Opticks has two 'integrations' or adapters, a simple one based on a local key/value store, and one wrapping the Optimizely Full Stack SDK. Once initialized, using/consuming the toggle decisions is the same.

In the future the integrations will be packaged separately so you can include the one you need, for now the "simple" is the default and the Optimizely adapter can be included directly via: import Opticks from 'opticks/lib/optimizely'

Integrations

Simple

See the Simple integration documentation.

Optimizely

See the Optimizely integration documentation.

Toggles

Toggles can be used to implement a/b/c style MVT testing and on/off feature flags as well. We specify multiple variants of which only one is active at any time. By convention the variants are named a (control), b, c etc.

Reading values

While it's recommended to use the strategy described in executing code for variants, the following shows how the variant executing and code clean up works under the hood.

The simplest signature is as follows, to read the toggle value directly:

toggle(experimentId: string) => { variant: 'a' | 'b' | 'c' | 'd' | ... }

For example when the user is assigned to the b side:

const fooResult = toggle('foo')
if (fooResult === 'b') console.log('b side of the foo experiment')

This works fine, but will result in code that will be hard to clean up automatically. Considering the codemods replace the toggle with the 'winning' value (b in this case):

const fooResult = 'b'
if (fooResult === 'b') console.log('b variant of the foo experiment')

This would leave your code more messy than necessary. You could skip the intermediate value but it will still result in awkward leftover code:

if (toggle('foo') === 'b') ...

// becomes
if ('b' === 'b') ...
// or
if ('a' === 'b') ...

Rather than reading the return value directly, you can map your variant to arguments to the toggle function, like so:

// Defines the result if that toggle or experiment wins, either a function that
// will be executed, or any other value
type ToggleResultType = function | any

// do something for a/b/c variant:
toggle(
  experimentId,
  variantA: ToggleResultType,
  variantB: ToggleResultType,
  ?variantC: ToggleResultType,
  ...
)

The signature might look more complicated, but it allows you to define what the results for your variants a, b, c etc map to. The first value is the experimentId, then the values for a, b, etc.

For instance:

// simple boolean switch
const shouldDoSomething = toggle('foo', false, true)

// multiple variants as strings
// 'black' is the default, red and green are variants to experiment with
const buttonColor = toggle('foo', 'black', 'green', 'red')

The benefit is that after concluding your experiment, you can integrate the winning variation's code directly without awkward references to a or b etc.

After you run the codemods to declare b the winner, the corresponding raw value is kept:

const shouldDoSomething = toggle('foo', false, true)
const buttonColor = toggle('foo', 'black', 'green', 'red')

// becomes:
const shouldDoSomething = true
const buttonColor = 'green'

Much better already, but there is more room for improvement, especially if you want to do things conditionally for a variant.

Consider the following set up:

const shouldShowWarning = toggle('shouldShowWarning', false, true)
if (shouldShowWarning) showWarning()

// or directly:
if (toggle('shouldShowWarning', false, true)) showWarning()

This would end up with an orphaned conditional after the codemods did their cleaning:

const shouldShowWarning = true
if (shouldShowWarning) showWarning()

// or directly
if (true) showWarning()

The next section explains a more useful concept for this type of conditional branching.

Executing code for variants

A better approach that allows you to clean the code easier would be to encapsulate variant logic by executing code from the toggle:

const price = 100
const savings = 20

const CTA = toggle(
  'CTAWording',
  () => `Buy now for just ${price}` // variant a (default)
  () => `Buy now for ${price} and save ${savings}`, // variant b
  () => `From ${price + savings} to ${price}` // variant c
)

Then after running the cleaning codemods when the b variant wins:

const price = 100
const savings = 20

const CTA = `Buy now for ${price} and save ${savings}`

Or for an example of conditionally calling code:

alwaysDoSomething()
toggle('shouldShowWarning', null, () => shouldShowWarning())

This shows two special concepts of the codemods, passing a null and the use of arrow functions. Passing null allows for full clean up when that branch loses. For winners, the body of the arrow function is kept as-is.

After running the codemods with the winning b variant:

alwaysDoSomething()
shouldShowWarning() // no trace this was the result of a winning experiment

But if a would have won:

alwaysDoSomething()
// no trace that something was experimented with but lost

Removal of dead code

Above are just a few examples of how the codemods operate on the code. For instructions and more recipes, see Removal of dead code.