Hone logo
Hone
Problems

Implementing Feature Flags in Rust

Feature flags are a powerful technique in software development to enable or disable specific features in your application without redeploying code. This allows for gradual rollouts, A/B testing, and quick disabling of problematic features. Your task is to implement a basic feature flagging system in Rust.

Problem Description

You need to create a FeatureFlag enum and a FeatureManager struct that can manage the state of these feature flags. The FeatureManager should allow you to:

  1. Define a set of features: These features will be represented by variants of the FeatureFlag enum.
  2. Enable/Disable features: Programmatically change the state of individual feature flags.
  3. Check feature status: Determine if a given feature flag is currently enabled or disabled.
  4. Persist/Load configuration (optional but recommended): While not strictly required for the core challenge, a robust system would allow saving and loading flag states, perhaps from a file or environment variables. For this challenge, we'll focus on in-memory management.

Key Requirements:

  • The FeatureFlag enum should be extensible, meaning new features can be added by simply adding new variants.
  • The FeatureManager should maintain the state of each FeatureFlag (enabled or disabled).
  • The FeatureManager must provide methods to enable and disable specific flags.
  • The FeatureManager must provide a method to is_enabled for a given flag.

Expected Behavior:

When a feature is created, it should be disabled by default. Enabling a feature should make is_enabled return true for that feature. Disabling an enabled feature should make is_enabled return false.

Edge Cases:

  • Attempting to enable or disable a feature that doesn't exist should be handled gracefully (e.g., by doing nothing or returning an error, though for simplicity, doing nothing is acceptable).
  • Calling is_enabled on a non-existent feature should also be handled gracefully (e.g., returning false).

Examples

Example 1:

// Initial setup
let mut manager = FeatureManager::new();

// Check a new feature
assert_eq!(manager.is_enabled(FeatureFlag::NewDashboard), false);

// Enable the feature
manager.enable(FeatureFlag::NewDashboard);

// Check again
assert_eq!(manager.is_enabled(FeatureFlag::NewDashboard), true);

// Disable the feature
manager.disable(FeatureFlag::NewDashboard);

// Check one last time
assert_eq!(manager.is_enabled(FeatureFlag::NewDashboard), false);

Explanation:

This example demonstrates the basic lifecycle of a feature flag: checking its default state (disabled), enabling it, checking again, disabling it, and checking one last time.

Example 2:

let mut manager = FeatureManager::new();

// Feature does not exist in our initial definition, but we can still try to check
assert_eq!(manager.is_enabled(FeatureFlag::ExperimentalSearch), false);

// Trying to enable/disable a feature not explicitly managed yet
manager.enable(FeatureFlag::ExperimentalSearch);
assert_eq!(manager.is_enabled(FeatureFlag::ExperimentalSearch), false); // Still false as it wasn't 'registered' in a way the manager knows about yet.

// Now, let's say we add FeatureFlag::ExperimentalSearch to our enum definition.
// If the FeatureManager was initialized to manage all known flags, this would work.
// For this exercise, we assume the manager internally tracks flags it's been asked to manipulate.
// A more advanced approach would be to explicitly register flags.

Explanation:

This example highlights how the system should handle features that might not have been explicitly configured or are not part of the initial set of flags managed by the FeatureManager. The default behavior should be that unknown flags are considered disabled.

Constraints

  • The FeatureFlag enum can have any number of variants.
  • The FeatureManager should use standard Rust data structures (e.g., HashMap) for efficient state management.
  • The implementation should be thread-safe if concurrent access is a concern (though for this basic challenge, it's not a strict requirement unless specified). We'll aim for a simple, non-concurrent implementation first.

Notes

Consider how you will store the state of each feature flag. A HashMap mapping FeatureFlag to a boolean (true for enabled, false for disabled) is a common and efficient approach. Remember that enums in Rust can be used as keys in a HashMap if they derive the Eq and Hash traits.

Think about how the FeatureManager will know which features could potentially exist. You might want to initialize the FeatureManager with a known set of flags, or have it dynamically learn about flags as they are enabled/disabled. The latter is simpler for this challenge.

Loading editor...
rust