Design a Robust Feature Flag Evaluation Engine
CrestaSoftware Engineer · OnsiteLast updated
Implement an in-memory feature flag evaluation engine that evaluates flags against user attributes using rule predicates, deterministic percentage rollouts, and a true-wins resolution policy.
Problem Statement
Feature flagging allows systems to dynamically toggle functionality for specific users without deploying new code. You are tasked with implementing an in-memory feature flag evaluation engine.
The engine is initialized with a list of flag configurations and evaluates flag states (True or False) for given user profiles.
Configuration and Evaluation Rules
- User Schema: A dictionary containing at least an
"id"(string), plus arbitrary attribute key-value pairs (e.g.,"country":"US","age":28). - Flag Schema:
key: Unique string identifier for the flag.default_value: Boolean fallback if no rules match.rules: A list of rule definitions evaluated for each user.
- Rule Schema:
conditions: A list of predicate objects:{"attribute": str, "operator": str, "value": Any}. A rule matches if all its conditions evaluate to true (AND logic). Ifconditionsis empty, it matches unconditionally.rollout_percentage(optional): Integer[0, 100]. If present, the user must fall within this bucket to satisfy the rule.serve: Boolean value (TrueorFalse) to return if the rule matches.
- Operators:
EQUALS: User attribute value equals rule value.IN: User attribute value is present in rule value (list).GTE: User attribute value is greater than or equal to rule value (numerical comparison).- Missing/Null handling: If a condition targets an attribute that is missing or
Noneon the user, that condition evaluates toFalse.
- Deterministic Rollout: Use SHA-256 to hash
"{flag_key}:{user_id}". Compute bucket asint(sha256_hex, 16) % 100. The user is included ifbucket < rollout_percentage. - True-Wins Conflict Resolution: When multiple rules match a user, if any matched rule serves
True, the evaluated state isTrue. If rules match but all serveFalse, the state isFalse. If no rules match, fall back todefault_value. - Immutability: Input configurations and user objects must never be mutated.
Class Interface
class FeatureFlagEngine:
def __init__(self, flags_config: list[dict]):
pass
def evaluate(self, flag_key: str, user: dict) -> bool:
"""Evaluate a single flag for a user. Return default_value if flag_key is not found."""
pass
def evaluate_all(self, user: dict) -> dict[str, bool]:
"""Evaluate all registered flags for a user, returning a map of flag_key -> bool."""
pass
Example
flags = [
{
"key": "beta_dashboard",
"default_value": False,
"rules": [
{
"conditions": [{"attribute": "country", "operator": "IN", "value": ["US", "CA"]}],
"rollout_percentage": 50,
"serve": True
},
{
"conditions": [{"attribute": "beta_tester", "operator": "EQUALS", "value": True}],
"serve": True
}
]
}
]
engine = FeatureFlagEngine(flags)
user_a = {"id": "u123", "country": "US", "beta_tester": False} # sha256("beta_dashboard:u123") % 100 -> e.g. 72 (>= 50)
user_b = {"id": "u456", "country": "UK", "beta_tester": True}
engine.evaluate("beta_dashboard", user_a) # Returns False (rule 1 rollout misses, rule 2 condition fails)
engine.evaluate("beta_dashboard", user_b) # Returns True (rule 2 matches)
Constraints
- Flag keys and user IDs are non-empty ASCII strings.
rollout_percentageis an integer between0and100inclusive.- Engine should support
O(1)flag lookup and run evaluation efficiently over thousands of users.
Hints
Hint 1
Pre-index the flag definitions in a hash table keyed by flag_key during initialization to allow constant-time lookups.
Hint 2
Isolate rule predicate evaluation into a helper function and safely handle missing or mismatched attribute types without raising exceptions.
Hint 3
For the True-wins policy, iterate through matching rules: if any rule serves True, you can short-circuit and return True immediately.
Follow-up questions
- How would you support real-time configuration updates to flags without introducing race conditions during concurrent user evaluations?
- If flag evaluations emit audit telemetry logs, how would you prevent high-throughput evaluation calls from overloading downstream logging pipelines?
- How would you extend the engine to support multi-variant flags (e.g., string variants 'control', 'variant_a', 'variant_b') instead of only booleans?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.