Go Feature Flag System
Feature flags (or feature toggles) are a powerful technique for enabling or disabling features in your application without deploying new code. This allows for controlled rollouts, A/B testing, and quick rollback of problematic features. Your task is to implement a basic feature flag system in Go.
Problem Description
You need to create a Go package that allows for the dynamic management of feature flags. The system should support defining flags, enabling/disabling them, and checking their status. The primary goal is to provide a simple and efficient way for other parts of an application to query whether a specific feature should be active.
Key Requirements:
- Flag Definition: The system must allow defining feature flags with a unique name (string).
- State Management: Each flag can be either "enabled" or "disabled".
- Status Checking: A function to check the current status of a given flag.
- Dynamic Updates: The ability to programmatically enable or disable flags after they have been defined.
- Default State: Flags should have a default state (e.g., disabled) if not explicitly set.
Expected Behavior:
- When a feature flag is checked and its state is "enabled", any code guarded by that flag should execute.
- When a feature flag is checked and its state is "disabled", any code guarded by that flag should be skipped.
- Initially, all flags should be considered disabled unless explicitly enabled.
Edge Cases to Consider:
- Checking the status of a flag that has not been defined.
- Concurrent access to flag states if the system were to be used in a multithreaded environment (though for this challenge, we will focus on a single-threaded demonstration).
Examples
Example 1: Basic Usage
// Assume a FeatureFlagManager has been initialized
manager := NewFeatureFlagManager()
// Define and enable a flag
manager.EnableFeature("new-dashboard")
// Check the status
isNewDashboardEnabled := manager.IsFeatureEnabled("new-dashboard") // true
// Define another flag, leaving it disabled by default
manager.DefineFeature("experimental-search")
// Check the status of the disabled flag
isExperimentalSearchEnabled := manager.IsFeatureEnabled("experimental-search") // false
// Enable the experimental search flag
manager.EnableFeature("experimental-search")
isExperimentalSearchEnabled = manager.IsFeatureEnabled("experimental-search") // true
Output:
The isNewDashboardEnabled variable would hold true.
The isExperimentalSearchEnabled variable would first hold false and then true after enabling.
Explanation:
The first flag "new-dashboard" is defined and explicitly enabled. Therefore, IsFeatureEnabled returns true. The "experimental-search" flag is defined and remains in its default disabled state, so IsFeatureEnabled initially returns false. After calling EnableFeature for "experimental-search", its status changes to enabled, and subsequent checks return true.
Example 2: Undefined Feature
manager := NewFeatureFlagManager()
// Attempt to check a feature that has not been defined
isUnknownFeatureEnabled := manager.IsFeatureEnabled("non-existent-feature")
Output:
The isUnknownFeatureEnabled variable would hold false.
Explanation:
The IsFeatureEnabled function should gracefully handle requests for features that have not been defined, returning false by default.
Constraints
- Flag names must be non-empty strings.
- The system should be able to handle at least 100 unique feature flags without significant performance degradation for status checks.
- The implementation should be in pure Go, without relying on external feature flag services or databases.
Notes
- Consider how you will store the state of your feature flags. A map is a common and suitable data structure for this.
- Think about thread-safety. While not strictly required for a basic demonstration, a robust system would need to handle concurrent access. For this challenge, you can assume a single-threaded context for simplicity, or if you choose to implement thread-safety, clearly document it.
- Your solution should include a way to initialize your feature flag manager and functions to manipulate and query flag states.