Reducing technical debt from feature flags
Read time: 11 minutes
Last edited: Mar 07, 2023
This guide provides ways to reduce and eliminate technical debt related to feature flags using LaunchDarkly. Like all debt, technical debt accumulates over time, but you can mitigate that debt over time if you put effective processes in place before you need them.
In this guide, we'll explore:
- The challenge of technical debt
- The lifecycle of a flag
- Naming conventions
- Using tags
- Code references
- Archiving and deleting flags
Just like feature flags should be a core engineering practice, so should a strategy to address technical debt.
To complete this guide, you must have the following prerequisites:
- Proficiency and understanding of creating a feature flag in LaunchDarkly
- Knowledge of your organization’s release process
You should understand these concepts before you read this guide:
Technical debt is a concept in software development that describes the implied cost of rework required in the future because of short-term, limited solutions. It is often caused by choosing a fast, limited solution now instead of using a better approach that would take longer. A common reason for this is that necessary work must be delayed to meet a deliverable or a deadline.
As this debt accumulates, it is harder to maintain the system and code, which can impact the speed of development and efficiency of your codebase in the future.
One way technical debt can accumulate is when you fail to maintain your feature flags.
Software delivery lifecycle
The software delivery lifecycle (SDLC) is a process followed for a software project. The process describes how to develop, maintain, and modify software. The stages of the software delivery cycle are:
- Testing and integration
Permanent and temporary flags
Flags are either temporary or permanent. A temporary flag has a limited lifespan. Once the flag has fulfilled its business purpose, remove it from the codebase. Temporary flags include flags for release management, experiments, and interoperability testing.
Permanent flags provide control for an extended time after the release of a feature. They will potentially exist for the life of a feature. Permanent flags include flags for entitlements, load shedding, custom-branding, or accessibility.
Challenges of technical debt
Every feature should have a flag, but if you don't regularly archive flags, you can accumulate a lot of debt.
Cluttered code is harder to maintain and test. Unnecessary code remains because nobody remembers why it existed, and there is a fear that things will break if it is removed. Failure to remove flags leads to cluttered code.
Not only do you want to remove the references to the flag in your code, but you also don’t want to send evaluation settings for flags you don’t need. When you use features like Data Export to track the impact of your rollouts, your database may be overwhelmed with unnecessary event data. You don't want to transfer and store data on flags that should have been archived three months ago.
Failure to remove flags clutters your flags list, as well as your code. You can’t quickly find the flag you need to toggle. This may seem like a minor inconvenience, but if you need to quickly toggle a flag off, having to scroll through hundreds of flags adds time. But cluttered code and extensive flags lists aren’t the only challenges.
You also run the risk of an old flag evaluating to a state that is invalid or undesirable. When you’re rolling out a new change such as an updated user interface (UI), it is common to keep the current UI as the default version until you have confidence in the new one. Once the flag is serving 100% of contexts the new UI, the flag has reached the end of its lifecycle and should be archived. Failure to do this runs the risk of falling back to the undesired old UI if a flag gets turned off or an SDK failure results in using the fallback value.
Test the fallback values of permanent flags periodically to ensure they are up to date and delivering valid states. To learn more about fallback values, read Changing default flag values.
Understanding the flag's lifecycle
The flags list provides the status of every flag and when it was last evaluated. Statuses include:
- New/Never Requested: You created the flag fewer than seven days ago and it has never been requested.
- Active: LaunchDarkly is currently receiving requests for the flag using your production SDK.
- Launched: All context instances have been receiving one variation of the flag for seven days or more.
- Inactive: The flag has not been requested for at least seven days.
To learn more, read Flag statuses.
Temporary flags with an "Inactive" status should likely be archived. The "Inactive" status indicates that the flag isn't being evaluated anymore. This may mean that you're no longer running the code which evaluates the flag, or that you have already removed the flag from the code.
Temporary flags with a "Launched" status may also be ready to archive. The "Launched" status indicates that any gradual rollout of a new feature has ended, and it's now live for all contexts. The flag is still evaluated every time the code is run, but because it returns the same variation for everyone, it's no longer needed. You should now either archive the flag, or turn it into a permanent flag that you can use as a kill switch to disable the feature entirely.
For example, consider this flag:
This flag’s status is "Never requested," but it was added over a year ago. Maybe it was created on accident, maybe the feature never shipped, perhaps it shipped with a different flag. Whatever the reason, no one is using the flag. You can archive it.
If you don't archive flags that no one is using, they can become a form of technical debt. However, do not archive flags solely because of their status. Be sure it is no longer in use.
Archiving and deleting flags
LaunchDarkly provides the options to archive and delete flags. We strongly recommend archiving flags rather than deleting them, because an archived flag's history remains in your LaunchDarkly project. To learn how to archive flags, read Archiving and deleting flags.
If you delete a flag, LaunchDarkly deletes all references to the flag, including its history. Deleting a flag also means a member could make a new flag with the same key as the old deleted flag, creating the possibility that your code could begin referencing the wrong flag. This can have serious and unpredictable effects on your app performance.
LaunchDarkly SDKs consider archived flags "gone." When you select a flag to archive, the panel takes you through the archiving process. LaunchDarkly warns you if you try to archive a flag that is still serving variations, or that is detected in your code through code references.
A healthy project has a high ratio of archived to unarchived flags. A general guideline is that any project over three months old should have archived at least one flag. If it has not, you may want to examine your archival practices. An appropriate time-to-archive varies depending on your business needs, but a general best practice is to archive flags quarterly. This means a healthy time-to-archive is in the 90-120 day range.
Generally, a project should have fewer deleted flags than archived flags. If you have more deleted flags than archived flags, or if a project has more than ten deleted flags, you may need to review your archiving and deleting practices. You may choose to restrict who can delete flags by assigning them a custom role. To learn more, read Custom roles.
Custom roles are available to customers on an Enterprise plan. To learn more, read about our pricing. To upgrade your plan, contact Sales.
Eliminating flag debt
Here are some processes you can follow to reduce or eliminate flag debt in your organization:
Creating organization-wide naming conventions
A shared naming convention for your organization's flags is an effective way to eliminate debt. Flags should have understandable, intuitive names.
For example, imagine a flag named
FF123_do_not_delete_this_72. When the developer that created the flag leaves the company, the person who takes over their work cannot necessarily tell what that flag is supposed to do. The name of that flag is too obscure to easily determine if the flag is important or not, and taking time to find the flag references in the codebase, determine the results of its variations, and calculate the impact of archiving the flag all seem less urgent than other work.
If flags do not have human-readable names, they can become technical debt.
To learn more, read Creating naming conventions for flags.
Writing useful descriptions
Use descriptions to add more context to the flag. Unlike flag names, you can update descriptions. They can include detailed information, such as the date the flag was last reviewed, the purpose of the flag, and more.
Descriptions are fast ways to help other account members learn what a flag does and what its impact is.
Minimizing flag scope
A flag should have limited scope. Having a flag that controls more than one feature action at a time can be confusing and can make it harder to troubleshoot problems.
Imagine the smallest unit of logic needed for the most responsive flag. If there are multiple parts to a feature that have to work together, you can create a main flag with other flags dependent on it.
For example, you launch a new dashboard with three widgets. To manage them, create four flags: one flag for each widget, with a dependency on a fourth flag for the main dashboard. In this scenario, if one widget causes problems, you can disable it and still serve the dashboard with the two remaining widgets.
Scheduling regular flag reviews
Schedule regular review cycles on a monthly or quarterly basis to identify flags to archive. Some companies dedicate sprints to tackling technical debt. If you do this, include a review of your feature flags, too.
Some teams schedule a regular "Flag Cleanup Day." In preparation, a team member produces a list of flags to be cleaned up. The list is divided up amongst the team. Then, each team member goes through their assigned flags and, for each flag, produces a patch or pull request which removes the flag from the code.
In addition to temporary flags, you should also review any permanent flags to determine that they are still necessary. As features change, the need for the flags associated with them can also change.
During a review cycle, you can search for flags with "Launched" and "Inactive" statuses. Both of these status types indicate flags that may be candidates for removal.
If your project has tens or even hundreds of flags, finding all of the "Launched" and "Inactive" can take time. You can use flag filters to narrow the list of flags displayed to only those flags which meet your filter criteria.
Here is an image of a flag filter:
Here is how to filter and archive temporary flags by status:
- Navigate to the feature flags list and click Filter.
- Choose "Status" from the Add a filter to refine your search menu:
- Select a status of "Launched" or "Inactive."
- Archive the flags you no longer need. Be sure to only archive temporary flags, not permanent ones.
- Repeat steps 3 and 4 for the status you did not filter by the first time:
In addition to flag status, you can also filter by flags that you personally maintain. You can save your list filter configurations to return to later, making it easy to regularly check for flags to archive. To learn how, read Saving filtered flags lists.
Marking flags as permanent
When you create or edit a flag, you can indicate whether or not the flag is permanent by selecting the This is a permanent flag checkbox in the flag's Settings tab. When someone tries to archive a permanent flag, a warning appears. This can help prevent flags from being archived unnecessarily.
You can also filter flags based on whether they are temporary or permanent. This can help you find flags to archive.
When you conduct a flag review, confirm the This is a permanent flag checkbox is selected for every permanent flag.
To learn more, read Flag settings.
Using effective tagging conventions
Tags are strings you can attach to any flag within LaunchDarkly. They help you group resources together.
You can control the spread of technical debt with tags by including a tag with a sprint designation or deploy date. When you conduct your regularly scheduled reviews, you can search for specific sprints or deploy dates.
Tags are case sensitive. For example, searching for
Permanent tags and
permanent tags will yield different results.
Including flags in your workflow's definition of "done"
Each company and team within an organization may have their own standards for what constitutes "done" on a task or project. Done indicates the project can be removed from the list of current tasks. For example, a team may consider the code for a task to be incomplete until it has passed automated tests.
Done means different things for different teams. A feature may be done when it rolls out to 100% of contexts, or when it rolls out to a specific set of contexts. When a feature is fully rolled out, or an experiment is ended, that's the best time to clean up the flag. When scheduling the work for rolling out a feature, include the flag cleanup work in the schedule. A feature is done when the flag is archived.
If the flag you use for a release will convert to a permanent flag, the definition of done should be when the setting on the flag changes to indicate it is permanent. You can make archiving flags part of each sprint or project end. Using this method, you'll do the work to archive the flag when the context is fresh.
To learn more about integrating flag archiving behavior into your feature development processes, read the LaunchDarkly blog article How to use feature flags without technical debt.
Using code references to find and remove references to flags
Archiving a flag removes it from the flags list and your app's contexts no longer encounter it.
Before you do this, remove the flag from your codebase. Code references let you quickly find where in your source code feature flags are referenced. This simplifies the process of finding code to remove in projects and files.
To access code references:
- Navigate to the flags list and find the flag you wish to remove.
- Click the flag's name to open the flags list.
- Click the Code references tab:
After you remove all code references mentioning that flag from the codebase and rerun the scanning tool, LaunchDarkly creates an extinction event. This event appears as a message on the Code references tab of the feature flag. To learn more, read Understanding extinction events.
Planning to remove flags during flag creation
When creating a pull request to add a flag into your code, you can also create a second pull request which removes the flag. This pull request should simply remove the flag code without other changes. This minimizes the number of conflicts to resolve even if, as often happens, the code for the new feature is updated before the rollout is finished.
The code may change before you merge the branch, but creating it gives you somewhere to start when you're ready to clean up the code. The presence of the branch also serves as a reminder to remove the flag when it's no longer needed.
Retiring inactive projects
You can identify entire projects that may be inactive by the age and activity level of its flags. If no one has created new flags within the project in the last three months, and it does not contain any active permanent flags, you may be able to delete the project. To learn how, read Deleting projects.
Receiving flag removal alerts in Slack
You can use the Slack app to subscribe to notifications when it’s time to remove flags from code. To learn more, read Receiving alerts when flags are ready to remove.
In this guide, you learned about:
- Challenges of technical debt
- The flag lifecycle
- Processes and features within LaunchDarkly to help control flag debt
For additional discussion on the lifecycle of a feature flag, read the ebook Effective Feature Management.
Your 14-day trial begins as soon as you sign up. Learn to use LaunchDarkly with the app's built-in tutorial. You'll discover how easy it is to manage the whole feature lifecycle from concept to launch to control.
Want to try it out? Start a trial.