Skip to content

Commit d67ac85

Browse files
committed
docs(oep): clarify OpenFeature toggle implementation and adoption strategy
Add example Django implementation and clarify synchronization problems solved by OpenFeature. Document SDK adoption strategy and toggle metadata approach.
1 parent eb1028f commit d67ac85

File tree

1 file changed

+98
-6
lines changed

1 file changed

+98
-6
lines changed

oeps/best-practices/oep-0068-bp-openfeature-toggles.rst

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ Abstract
4141

4242
OpenFeature is an open standard and ecosystem for managing feature toggles across
4343
various languages and frameworks. This offers a single, consistent format for managing
44-
the ubiquitous toggles in Open edX to improve their discoverability and maintenance.
44+
the ubiquitous toggles in Open edX to improve their discoverability and maintenance. The
45+
core problem that adoption of OpenFeature addresses is the need to synchronize different
46+
toggle settings across the boundaries of repositories and processes.
4547

4648
Motivation
4749
**********
@@ -78,6 +80,19 @@ the adoption of OpenFeature, the differently named toggles that share purpose ac
7880
repositories will be aligned. This will enable operators to manage a single toggle
7981
setting to enable the functionality across the full Open edX stack.
8082

83+
The adoption of OpenFeature will be through the use of their provided Python and
84+
JavaScript SDKs. Those SDKs already encapsulate the interfaces mandated by the
85+
specification, freeing the Open edX community from having to implement those
86+
capabilities on their own. The adoption of those SDKs can happen within the existing
87+
libraries used and maintained by the Open edX community, namely edx-toggles for IDAs and
88+
frontend-platform for MFEs.
89+
90+
The current approach of annotating toggles with explicit metadata will be
91+
maintained. The OpenFeature specification and client implementations do not provide any
92+
method for annotating flags in the context of the source code. Providers are able to
93+
populate metadata that is returned as part of the evaluation response, but this is not
94+
versioned and maintained in the Open edX projects.
95+
8196
Rationale
8297
*********
8398

@@ -99,11 +114,88 @@ Waffle, but that will be created as part of the adoption process for this propos
99114
Reference Implementation
100115
************************
101116

102-
The reference implementation must be completed before any OEP is given "Final"
103-
status, but it need not be completed before the OEP is "Accepted". While there is
104-
merit to the approach of reaching consensus on the specification and rationale
105-
before writing code, the principle of "rough consensus and running code" is
106-
still useful when it comes to resolving many discussions.
117+
An example implementation of a Python provider that retrieves toggle values from Django settings could look like this:
118+
119+
.. code-block:: python
120+
121+
from typing import Any, Dict
122+
from django.conf import settings
123+
from openfeature.provider.provider import AbstractProvider
124+
from openfeature.flag_evaluation import FlagResolutionDetails, EvaluationContext
125+
126+
class DjangoSettingsProvider(AbstractProvider):
127+
def __init__(self):
128+
super().__init__()
129+
self.name = "Django Settings Provider"
130+
131+
def get_metadata(self):
132+
return {"name": self.name}
133+
134+
def get_bool_value(
135+
self,
136+
flag_key: str,
137+
default_value: bool,
138+
evaluation_context: EvaluationContext = None,
139+
) -> FlagResolutionDetails[bool]:
140+
value = self._get_flag_value(flag_key, default_value)
141+
return FlagResolutionDetails(value=bool(value))
142+
143+
def get_string_value(
144+
self,
145+
flag_key: str,
146+
default_value: str,
147+
evaluation_context: EvaluationContext = None,
148+
) -> FlagResolutionDetails[str]:
149+
value = self._get_flag_value(flag_key, default_value)
150+
return FlagResolutionDetails(value=str(value))
151+
152+
def get_integer_value(
153+
self,
154+
flag_key: str,
155+
default_value: int,
156+
evaluation_context: EvaluationContext = None,
157+
) -> FlagResolutionDetails[int]:
158+
value = self._get_flag_value(flag_key, default_value)
159+
return FlagResolutionDetails(value=int(value))
160+
161+
def get_float_value(
162+
self,
163+
flag_key: str,
164+
default_value: float,
165+
evaluation_context: EvaluationContext = None,
166+
) -> FlagResolutionDetails[float]:
167+
value = self._get_flag_value(flag_key, default_value)
168+
return FlagResolutionDetails(value=float(value))
169+
170+
def get_object_value(
171+
self,
172+
flag_key: str,
173+
default_value: Dict,
174+
evaluation_context: EvaluationContext = None,
175+
) -> FlagResolutionDetails[Dict]:
176+
value = self._get_flag_value(flag_key, default_value)
177+
return FlagResolutionDetails(value=dict(value))
178+
179+
def _get_flag_value(self, flag_key: str, default_value: Any) -> Any:
180+
return getattr(settings, flag_key, default_value)
181+
182+
183+
Usage of the above provider could look like:
184+
185+
.. code-block:: python
186+
187+
import openfeature.api
188+
from django.conf import settings
189+
190+
# In your Django settings.py
191+
FEATURE_FLAG_EXAMPLE = True
192+
193+
# In your application code
194+
client = openfeature.api.get_client("edx")
195+
openfeature.api.set_provider(DjangoSettingsProvider())
196+
197+
# Evaluate a flag
198+
is_enabled = client.get_boolean_value("FEATURE_FLAG_EXAMPLE", False)
107199
108200
Rejected Alternatives
109201
*********************

0 commit comments

Comments
 (0)