Further Reading

πŸ’‘ The Problem Statement

"Design a Feature Flag System like LaunchDarkly that allows teams to dynamically enable or disable features without redeploying code."


πŸ”₯ Functional Requirements

βœ… Toggle Features Dynamically – Features can be turned ON/OFF without redeploying.

βœ… Targeting Rules – Flags can be enabled per user, per region, or percentage-based rollouts.

βœ… Real-Time Updates – Changes should take effect instantly across all users.

βœ… Client SDKs – Apps should be able to fetch feature flag values via an API.

βœ… Audit Logs – Track who changed what & when.

βš™οΈ Non-Functional Requirements

πŸš€ Low Latency – Feature flag evaluation must be fast (<5ms per request).

βš– High Availability – The system should handle millions of requests per second.

πŸ”„ Eventual Consistency – Flags can propagate with a slight delay but should be eventually consistent.

πŸ“ˆ Scalability – Must work for millions of users & feature flags.


⏳ Constraints & Assumptions

πŸ“Œ Feature flags are read-heavy (90% reads, 10% writes).

πŸ“Œ Some flags require real-time updates, while others can be cached.

πŸ“Œ System should support SDK-based polling & server-side evaluation.

High-Level Architecture

The system should support a high number of feature flags, efficient flag evaluations, and real-time updates to ensure that the most recent changes are reflected across all clients. The architecture should focus on scalability, high availability, low latency, and eventual consistency.

Components:

  1. API Layer:
  2. Database:
  3. Caching Layer:
  4. Real-Time Updates:
  5. SDKs:
  6. Audit Logs:

Detailed Breakdown - Database

We will use PostgreSQL for storing persistent data, and Redis for caching. Here’s how the tables and structures might look:

  1. Feature Flags Table:

    CREATE TABLE feature_flags (
      flag_id SERIAL PRIMARY KEY,
      name VARCHAR(255) NOT NULL,
      description TEXT,
      type ENUM('boolean', 'string', 'number') NOT NULL,
      filter_key ENUM('user', 'region', 'percentage') NOT NULL,
      filter_value JSONB,  -- This stores targeting rules in JSON format
      is_active BOOLEAN DEFAULT TRUE,
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );
    
  2. Change Tracking Table (Audit Logs):

    CREATE TABLE feature_flag_changes (
      change_id SERIAL PRIMARY KEY,
      flag_id INT REFERENCES feature_flags(flag_id),
      user_id INT NOT NULL,  -- User who made the change
      change_type ENUM('created', 'updated', 'deleted') NOT NULL,
      change_description TEXT,
      timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );
    
  3. Flag Targeting Table:

    CREATE TABLE flag_targeting (
      targeting_id SERIAL PRIMARY KEY,
      flag_id INT REFERENCES feature_flags(flag_id),
      filter_key ENUM('user', 'region', 'percentage') NOT NULL,
      filter_value JSONB,  -- Specific targeting data (e.g., a list of users, regions, or percentage)
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );
    
  4. Real-Time Flag Updates (Cache):

    Redis keys might look like:

  5. Message Queue (Kafka/RabbitMQ):

API Layer (RESTful)

  1. GET /flags:

    Example response:

    [
      { "flag_id": 1, "name": "NewFeatureX", "is_active": true, "description": "Enable new feature" },
      { "flag_id": 2, "name": "BetaFeature", "is_active": false, "description": "Beta testing feature" }
    ]
    
  2. POST /flag:

  3. PUT /flag/{flagId}:

  4. DELETE /flag/{flagId}:

Real-Time Updates (WebSockets/SSE)

  1. WebSockets/SSE:

Consistency and Availability

Audit Logs:

SDKs: