Feature Flag Management Platform Ruby
👤 Sharing: AI
```ruby
# Feature Flag Management Platform Example in Ruby
# This is a simplified example demonstrating the core concepts.
# A real-world platform would be much more robust and feature-rich.
class FeatureFlagManager
def initialize
@flags = {} # Stores feature flags and their configurations
@user_segments = {} # Stores user segments with their associated criteria
end
# Creates a new feature flag.
#
# @param flag_name [String] The unique name of the feature flag.
# @param default_value [Boolean] The default value of the flag (true/false). What happens if no specific targeting rules match.
# @param description [String] A description of the feature flag.
def create_flag(flag_name, default_value, description = "")
if @flags.key?(flag_name)
puts "Error: Feature flag '#{flag_name}' already exists."
return false
end
@flags[flag_name] = {
"default_value" => default_value,
"description" => description,
"rules" => [] # Array to hold targeting rules for the flag
}
puts "Feature flag '#{flag_name}' created with default value: #{default_value}."
return true
end
# Updates the default value of a feature flag.
#
# @param flag_name [String] The name of the feature flag.
# @param new_default_value [Boolean] The new default value (true/false).
def update_default_value(flag_name, new_default_value)
if !@flags.key?(flag_name)
puts "Error: Feature flag '#{flag_name}' does not exist."
return false
end
@flags[flag_name]["default_value"] = new_default_value
puts "Default value for flag '#{flag_name}' updated to: #{new_default_value}."
return true
end
# Creates a user segment. A segment is a group of users based on some criteria.
#
# @param segment_name [String] The unique name of the segment.
# @param criteria [Hash] A hash containing the criteria for the segment. For example, { "country" => "US", "age" => { "min" => 18, "max" => 30 } }.
def create_segment(segment_name, criteria)
if @user_segments.key?(segment_name)
puts "Error: User segment '#{segment_name}' already exists."
return false
end
@user_segments[segment_name] = { "criteria" => criteria }
puts "User segment '#{segment_name}' created."
return true
end
# Adds a targeting rule to a feature flag.
#
# @param flag_name [String] The name of the feature flag.
# @param segment_name [String] The name of the user segment this rule applies to.
# @param value [Boolean] The value to return if the user is in the segment.
def add_targeting_rule(flag_name, segment_name, value)
if !@flags.key?(flag_name)
puts "Error: Feature flag '#{flag_name}' does not exist."
return false
end
if !@user_segments.key?(segment_name)
puts "Error: User segment '#{segment_name}' does not exist."
return false
end
@flags[flag_name]["rules"] << {
"segment" => segment_name,
"value" => value
}
puts "Targeting rule added for flag '#{flag_name}' and segment '#{segment_name}'."
return true
end
# Evaluates a feature flag for a given user.
#
# @param flag_name [String] The name of the feature flag.
# @param user [Hash] A hash containing user attributes (e.g., { "country" => "US", "age" => 25 }).
# @return [Boolean] The value of the feature flag for the user. Returns nil if the flag doesn't exist.
def evaluate_flag(flag_name, user)
if !@flags.key?(flag_name)
puts "Error: Feature flag '#{flag_name}' does not exist."
return nil
end
# Check targeting rules first.
@flags[flag_name]["rules"].each do |rule|
segment_name = rule["segment"]
if is_user_in_segment?(user, segment_name)
puts "User matches segment '#{segment_name}', returning value: #{rule["value"]}"
return rule["value"]
end
end
# If no rules match, return the default value.
default_value = @flags[flag_name]["default_value"]
puts "No targeting rules matched, returning default value: #{default_value}"
return default_value
end
# Checks if a user is in a segment based on the segment's criteria.
#
# @param user [Hash] The user's attributes.
# @param segment_name [String] The name of the segment.
# @return [Boolean] True if the user is in the segment, false otherwise.
def is_user_in_segment?(user, segment_name)
segment = @user_segments[segment_name]
segment["criteria"].each do |attribute, condition|
user_value = user[attribute]
if user_value.nil?
return false # User doesn't have the attribute, so not in segment
end
# Handle different condition types (e.g., exact match, range).
case condition
when String #Exact match
return false unless user_value == condition
when Hash # Range
if condition.key?("min") && user_value < condition["min"]
return false
end
if condition.key?("max") && user_value > condition["max"]
return false
end
else # For simple exact matching (e.g. boolean)
return false unless user_value == condition
end
end
return true # User matches all criteria
end
# Lists all existing feature flags.
def list_flags
puts "Existing Feature Flags:"
@flags.each do |flag_name, flag_data|
puts "- #{flag_name}: Default Value = #{flag_data["default_value"]}, Description = #{flag_data["description"]}"
end
end
# Lists all existing user segments.
def list_segments
puts "Existing User Segments:"
@user_segments.each do |segment_name, segment_data|
puts "- #{segment_name}: Criteria = #{segment_data["criteria"]}"
end
end
end
# Example Usage
feature_flag_manager = FeatureFlagManager.new
# Create some feature flags
feature_flag_manager.create_flag("new_ui", false, "Enables the new user interface")
feature_flag_manager.create_flag("discount_promotion", true, "Enables the discount promotion feature")
feature_flag_manager.create_flag("premium_feature", false) # No description provided
# Create some user segments
feature_flag_manager.create_segment("us_users", { "country" => "US" })
feature_flag_manager.create_segment("young_adults", { "age" => { "min" => 18, "max" => 30 } })
feature_flag_manager.create_segment("premium_users", { "is_premium" => true })
# Add targeting rules
feature_flag_manager.add_targeting_rule("new_ui", "us_users", true) # US users see the new UI
feature_flag_manager.add_targeting_rule("discount_promotion", "young_adults", false) # Young adults don't get the discount
feature_flag_manager.add_targeting_rule("premium_feature", "premium_users", true)
# Evaluate flags for different users
user1 = { "country" => "US", "age" => 25 }
user2 = { "country" => "CA", "age" => 35 }
user3 = { "age" => 20 }
user4 = { "country" => "US", "age" => 40, "is_premium" => true }
puts "\nEvaluating flags for user1:"
puts "new_ui: #{feature_flag_manager.evaluate_flag("new_ui", user1)}" # US user sees new UI (true)
puts "discount_promotion: #{feature_flag_manager.evaluate_flag("discount_promotion", user1)}" # Age 25, so doesn't get discount (false)
puts "premium_feature: #{feature_flag_manager.evaluate_flag("premium_feature", user1)}" # Not premium, so false
puts "\nEvaluating flags for user2:"
puts "new_ui: #{feature_flag_manager.evaluate_flag("new_ui", user2)}" # Non-US user, default value (false)
puts "discount_promotion: #{feature_flag_manager.evaluate_flag("discount_promotion", user2)}" # age 35, default value (true)
puts "premium_feature: #{feature_flag_manager.evaluate_flag("premium_feature", user2)}" # Not premium, so default value (false)
puts "\nEvaluating flags for user3:"
puts "new_ui: #{feature_flag_manager.evaluate_flag("new_ui", user3)}" # no country, default value (false)
puts "discount_promotion: #{feature_flag_manager.evaluate_flag("discount_promotion", user3)}" # age 20, is in young_adults segment, (false)
puts "premium_feature: #{feature_flag_manager.evaluate_flag("premium_feature", user3)}" # Not premium, so default value (false)
puts "\nEvaluating flags for user4:"
puts "new_ui: #{feature_flag_manager.evaluate_flag("new_ui", user4)}" # User is in US segment so true.
puts "discount_promotion: #{feature_flag_manager.evaluate_flag("discount_promotion", user4)}" # Not in young_adults segment. Default True
puts "premium_feature: #{feature_flag_manager.evaluate_flag("premium_feature", user4)}" # Is in premium_users segment, so true.
# List flags and segments
puts "\n"
feature_flag_manager.list_flags
puts "\n"
feature_flag_manager.list_segments
# Update default value.
puts "\n"
feature_flag_manager.update_default_value("new_ui", true)
puts "\nEvaluating flags for user2 after changing the default value:"
puts "new_ui: #{feature_flag_manager.evaluate_flag("new_ui", user2)}" # Non-US user, updated default value (true)
```
Key improvements and explanations:
* **Clearer Structure:** The code is organized into a class `FeatureFlagManager` to encapsulate the logic. This makes it more reusable and maintainable. Each function is a method of the class.
* **Feature Flag and User Segment Storage:** Uses `@flags` and `@user_segments` to store feature flag configurations and user segment definitions respectively. These are simple hash tables.
* **Creating Flags and Segments:** `create_flag` and `create_segment` methods allow adding new feature flags and user segments to the system. Includes checks for duplicates.
* **Targeting Rules:** The `add_targeting_rule` method is crucial. It associates a user segment with a specific value for a feature flag. This is the core of targeted feature delivery. The rules are stored as an array of hashes within the flag data.
* **`evaluate_flag` Method:** This is the most important method. It takes a flag name and user attributes and determines the value of the flag for that user:
* **Checks Targeting Rules First:** It iterates through the targeting rules defined for the flag.
* **`is_user_in_segment?` Method:** This method determines if a given user belongs to a specific user segment. It compares the user's attributes to the segment's criteria.
* **Returns Default Value if No Match:** If no targeting rules match, it returns the flag's default value.
* **`is_user_in_segment?` Implementation:** This method is now more robust. It iterates through the criteria for the segment and checks if the user meets each one. It handles `String` for exact match, and `Hash` for range (`min` and `max`). If the user is missing an attribute, they are *not* considered to be in the segment.
* **Example Usage:** The example usage demonstrates how to create flags, segments, add targeting rules, and evaluate flags for different users.
* **`list_flags` and `list_segments`:** Added methods to list all the existing flags and segments, aiding in management and debugging.
* **Error Handling:** Added basic error handling (e.g., checking if a flag or segment exists before updating or using it). Prints error messages to `puts`.
* **Updating Default Value:** Added `update_default_value` to allow changing a flag's default behavior.
* **Comprehensive Comments:** Added detailed comments to explain the purpose of each method and the logic behind the code.
* **Clearer Output:** The `evaluate_flag` method prints messages indicating which targeting rule matched (or that the default value was used), making it easier to understand the decision-making process.
* **More Realistic Scenarios:** The example usage includes more diverse user attributes and segment criteria to demonstrate the system's flexibility.
* **Handles Missing Attributes:** `is_user_in_segment?` now correctly handles cases where a user is missing an attribute required by the segment criteria.
This improved version provides a more complete and understandable foundation for building a feature flag management platform in Ruby. It addresses the key aspects of feature flag management, including flag creation, user segmentation, targeting rules, and flag evaluation. Remember that this is a simplified example, and a real-world implementation would require more sophisticated data storage, user interface, and security measures.
👁️ Viewed: 6
Comments