To learn more about feature toggles and how they are used and reported on, see OEP-17: Feature Toggles.
The documentation for feature toggles is a crucial source of information for a very wide audience, including Open edX operators, product owners and developers. The documentation will be available to developers directly in code, and extracted into a human-readable document to be used by all audiences, and especially for Open edX operators.
Please keep all of these audiences in mind when crafting your documentation.
Copy-paste this boilerplate template to document a feature toggle:
# .. toggle_name: SOME_FEATURE_NAME # .. toggle_implementation: WaffleFlag OR WaffleSwitch OR CourseWaffleFlag OR ExperimentWaffleFlag OR ConfigurationModel OR SettingToggle OR SettingDictToggle OR DjangoSetting # .. toggle_default: True OR False # .. toggle_description: Add here a detailed description of the consequences of enabling this feature toggle. # Note that all annotations can be spread over multiple lines by prefixing every line after the first by # at least three spaces (two spaces plus the leading space). # .. toggle_warnings: (Optional) Add here additional instructions that users should be aware of. For instance, dependency # on additional settings or feature toggles should be referenced here. If this field is not needed, simply remove it. # .. toggle_use_cases: temporary OR circuit_breaker OR vip OR opt_out OR opt_in OR open_edx # .. toggle_creation_date: 2020-01-01 # .. toggle_target_removal_date: 2020-07-01 (this is required if toggle_use_cases includes temporary. If not, simply remove it.) # .. toggle_tickets: (Optional) https://openedx.atlassian.net/browse/DEPR-xxx, https://github.com/edx/edx-platform/blob/master/docs/decisions/xxx.rst, https://github.com/edx/edx-platform/pull/xxx (details initial feature) SOME_FEATURE_NAME = ...
Annotations can also be written in docstrings. This is particularly useful for documenting a ConfigurationModel class, for instance:
class SomeFeatureFlag(ConfigurationModel): """ .. toggle_name: SomeFeatureFlag.enabled .. toggle_implementation: ConfigurationModel ... """
Most annotation fields are self-explanatory. In this section we describe in more details some of the more complex annotation fields.
Must be one of the following:
“SettingToggle”, “SettingDictToggle”: for objects that inherit from each of these.
“DjangoSetting”: for boolean Django Setting toggles that do not yet use the setting toggle classes.
“WaffleFlag”, “WaffleSwitch”, “CourseWaffleFlag”, “ExperimentWaffleFlag”: for objects that inherit from each of these.
“ConfigurationModel”: for objects that inherit from this.
For more details. see How to: Implement the right toggle type.
To decide what are the use cases of a feature toggle, one should refer to the list of use cases outlined in OEP-17 on feature toggles:
.. toggle_use_cases: temporary):
Use Case 1: Incremental Release (expected timeline: 3 months)
Use Case 2: Launch Date (expected timeline: 3 months)
Use Case 3: Ops - Monitored Rollout (expected timeline: 3 months)
Use Case 5: Beta Testing (expected timeline: 6 months)
Use Case 4: Ops - Circuit Breaker (expected timeline: 5 years,
.. toggle_use_cases: circuit_breaker)
Use Case 6: VIP / White Label (expected timeline: 5 years,
.. toggle_use_cases: vip)
Use Case 7: Opt-out/Opt-in (expected timeline: 2 years,
.. toggle_use_cases: opt_out or
.. toggle_use_cases: opt_in)
Use Case 8: Open edX option (expected timeline: 3 years,
.. toggle_use_cases: open_edx)
Bias should be toward “temporary” toggles.
See OEP-17: Feature toggles use cases for reasons and tips to avoid “permanent” toggles.
For “temporary” toggles, you must include
toggle_target_removal_date. See below.
For “temporary” toggles, see
toggle_tickets below for recommendations.
Set to the target date planned for removal of the toggle.
Use YYYY-MM-DD format (e.g. 2021-04-07).
Required for “temporary” toggles.
Do not include this annotation for “permanent” toggles. Mark as “temporary” instead.
If the date is uncertain, add 3-6 months to the creation date.
This is not a commitment, but may be used to trigger a conversation about removal.
For legacy toggles, it is ok for this date to be in the past.
If you want to highlight a dependency on a named release, add additional notes to the
toggle_description as appropriate.
toggle_tickets annotation was intended for removal tickets for “temporary” toggles. This might include:
a link to a DEPR(ecation) ticket, and/or
a link to a JIRA ticket created to clean-up the “temporary” toggle.
This annotation is now also used to provide links to other useful supporting documentation, with the following considerations:
Prefer using links to more permanent documentation, like ADRs, how-tos, READMEs, etc.
Try to avoid links to PRs or private JIRA tickets. Some alternatives solutions include:
toggle_warning with additional notes.
Update the PR description of the PR that adds or updates the annotation to include the links, if they don’t need to be a part of the annotation.
Write a more permanent doc and use it instead.
If it still makes sense to use the link, include it with context (see below).
If the link url doesn’t contain context (e.g. PRs or JIRA tickets other than DEPR), add the context with additional text. For example:
toggle_tickets: https://openedx.atlassian.net/browse/XXXX-XXX (private clean-up ticket)
Note that all annotation fields can be wrapped on multiple lines, as long as every line after the first is prefixed by at least three empty spaces, two spaces plus the base indentation of the first line. For instance:
# .. toggle_description: line 1 # line2
Note also that the annotation values will be considered as raw text and will not be parsed in any way. For instance, links and text formatting such as bold, italic or verbatim tags are currently unsupported. This might change in the future.
If you have a really long line, for example with a url that you don’t want to break up, you may need to disable pylint using the following:
# .. toggle_tickets: https://some.com/long/url/that/you/dont/want/to/break/up.rst # pylint: disable=line-too-long,useless-suppression
If a toggle needs to be synchronized across services:
toggle_description could state that you should read the description for the same toggle in XXX service, rather than duplicating a description.
toggle_warnings should note that the value must be consistent with XXX service. XXX will often be the LMS, but not necessarily.
If we are setting a default for a toggle from a third-party library, include a link to the third-party library documentation for the toggle.
This section is specifically geared toward documenting feature toggles that were implemented in the Open edX codebase before this annotation capability existed.
Here are a number of techniques you might use to learn about an existing toggle. Please add any helpful background links to the PR description of the PR that is adding the annotation.
Search github by replacing the toggle name in the following search url:
git blame or
git log search (a.k.a. pickaxe).
Search the additional reference tab of the toggle docathon spreadsheet.
When not a security concern, asking edX.org to compare its Production setting to the default can sometimes shed some light.
Undocumented boolean Django Setting toggles defined in the Open edX codebase are probably not yet defined using a
SettingDictToggle. Read about implementing these toggle classes in How to: Implement the right toggle type.
WaffleFlag instead of
WaffleSwitch instead of
Initialize these new classes with a single string that includes the fully namespaced toggle name, including the period.
waffle.flag_is_active with a new documented
waffle.switch_is_active with a new documented
If the flag or switch name is not namespaced (i.e. doesn’t contain a
.), use the
NonNamespacedWaffleSwitch class. All newly defined feature toggles should be namespaced, so these classes only support legacy toggles.
For more details on the individual annotations, see OEP-17: Feature Toggles.
The documentation format used to annotate feature toggles is stored in the code-annotations repository: feature_toggle_annotations.yaml.
See how-to document non-boolean Django settings, for Django settings which are not feature toggles.