Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions adrs/0033-feature-flags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# ADR-0033: Feature Flags

## Status

Draft

Date of decision: Pending
Comment on lines +5 to +7
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a reminder to update these to accepted and with the date before you merge.


## Context and Problem Statement
We would like to be able to deploy to production at any point, even if some features are incomplete or otherwise
should not be made public - i.e. we would like to enable trunk-based development.
We will use feature flags to hide incomplete/unwanted features in production.

Depending on how we implement them, feature flags could also provide a number of other benefits, such as allowing:
* A/B testing
* enabling/disabling features for specific users
* gradually rolling out features
* quickly disabling a feature if it is causing problems without needing to do a new deployment
* testing features in an environment without exposing them to all users

What feature flag system should we use?

## Considered Options
* If statements with hard-coded switch values
* If statements with custom interface
* Spring Beans natively selected by per-environment configuration
* Library selecting beans by per-environment configuration with additional overrides
* Library selecting beans with self-hosted dynamic flags
* Feature Flags as a Service (FFaaS) product

### Libraries considered if using a library
* Using Togglz as the library
* Using FF4J as the library

## Decision Outcome
Library selecting beans by per environment static configuration with additional overrides, because it provides a good balance of simplicity,
maintainability, and potential for future expansion if needed.

### Library selected
FF4J, because it provides native Spring DI integration using Aspect Oriented Programming (AOP) and is a little more actively supported

## Pros and Cons of the overall Options

### If statements with hard-coded switch values

Directly branch code using if statements decision points and have all feature flag values hard-coded as constants.

* Good, because it is simple to implement and requires no additional dependencies.
* Bad, because it leads to messy code and makes feature flag logic hard to maintain and test.
* Bad, because it does not leverage our dependency injection system, reducing code clarity and maintainability.
* Bad, because it does not allow different values in different environments with the same version of the code.

### If statements with custom interface

Directly branch code using if statements decision points and have all feature flag values calculated based
on environment values, but still hard-coded.

* Good, because it is relatively simple to implement and requires no additional dependencies.
* Bad, because it leads to messy code and makes feature flag logic hard to maintain and test.
* Bad, because it does not leverage our dependency injection system, reducing code clarity and maintainability.
* Good, because it allows different values in different environments with the same version of the code.
* Bad, because feature flag values cannot be changed without changing the code.

### Spring Beans natively selected by per-environment configuration

Use per-environment configuration to select which beans are active, controlling feature availability at startup. The beans can either be
alternative implementations of the same interface, or an interface determining whether a feature is enabled.

* Good, because behaviour is fixed per deployment to a given environment, ensuring predictability and replicability of behaviour.
* Good, because it integrates well with our DI system and keeps code clean.
* Bad, because it does not support advanced features like A/B testing or gradual rollouts without custom code.
* Good, because any advanced features implemented will be well understood by us.
* Neutral, as it requires a restart with reconfiguration to change flags, but this is acceptable for our use case.

### Library selecting beans by per-environment configuration with additional overrides

Use a feature flag library (e.g., Togglz, FF4J) to manage flags via per-environment configuration, with DI integration. This gives all the
advantages of the previous option, but with some additional features provided by the library such as targeting specific users.

* Good, because behaviour is fixed per deployment, ensuring predictability and replicability.
* Good, because it integrates well with our DI system and keeps code clean.
* Good, because it supports some advanced features using static context without custom code.
* Bad, because any advanced features not supported by the library would require integrated custom implementation.
* Neutral, as it requires a restart with reconfiguration to change flags, but this is acceptable for our use case.
* Good, because it will support extension to dynamic flags in future if needed.

### Library selecting beans with self-hosted dynamic flags

Use a feature flag library as above with per-environment defaults and database-backed flags and an admin console for runtime changes.

* Bad, because behaviour is not fixed per deployment, reducing predictability and replicability.
* Good, because it allows runtime flag changes, to alter the service behaviour without redeployment.
* Good, because it integrates well with our DI system and keeps code clean.
* Good, because it supports some advanced features without custom code.
* Bad, because any advanced features not supported by the library would require integrated custom implementation.
* Bad, because it introduces an additional potential security concern and operational complexity.
* Bad, because inadvertent mistakes in the admin console could degrade service or expose features unintentionally.
* Bad, because implementation will be more involved and include infrastructure changes.

### Feature Flags as a Service (FFaaS)

Use a commercial feature flag service (e.g., LaunchDarkly, Unleash).

* Bad, because behaviour is not fixed per deployment, reducing predictability and replicability.
* Bad, because it will not provide native DI integration with Spring, leading to additional complexity.
* Bad, because this would not provide implementations of advanced features out of the box, requiring custom integration.
* Bad, because it is expensive and provides advanced features like management across distributed systems that we do not need.
* Bad, because it introduces external dependencies and operational overhead.

## Pros and Cons of the library Options

### Togglz
* Good, because it is simple and lightweight.
* Neutral, because it can be used with Spring, but does not provide native DI integration.
* Good, because it pulls in values explicitly from spring configuration.
* Bad, because it's a fairly small project with infrequent releases.
* Good because it supports user groups, rollout percentages, and other activation strategies.
* Bad, because it does not support AOP, so switching a single method on an interface requires changing dependency injection.
* Bad, because it does not natively support cookie or header-based targeting, which might be a useful feature at some point.

### FF4J
* Good, because it provides native Spring DI integration using Aspect Oriented Programming.
* Good, because its AOP allows switching a single method on an interface without changing dependency injection.
* Good, because it is simple to integrate.
* Neutral, because it pulls in values from explicit configuration files.
* Bad, because it's a fairly small project with infrequent releases.
* Good, because it has more recent updates than Togglz and is being more actively maintained.
* Good because it supports user groups, rollout percentages, and other activation strategies.
* Bad, because it does not natively support cookie or header-based targeting, which might be a useful feature at some point.

## More Information

* https://www.togglz.org
* https://ff4j.github.io/
* https://martinfowler.com/articles/feature-toggles.html
Loading