mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-23 00:22:19 +01:00
New sidebar navigation, updated titles (#7643)
1. Updates the folder structure of the main sidebar navigation to [a new version](https://unleash-internal.slack.com/archives/C06NG1LUUCU/p1721413054821399) 2. Updates the title of `15 Principles for using feature flag systems at scale` article to a new title given by @riboflavin 3. Updates the title of `11 Principles for building and scaling feature flag systems` article to a new title given by @riboflavin ## Before (all collapsed)  ## After (all collapsed) 
This commit is contained in:
parent
cf4435ca2d
commit
9c2b906d79
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 15 Principles for using feature flag systems at scale
|
||||
title: "Feature flag management: Best practices for using feature flags at scale"
|
||||
---
|
||||
|
||||
import Figure from '@site/src/components/Figure/Figure.tsx'
|
||||
@ -28,7 +28,11 @@ This guide is organized into three sections that align with the stages of a larg
|
||||
- [13. Never reuse feature flag names.](#13-never-reuse-feature-flag-names)
|
||||
- [14. Avoid giant feature flag targeting lists.](#14-avoid-giant-feature-flag-targeting-lists)
|
||||
- [15. Do not define business logic using feature flags.](#15-do-not-define-business-logic-using-feature-flags)
|
||||
- [Staying sane while managing feature flags at scale](#staying-sane-while-managing-feature-flags-at-scale)
|
||||
- [Dependency on 3rd party services](#dependency-on-3rd-party-services)
|
||||
- [Complexity and Maintainability](#complexity-and-maintainability)
|
||||
- [Performance Implications](#performance-implications)
|
||||
- [Security Risks](#security-risks)
|
||||
- [Keeping cool while managing feature flags at scale](#keeping-cool-while-managing-feature-flags-at-scale)
|
||||
|
||||
## Organizing your team and internal processes to support feature flags
|
||||
|
||||
@ -84,10 +88,10 @@ To be clear, the developers should still be kept in the loop (after all, when wa
|
||||
|
||||
Here are common examples that require updating flag permissions you should plan for:
|
||||
|
||||
* Permissions are wrongly scoped. Someone was left out, or someone who should not have access does.
|
||||
* Requirements changed mid-project.
|
||||
* The project owner or team lead changed.
|
||||
* Teams are reorganized.
|
||||
- Permissions are wrongly scoped. Someone was left out, or someone who should not have access does.
|
||||
- Requirements changed mid-project.
|
||||
- The project owner or team lead changed.
|
||||
- Teams are reorganized.
|
||||
|
||||
The flag lifecycle stage dictates changes in the owners.
|
||||
|
||||
@ -97,14 +101,14 @@ It is clear now that different teams will require access to flags across their l
|
||||
|
||||
Here is a partial list of things one or more users will want to do with a feature flag for which you need to configure permissions:
|
||||
|
||||
* Create
|
||||
* Delete
|
||||
* Turn-on
|
||||
* Turn-off
|
||||
* Configure targeting
|
||||
* Change rollout
|
||||
* Read configuration
|
||||
* Update configuration
|
||||
- Create
|
||||
- Delete
|
||||
- Turn-on
|
||||
- Turn-off
|
||||
- Configure targeting
|
||||
- Change rollout
|
||||
- Read configuration
|
||||
- Update configuration
|
||||
|
||||
Let’s look at a simple example: a product manager working with the development team to test a new Beta feature.
|
||||
|
||||
@ -146,7 +150,6 @@ Even if you don’t require anyone else's approval before making changes in prod
|
||||
2. You avoid making changes by mistake. If your cat walks across the keyboard, you can feel safe that they won’t accidentally expose your unfinished code to everyone.
|
||||
3. You get to review the changes before they go out. You get the full overview of the changes you’re making. You can double-check that the changes will have the effect you want.
|
||||
|
||||
|
||||
## Instrumenting your code and managing flag lifecycle
|
||||
|
||||
Flags live in code, and hundreds of small choices go into instrumenting flags into that code. Here are some tips we’ve picked up to improve the maintainability and performance of large-scale feature flag systems.
|
||||
@ -161,26 +164,26 @@ For user-facing changes (e.g., testing a light/dark mode or a new signup workflo
|
||||
|
||||
Instrumenting your code in this way has several benefits:
|
||||
|
||||
* Simplified Code: By controlling a new feature at a single location, the rest of your system doesn't need to be aware of the flag, leading to cleaner code.
|
||||
* Enhanced Testing: Easier isolation of the feature for unit and integration tests.
|
||||
* Improved maintainability: When a feature flag is used at a single location, it is easier to clean up the flag when it has served its purpose. In addition, simpler and testable code is easier to maintain over time.
|
||||
- Simplified Code: By controlling a new feature at a single location, the rest of your system doesn't need to be aware of the flag, leading to cleaner code.
|
||||
- Enhanced Testing: Easier isolation of the feature for unit and integration tests.
|
||||
- Improved maintainability: When a feature flag is used at a single location, it is easier to clean up the flag when it has served its purpose. In addition, simpler and testable code is easier to maintain over time.
|
||||
|
||||
For backend changes (e.g., a new database schema), evaluating the feature flag near the affected module is best.
|
||||
|
||||
This enables:
|
||||
|
||||
* Focused Testing: Evaluating the flag's impact within the specified module simplifies testing and debugging. You only need to consider the immediate code's behavior, making troubleshooting more efficient.
|
||||
* Isolation: Evaluating close to the module helps isolate the impact of the feature flag, reducing the risk of unintended consequences in other parts of the codebase.
|
||||
* Testable: Make sure your modules are testable. Usually, it makes sense to evaluate the flag logic outside and either inject the result or simply have two different implementations of the module. This optimizes for testability, making it straightforward to implement unit tests for both the old and the new logic.
|
||||
- Focused Testing: Evaluating the flag's impact within the specified module simplifies testing and debugging. You only need to consider the immediate code's behavior, making troubleshooting more efficient.
|
||||
- Isolation: Evaluating close to the module helps isolate the impact of the feature flag, reducing the risk of unintended consequences in other parts of the codebase.
|
||||
- Testable: Make sure your modules are testable. Usually, it makes sense to evaluate the flag logic outside and either inject the result or simply have two different implementations of the module. This optimizes for testability, making it straightforward to implement unit tests for both the old and the new logic.
|
||||
|
||||
Once you have defined your flags, striving for single evaluation points whenever possible is crucial. This reduces code complexity and potential errors from managing multiple evaluation points.
|
||||
|
||||
Here are a few examples of functionality managed by feature flags and where you should try to evaluate in your code:
|
||||
|
||||
* Recommendation Engine: When testing changes to the recommendation algorithm, evaluating the feature flag close to the recommendation module allows focused testing and isolation of the changes.
|
||||
* Database Query Optimization: Evaluating the flag near the optimized query simplifies testing and ensures the change behaves as expected within that specific query.
|
||||
* Third-Party Integrations: If a feature flag controls the integration with a third-party service, evaluating it near the integration code helps isolate the behavior changes. This simplifies testing the interaction with the third-party service based on the flag state, without affecting other integrations in the system.
|
||||
* Cache Invalidation Logic: When modifying code that invalidates cache entries based on a feature flag, evaluating the flag near that logic allows for focused testing of the cache invalidation behavior. This isolates the test from other parts of the system that could potentially interact with the cache.
|
||||
- Recommendation Engine: When testing changes to the recommendation algorithm, evaluating the feature flag close to the recommendation module allows focused testing and isolation of the changes.
|
||||
- Database Query Optimization: Evaluating the flag near the optimized query simplifies testing and ensures the change behaves as expected within that specific query.
|
||||
- Third-Party Integrations: If a feature flag controls the integration with a third-party service, evaluating it near the integration code helps isolate the behavior changes. This simplifies testing the interaction with the third-party service based on the flag state, without affecting other integrations in the system.
|
||||
- Cache Invalidation Logic: When modifying code that invalidates cache entries based on a feature flag, evaluating the flag near that logic allows for focused testing of the cache invalidation behavior. This isolates the test from other parts of the system that could potentially interact with the cache.
|
||||
|
||||
### 8. Evaluate a feature flag only once.
|
||||
|
||||
@ -188,9 +191,9 @@ Here are a few examples of functionality managed by feature flags and where you
|
||||
|
||||
When building new (often complex) features for users, systems require changes across multiple parts – modules within an application or services in a microservices architecture. While it's tempting to use a single feature flag to control all these changes and evaluate it locally in each module, we recommend against it for a few reasons:
|
||||
|
||||
* Unpredictable Timing: User requests flow through the system and touch different parts as they progress. Between each invocation, time passes. Even with perfectly synchronized feature flags, requests will hit different system parts at slightly different times. This means the flag state could change between evaluations, leading to inconsistent behavior for the user.
|
||||
* Laws of distributed computing: Particularly in distributed systems, we cannot assume all parts of the system are perfectly synchronized, as networks are unreliable and can experience transient errors at any time. Feature flag systems generally [prefer availability over consistency](feature-flag-best-practices.md#6-design-for-failure-favor-availability-over-consistency). By only evaluating a feature flag once, we guarantee a consistent experience for our users.
|
||||
* Violates Single Responsibility: Using the same flag in multiple locations spreads feature control logic throughout your codebase, violating the single-responsibility principle.
|
||||
- Unpredictable Timing: User requests flow through the system and touch different parts as they progress. Between each invocation, time passes. Even with perfectly synchronized feature flags, requests will hit different system parts at slightly different times. This means the flag state could change between evaluations, leading to inconsistent behavior for the user.
|
||||
- Laws of distributed computing: Particularly in distributed systems, we cannot assume all parts of the system are perfectly synchronized, as networks are unreliable and can experience transient errors at any time. Feature flag systems generally [prefer availability over consistency](feature-flag-best-practices.md#6-design-for-failure-favor-availability-over-consistency). By only evaluating a feature flag once, we guarantee a consistent experience for our users.
|
||||
- Violates Single Responsibility: Using the same flag in multiple locations spreads feature control logic throughout your codebase, violating the single-responsibility principle.
|
||||
|
||||
We find that companies are usually more successful when using feature flags when they can protect new complex features with a single flag evaluated only once per user request. This approach ensures consistent behavior and simplifies long-term code maintainability.
|
||||
|
||||
@ -208,21 +211,21 @@ Paying down technical debt–in its simplest form, removing old flags–requires
|
||||
|
||||
All feature flags progress through a set of predefined lifecycle stages even if these stages are not explicitly defined in your feature flag system:
|
||||
|
||||
* Initial: The feature flag is defined, but no code implementation has begun.
|
||||
* Pre-Live: Some code is implemented, but the feature is not enabled for any users in production. Internal testing and validation are ongoing.
|
||||
* Live: The code is deployed to production and gradually rolled out to a controlled set of users for validation with real users.
|
||||
* Completed: A team has decided to keep or cancel the feature. The feature flag still exists, but it is now time to clean up the code protected by it to ensure no more technical debt is acquired.
|
||||
* Archived: The feature flag has reached its end-of-life and has been disabled. The code associated with the feature flag is cleaned up to avoid technical debt.
|
||||
- Initial: The feature flag is defined, but no code implementation has begun.
|
||||
- Pre-Live: Some code is implemented, but the feature is not enabled for any users in production. Internal testing and validation are ongoing.
|
||||
- Live: The code is deployed to production and gradually rolled out to a controlled set of users for validation with real users.
|
||||
- Completed: A team has decided to keep or cancel the feature. The feature flag still exists, but it is now time to clean up the code protected by it to ensure no more technical debt is acquired.
|
||||
- Archived: The feature flag has reached its end-of-life and has been disabled. The code associated with the feature flag is cleaned up to avoid technical debt.
|
||||
|
||||
By monitoring feature progression through the lifecycle stages, organizations gain valuable insights from which they can benefit to improve their development process and pay down technical debt. Some key benefits of tracking feature flag lifecycle include:
|
||||
|
||||
* Identifying Bottlenecks: Teams can analyze the average time spent in each stage and pinpoint bottlenecks. Some examples include:
|
||||
- Identifying Bottlenecks: Teams can analyze the average time spent in each stage and pinpoint bottlenecks. Some examples include:
|
||||
1. Stuck in Initial: This may indicate issues like unclear requirements or integration difficulties in pre-production environments.
|
||||
2. Stuck in Pre-live: Suggest challenges in achieving production readiness, like incomplete testing or code bugs.
|
||||
3. Stuck in Live: This could imply difficulties gathering data or making decisions about the feature's future (e.g., lack of clear success metrics).
|
||||
4. Stuck in Completed: Signals delays in decommissioning the feature flag and cleaning up resources, potentially creating technical debt.
|
||||
* Easily Remove Stale Feature Flags: Feature flags left active after their purpose is served tend to create technical debt. This code is unused, increasing the risk of accidental exposure in production and making the codebase more complex to maintain. By retiring flags promptly, developers understand which code sections can be safely cleaned up, reducing technical debt.
|
||||
* Data-Driven Insights: By collecting and aggregating metrics across features and teams over time, organizations gain valuable insights into team performance trends. Suddenly, it is easy to measure time-to-production or the number of times we need to disable a feature in production. Over time, this level of insights allows organizations to identify gradual changes in team efficiency or identify areas needing improvement that might otherwise go unnoticed.
|
||||
- Easily Remove Stale Feature Flags: Feature flags left active after their purpose is served tend to create technical debt. This code is unused, increasing the risk of accidental exposure in production and making the codebase more complex to maintain. By retiring flags promptly, developers understand which code sections can be safely cleaned up, reducing technical debt.
|
||||
- Data-Driven Insights: By collecting and aggregating metrics across features and teams over time, organizations gain valuable insights into team performance trends. Suddenly, it is easy to measure time-to-production or the number of times we need to disable a feature in production. Over time, this level of insights allows organizations to identify gradual changes in team efficiency or identify areas needing improvement that might otherwise go unnoticed.
|
||||
|
||||
## Common pitfalls to avoid when implementing flags at scale
|
||||
|
||||
@ -248,7 +251,6 @@ A dedicated config management system should manage long-term configuration setti
|
||||
|
||||
A good rule of thumb is that if the data is static (you don’t expect it to change without restarting your application), needs encryption, or contains PII (Personal Identifiable Information), it’s probably better suited for your Configuration management system than a feature flag system.
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 11 Principles for building and scaling feature flag systems
|
||||
title: "Feature flags: Best practices for building and scaling feature flag systems"
|
||||
---
|
||||
|
||||
import Figure from '@site/src/components/Figure/Figure.tsx'
|
||||
@ -10,6 +10,7 @@ There are 11 principles for building a large-scale feature flag system. These pr
|
||||
|
||||
These principles are:
|
||||
|
||||
- [Background](#background)
|
||||
- [1. Enable run-time control. Control flags dynamically, not using config files.](#1-enable-run-time-control-control-flags-dynamically-not-using-config-files)
|
||||
- [2. Never expose PII. Follow the principle of least privilege.](#2-never-expose-pii-follow-the-principle-of-least-privilege)
|
||||
- [3. Evaluate flags as close to the user as possible. Reduce latency.](#3-evaluate-flags-as-close-to-the-user-as-possible-reduce-latency)
|
||||
|
@ -38,6 +38,23 @@ module.exports = {
|
||||
documentation: [
|
||||
'welcome',
|
||||
'quickstart',
|
||||
{
|
||||
label: 'Feature Flags Developer Guide',
|
||||
type: 'category',
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
title: 'Feature Flag Developer Guide',
|
||||
description:
|
||||
'What are feature flags? And other concepts to get you started.',
|
||||
slug: '/topics',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
label: 'Feature Flag Concepts',
|
||||
collapsed: true,
|
||||
type: 'category',
|
||||
items: ['topics/concepts/what-is-a-feature-flag'],
|
||||
},
|
||||
{
|
||||
label: 'Feature Flag Best Practices',
|
||||
collapsed: true,
|
||||
@ -47,12 +64,24 @@ module.exports = {
|
||||
title: 'Feature Flag Best Practices',
|
||||
description:
|
||||
'Principles and recommendations for best practices of using feature flags.',
|
||||
slug: '/topics',
|
||||
slug: 'topics/feature-flags/',
|
||||
},
|
||||
items: [
|
||||
'topics/feature-flags/feature-flag-best-practices',
|
||||
'topics/feature-flags/best-practices-using-feature-flags-at-scale',
|
||||
'topics/feature-flag-migration/feature-flag-migration-best-practices',
|
||||
{
|
||||
type: 'doc',
|
||||
label: 'Building and scaling feature flag systems',
|
||||
id: 'topics/feature-flags/feature-flag-best-practices',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
label: 'Using feature flags at scale',
|
||||
id: 'topics/feature-flags/best-practices-using-feature-flags-at-scale',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
label: 'Migrating from homegrown feature management solutions',
|
||||
id: 'topics/feature-flag-migration/feature-flag-migration-best-practices',
|
||||
},
|
||||
'topics/a-b-testing',
|
||||
],
|
||||
},
|
||||
@ -200,6 +229,9 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Understanding Unleash',
|
||||
collapsed: false,
|
||||
|
Loading…
Reference in New Issue
Block a user