Implementing a Feature Flagging System in Go
Building robust software often involves the ability to control the rollout of new features. This is crucial for A/B testing, canary releases, and gradual rollouts, allowing developers to test new functionality with a subset of users before a full release. Your challenge is to implement a foundational feature flagging system in Go.
Problem Description
You need to design and implement a Go package that allows for the dynamic enabling or disabling of features based on specific criteria. This system should be able to evaluate whether a feature is "on" or "off" for a given user or request.
Key Requirements:
- Feature Definition: Define a way to represent a feature with a unique identifier (e.g., a string name) and its current state (enabled/disabled).
- Evaluation Logic: Implement a function that takes a feature identifier and a context (representing the user or request) and returns
trueif the feature is enabled for that context, andfalseotherwise. - Contextual Targeting: The system should support basic contextual targeting. For this challenge, we will focus on a simple form of targeting: enabling a feature for a certain percentage of users.
- Configuration: The feature states and targeting rules should be configurable, allowing them to be changed without modifying the core code. For this challenge, assume the configuration is provided upfront as a data structure.
- No External Dependencies: The solution should not rely on external databases or third-party services for its core functionality.
Expected Behavior:
- When a feature is "enabled" globally, it should be considered enabled for all contexts unless specific disabling rules apply (not required for this version).
- When a feature is "disabled" globally, it should be considered disabled for all contexts.
- When a feature is enabled with a percentage rollout, the
IsEnabledfunction should returntruefor approximately that percentage of unique contexts. The uniqueness of a context will be determined by a specific identifier within the context.
Edge Cases:
- A feature that is not defined in the configuration should be treated as disabled.
- A context with no unique identifier should be handled gracefully (e.g., treated as disabled for percentage rollouts, or a default behavior).
Examples
Example 1: Basic Feature Enablement
Input Configuration:
{
"features": {
"new_dashboard": {
"enabled": true
},
"experimental_search": {
"enabled": false
}
}
}
Input Context (User ID): "user123"
Feature Name: "new_dashboard"
Output: true
Explanation: The new_dashboard feature is globally enabled in the configuration.
Input Context (User ID): "user123"
Feature Name: "experimental_search"
Output: false
Explanation: The experimental_search feature is globally disabled in the configuration.
Example 2: Percentage Rollout
Input Configuration:
{
"features": {
"new_recommendations": {
"enabled": true,
"rollout_percentage": 50
}
}
}
Input Contexts:
- User ID:
"user456" - User ID:
"user789" - User ID:
"userabc" - User ID:
"userdef" - User ID:
"userghi"
Feature Name: "new_recommendations"
Expected Output (illustrative, actual output will vary due to hashing):
"user456":true"user789":false"userabc":true"userdef":false"userghi":true
Explanation: The new_recommendations feature is enabled with a 50% rollout. The system uses a stable hashing mechanism (e.g., based on the User ID) to determine which users fall into the 50% group. In this illustrative output, 3 out of 5 users are in the enabled group.
Example 3: Undefined Feature
Input Configuration:
{
"features": {
"new_dashboard": {
"enabled": true
}
}
}
Input Context (User ID): "userxyz"
Feature Name: "non_existent_feature"
Output: false
Explanation: The non_existent_feature is not defined in the configuration, so it defaults to being disabled.
Constraints
- The feature names and user identifiers will be strings.
rollout_percentagewill be an integer between 0 and 100 (inclusive).- The hashing algorithm used for percentage rollouts must be deterministic to ensure consistent results for the same input.
Notes
- Consider how you will represent the configuration data. A
structin Go is a natural fit. - For percentage rollouts, you'll need a way to deterministically map a user identifier to a number within a specific range. Think about hashing functions.
- The
contextfor evaluation could be a simplestructcontaining relevant user information, such as a User ID. - The focus of this challenge is on the core logic of feature evaluation and percentage-based rollout. More complex targeting rules (e.g., by user attributes, geography) are out of scope for this exercise.