How to: Implement the right toggle type

First choose the general type of toggle and then the more specific implementation below.

There is also a decision map in OEP-17 on feature toggles.

Choosing the general toggle type

type

description

config as data

config as code

beyond on/off

Boolean Django Settings

Boolean Django Settings are simple on/off toggles. At edX, this would be set and deployed via remote config.

X

Waffle Switches

Waffle switches are simple on/off toggles. These are configured through Django admin.

X

Waffle Flags

Waffle flags are on/off toggles with a variety of other capabilities, such as percent rollout, setting for individual users or courses, etc. These are configured through Django admin.

X

Percent rollout, setting by user or course, potentially handles A/B experiments.

Config Models with Boolean Fields

Config models enable more complex configuration models with audit capabilities. Like Django Settings, config models would only contain toggles if it contained boolean fields. These are configured through Django admin.

X

Using your toggle

This section covers waffle switches and flags as well as Django Settings toggles. For information on Configuration Models refer to that library.

Creating toggles

Flags and switches are created with a name. The namespace prefix is used to categorize them and prevent conflicts.

FLAG_FOO = WaffleFlag('namespace.feature', module_name=__name__)
SWITCH_BAR = WaffleSwitch('namespace.feature', module_name=__name__)
SETTING_TOGGLE_BAZ = SettingToggle("SETTING_NAME", default=False, module_name=__name__)

Administering and testing toggles

For the waffle flag and switch, you will use Django Admin “waffle” section to configure for a flag named namespace.feature. Setting toggles are a wrapper around standard Django settings.

Functions to override waffle flags in test are provided in testutils.

Accessing toggles

Unlike the underlying waffle and settings libraries which look up values by name, toggles are imported and used directly:

from whereever import FLAG_FOO, SWITCH_BAR, SETTING_TOGGLE_BAZ

FLAG_FOO.is_enabled()
SWITCH_BAR.is_enabled()
SETTING_TOGGLE_BAZ.is_enabled()

State used by toggles

Obviously since some toggles take into account the user they must have more data than the zero arguments of is_enabled().

Waffle switches and flags have a few hidden sources of information. Both use a per-request cache, so a toggle value is stable during a request if there is one. Flags (including Course and Experiment types) additionally access the request via crum.get_request and through it the user. This means that in an environment without a request, flags will fail unless they are turned on for everyone like a simple switch.

Settings toggles are unsurprisingly reading from the django settings object.

Using other toggles

As a best practice, when implementing toggles in a library, we recommend keeping those toggles limited to private or internal use within the library. In other words, only code within the library should refer directly to the toggle.

If you wish to expose whether a library, service, or feature is available to its consumers, we recommend you instead expose a boolean method that may be implemented by wrapping a toggle.

Documenting your new toggle

As part of implementing your new toggle, read how to document the toggle, which should also help you think through the use cases and life expectancy of the toggle.

Toggle Implementation References

For additional details, see references to the actual toggle class implementations.

Django Setting toggles

Use the SettingToggle and SettingDictToggle classes to implement toggles based on a Django Setting. This new class should be added to the Django app that most closely relates to the setting. See the ADR for the Setting Toggle classes to understand the advantages over using the Django Setting directly.

If the toggle is being added to edx-platform, and it needs to be used by both LMS and Studio, you can add it to openedx/core/toggles.py.

Avoid referring to boolean Django Settings directly. However, if a boolean setting toggle is implemented without one of the wrapping classes, its annotation implementation would be DjangoSetting.

Waffle Switches

Use the WaffleSwitch class, a wrapper around the waffle switch.

If you are wrapping a legacy switch that does not have a namespaced name (i.e. no . in the name), use the NonNamespacedWaffleSwitch instead.

Waffle Flags

For the basic capabilities, use the WaffleFlag class, a wrapper around the waffle flag.

If you are wrapping a legacy flag that does not have a namespaced name (i.e. no . in the name), use the NonNamespacedWaffleFlag instead.

In edx-platform, there is also:

  • CourseWaffleFlag: A WaffleFlag that adds override capabilities per course and per organization.

  • ExperimentWaffleFlag: A somewhat complex CourseWaffleFlag that enables bucketing of users for A/B experiments.

Config Models

A ConfigurationModel can be used if all other options do not suit your needs. In most cases, it is no longer necessary.