Your interview for that Principal Engineer role at Stripe will likely hit you with a systems design question involving feature flags. They're a fundamental primitive in modern distributed systems, not just a deployment trick. You'll need to move beyond "toggle on/off" and really understand the nuances, especially around rule precedence.
Why Feature Flags Matter Beyond Toggles
I’ve seen too many candidates treat feature flags as a simple boolean config. That’s a junior-level understanding. At Google, where I spent five years, we used an internal system called "Flags" (creative, right?) that handled billions of evaluations per second. It wasn't just for A/B tests or canary rollouts. Flags managed experimental features, region-specific behavior, and even user experience variations based on subscription tiers. The key distinction: a flag isn't just a boolean; it's a configurable decision point in your code. This decision might return a boolean, an integer, a string, or even a complex JSON object.
Think about a new search algorithm. You don’t just turn it on for everyone. You expose it to internal users, then 1% of beta users, then 5% of a specific geo, then 50% of mobile users in that geo, and finally 100%. Each of these steps requires dynamic control. This isn't just about A/B testing; it’s about controlled rollout, experimentation, and operational safety. If the new algorithm tanks latency, you want to revert it for just the affected group, instantly.
The Core Problem: Conflicting Rules
Here’s where rule precedence becomes critical. Imagine a user in London. We want to test a new "dark mode" feature. Rule 1: All users get dark mode (enabled: true). Rule 2: Users in London get light mode (enabled: false) because of a known bug with local ad rendering. Rule 3: Premium subscribers in London get dark mode (enabled: true) because they're a high-value segment and we have a workaround for them.
If your feature flag evaluation logic doesn’t have a clear, deterministic way to resolve these conflicts, you're in trouble. You'll get unpredictable behavior, frustrated users, and a debugging nightmare. This isn't theoretical; I've personally seen systems where a lack of proper precedence led to A/B tests canceling each other out, making results meaningless. You can't just apply the first matching rule. You need a structured approach.
Standard Precedence Strategies: From Specific to Broad
Most mature feature flag systems, whether it’s LaunchDarkly, Optimizely, or an in-house solution, implement a "most specific rule wins" strategy.
Consider a rule engine. Each rule has a set of targeting conditions. These conditions define the audience for that rule. Example conditions:
user.country == "US"user.deviceType == "mobile"user.subscriptionStatus == "premium"user.id % 100 < 5(for a 5% rollout)feature.enabledForAdmins == true(for internal testing)
When a flag is evaluated for a given user context, the system gathers all rules that match that context. If multiple rules match, precedence determines the outcome.
The most common approach is an ordered list of rules, evaluated from top to bottom. The first matching rule with the highest priority wins. How do you define priority? Often, it’s a manual ordering, where more specific rules are placed higher up the list.
Let's revisit our dark mode example with this strategy:
- Rule: Premium subscribers in London get dark mode.
- Conditions:
user.country == "UK"ANDuser.city == "London"ANDuser.subscriptionStatus == "premium" - Value:
dark_mode_enabled = true
- Conditions:
- Rule: Users in London get light mode.
- Conditions:
user.country == "UK"ANDuser.city == "London" - Value:
dark_mode_enabled = false
- Conditions:
- Rule: All users get dark mode.
- Conditions: None (or
true) - Value:
dark_mode_enabled = true
- Conditions: None (or
If a premium user in London requests the flag, Rule 1 matches first. Its conditions are more stringent. The evaluation stops, and they get true. If a non-premium user in London requests, Rule 1 doesn't match. Rule 2 matches next, and they get false. If a user in New York requests, neither Rule 1 nor Rule 2 matches. Rule 3 matches, and they get true. This explicit ordering is simple to understand and manage, but it requires careful manual placement.
Conflicting Properties: Beyond Simple Booleans
What if a flag isn't just true or false? What if it's a JSON object defining UI elements?
feature_x_config = { "button_color": "red", "text_size": "large" }
Suppose we have two rules for a flag feature_x_config:
Rule A (Applies to all users): {"button_color": "blue", "text_size": "medium"}
Rule B (Applies to beta users): {"button_color": "green", "icon": "star"}
If a beta user requests feature_x_config, and Rule B takes precedence, what's the final configuration?
Option 1: Rule B completely overrides Rule A. Result: {"button_color": "green", "icon": "star"}. The text_size from Rule A is lost.
Option 2: Rule B merges with Rule A, with Rule B's properties taking precedence on conflict. Result: {"button_color": "green", "text_size": "medium", "icon": "star"}.
Most systems choose Option 2 for complex values. It’s more flexible and less error-prone. You can define a baseline configuration at a low-priority rule, and then override specific parts of it with higher-priority rules. This is how you'd manage a default UI theme with regional or user-tier specific tweaks. The interviewers will expect you to think about these subtleties. Don't just say "it returns a value." Talk about how that value is constructed.
Interview Scenario: Designing a Feature Flag System A-Z
An interviewer might ask you to design a feature flag system. You’ll need to cover:
1. Data Model:
- Flag Definition: Unique ID, name, description, default value (if no rules match).
- Rule:
idpriority(integer, lower value means higher priority)conditions(list of key-value pairs or expressions:user.country == "US",device.os == "iOS",segment.id IN [123, 456])value(the actual setting to apply: boolean, string, JSON, int)rollout_percentage(optional, for gradual rollouts within a rule)
- User Context: A map of attributes passed at evaluation time (
user_id,country,device_type,subscription_status, etc.).
2. Evaluation Flow:
- Client (your application) sends a request to the flag service:
getFlag("dark_mode", userContext) - Flag service retrieves the flag definition and its associated rules.
- Sort rules by
priority(ascending). - Iterate through sorted rules:
a. For each rule, evaluate its
conditionsagainst the provideduserContext. b. If all conditions match: i. Checkrollout_percentage. Generate a deterministic hash based on a user ID and flag ID. If the hash falls within the percentage, this rule matches. ii. This rule is now the winning rule. Stop iteration. - If no rule matches, return the flag's
default_value. - Return the
valuefrom the winning rule.
Notice the rollout_percentage inside a rule. This is powerful. You can have a rule that says "Users in California get the new search algorithm," and within that rule, specify "only 10% of users in California." This allows for granular, multi-stage rollouts.
3. Client-Side Caching & Performance: You can't hit a central service for every flag evaluation on every request. That's a latency killer.
- Push vs. Pull:
- Pull: Clients periodically fetch all flag configurations. Good for resilience, eventually consistent.
- Push: Flag service pushes updates to clients via WebSockets or similar. Lower latency for changes, but more complex.
- Local Evaluation: The best performance comes from local evaluation. The client downloads all relevant rules and then evaluates them in-process. This means less network overhead. Tools like LaunchDarkly's SDKs do exactly this. They download a JSON blob of all rules and evaluate locally.
4. Consistency & Data Freshness: If you change a flag in the admin UI, how quickly does it propagate?
- Eventual Consistency: Most distributed systems aim for this. Changes might take a few seconds or minutes to propagate to all client instances. For critical changes, you might need a "kill switch" mechanism that bypasses caching.
- Rollback: How do you revert a bad change? A good system lets you instantly revert to a previous configuration or turn off a flag completely.
5. Operational Aspects:
- Monitoring: Track flag evaluations, error rates, and performance impact. If
new_checkout_flowcauses a 500% spike in errors, you need to know immediately. - Dashboard/Admin UI: For defining flags, rules, and monitoring. This is where product managers and ops teams live.
- Audit Logs: Who changed what, when, and why? Essential for debugging and compliance. "Who enabled the experimental payment gateway for production?"
The "It Depends" Moment and Caveats
Here’s the honest truth: the exact implementation details depend heavily on your scale, latency requirements, and team structure.
- For a small startup with a single monolith, a simple database table and an in-memory cache might suffice. You don't need a globally distributed, real-time push system.
- For a FAANG-scale application, you're talking about a dedicated global service, probably using something like Apache Kafka for event propagation, and custom SDKs in multiple languages for local evaluation. The latency budget for flag evaluation might be in the single-digit milliseconds.
Also, be careful with flag proliferation. If you have thousands of flags, managing precedence becomes extremely complex. You need good naming conventions and regular flag cleanup (archiving old flags). Old flags become technical debt and can easily obscure the true state of your system. I've worked on systems where debugging an issue meant tracing through 15 different flags, each with its own set of rules, some of which hadn't been touched in years. That's a nightmare.
Beyond Basic Precedence: Contextual Overrides and Experiments
Sometimes, simple "most specific rule wins" isn't enough. Consider a flag for "new user onboarding flow." Rule A: All new users get flow V1 (default). Rule B: New users from marketing campaign X get flow V2. Rule C: New users in an A/B test for 'gamified onboarding' get flow V3 (this is a separate experiment).
If a user comes from marketing campaign X and is part of the gamified onboarding experiment, which flow do they get? This is where an additional layer of "experiment group assignment" might come into play. Your flag evaluation might first determine if a user belongs to any active experiments, and if so, that experiment's assigned variant (e.g., flow V3) might take precedence over other general targeting rules. This is often handled by a separate experiment-management system that integrates with the feature flag system.
Another advanced concept is a "sticky" assignment. Once a user is assigned to a variant (e.g., in an A/B test), they should usually remain in that variant for consistency, even if their other attributes change. This means the system needs to persist their assigned variant and prioritize it during subsequent evaluations. This requires a lookup of past assignments before evaluating the full rule set.
Common Interview Pitfalls to Avoid
- Over-engineering for a simple case: If the interviewer gives you a small-scale problem, don't jump to Kafka and Kubernetes unless specifically prompted. Start simple and scale up.
- Forgetting edge cases: What if the
userContextis missing a required attribute? What if a rule's value is invalid? What if the flag service is down? - Ignoring performance: Always consider latency, throughput, and caching. How will your system handle millions of requests per second?
- Lack of monitoring/observability: A system without visibility is impossible to manage in production.
- Not defining terms: Clearly state your assumptions about "user context," "rule," and "flag."
When discussing precedence, don't just say "rules are applied in order." Explain why that order matters, how it's determined (manual priority, specificity algorithm), and what happens when multiple rules match. Show that you understand the determinism required. They want to see you think through the potential for conflict and how to resolve it reliably.
Mastering feature flags, especially rule precedence, shows interviewers you understand how modern, dynamic applications are built and operated. It's a foundational piece of knowledge that separates a good engineer from an excellent one. It's not just about code; it's about product control and operational safety at scale.
Ready to Ace Your Next Interview?
Practice with AI-powered mock interviews tailored to your target role and company. Start Practicing for Free | Explore Interview Prep
