Extension proposal : lightweight feature flags

348 views
Skip to first unread message

gwe...@gmail.com

unread,
Sep 22, 2022, 7:38:38 PM9/22/22
to Quarkus Development mailing list
Hi everyone,

On @geoand's suggestion, I'm starting this conversation to talk about quarkus#28032 which is an extension proposal to introduce lightweight feature flags in Quarkus. To save you from switching between this conversation and #28032, I'll put here everything I already wrote in #28032. This post will contain ideas that are all open for suggestions and opinions. Some of them may not be compatible with each other.

Why lightweight? Because the extension wouldn't rely on any external feature flags library/framework/server, unlike quarkus-unleash or any other similar extension.

Why would a project depend on lightweight feature flags instead of Unleash (or similar)? Well, Unleash is an amazing tool but it also comes with some constraints that may not be acceptable for all projects, such as deploying and maintaining the Unleash server and its underlying DB for example. Projects that won't use Unleash because of these constraints could benefit from a simpler feature flags implementation.

I'm part of a console.redhat.com team that uses a lot of feature flags for several reasons, including:
- we often need to merge parts of unfinished huge features that must remain disabled until everything's ready for production
- we have to deal with risky migrations that sometimes affect the entire app and require extra precautions (intensive testing, automated and manual) before we actually migrate the production data
Our feature flags are custom-made and in-memory. At first, I wanted to write a Quarkus blog post to show how we use these flags and how we run our tests with any flags combinations very easily. Then I realized this could actually be the base of a new Quarkus extension.

Here's how things could look like from a user perspective if I transformed our custom-made feature flags into a Quarkus extension:

    import quarkus.featureflags.FeatureFlags;

    @FeatureFlags
    public class FeatureFlipper {

        @ConfigProperty(name = "huge-feature.enabled", defaultValue = "true")
        boolean hugeFeatureEnabled;
   
        @ConfigProperty(name = "risky-feature.enabled", defaultValue = "false")
        Boolean riskyFeatureEnabled;
   
        /* getters and setters */
    }

    @ApplicationScoped
    public class MyService {

        @Inject
        FeatureFlipper featureFlipper;

       public void doSomething() {
            if (featureFlipper.isHugeFeatureEnabled()) {
                // Do something with the huge feature
            } else {
                // Do something without the huge feature, or even nothing at all
            }
       }
   }

Now, let's talk a bit about implementation details.

1. The @FeatureFlags annotation could only be allowed on a single class in each Quarkus app, because it's a good practice to centralize all flags at the same place for easier maintenance. Build time validation would throw a DeploymentException if multiple instances of that annotation were detected. Adding that annotation to a class would make it a @Singleton bean using BeanDefiningAnnotationBuildItem at build time.

2. Each boolean or Boolean @ConfigProperty field from the annotated class would automatically be considered as a feature flag. A default value could be mandatory for these fields and a DeploymentException could be thrown at build time when it is missing.

3. Flags values could be changed from:
- the usual MP Config way of setting configuration values (application.properties, environment variables and all other kinds of config sources)
- calling setters on the feature flags boolean fields from the app (test) code
- the dev console, in order to test and enable/disable features in dev mode without having to reload the app at all
Another way of changing the flags values in real-time could be through a REST API but it may be better to document that and not provide it as an extension feature for security reasons. Users would use examples from our doc to build their REST API while being in control of the security associated with the API.

4. The extension config could contain a quarkus.feature-flags.log-at-startup=true|false (default true) config key to determine whether the flags values should be logged at app startup or not. This is something we use in my team and it can be really helpful when something goes wrong on prod and we need to know which flags are enabled. 

5. The extension config could contain a quarkus.feature-flags.expose-flags=true|false (default false) config key to expose all feature flags through an HTTP API. This can be really helpful when flags managed from a backend app are consumed by a frontend app to determine which UI features should be enabled. The HTTP endpoint path would start with the "non application root path" (/q) like metrics, health and friends.

6. @geoand added this comment in #28032:
"One thing I would like to figure out in the aforementioned discussion is how much it would make sense to have a declarative first approach - where classes and/or methods are swapped based on the presence of a feature set, using annotations and config. The idea being that method bodies should be unaffected."

I started working on an extension POC about this: quarkus-feature-flag. Feel free to take a look at it!
That POC contains the @FeatureFlags annotation and identifies the features flags fields at build time using Jandex. It logs the flags at startup using generated bytecode (with Gyzmo) and a synthetic observer (thanks @mkouba for helping me with this!). It exposes the flags using generated bytecode (Gyzmo again) and an HTTP endpoint at /q/featureflags using a Vert.x route (resteasy is not required). This is only the beginning but it already covers most of the things that we use in our apps at console.redhat.com.

One major aspect of our custom-made features flags is the flexibility they offer during the tests execution. Our flags can be overridden from the test code at any time (before, after or in the middle of a test). We simply check that the active Quarkus profile is a test profile before allowing the flags overrides. That kind of flexibility cannot be achieved while setting system properties from tests or using Quarkus test profiles, which is why we implemented our own feature flags in the first place. There's no rocket science behind this, as we simply rely on Java boolean fields and change their values at run time. However, I think it'd be great to have a section in the extension doc that would explain how to run tests with feature flags efficiently.

Now I'd like to know what you think about this :)

Thanks for reading this!

Gwenneg

Ladislav Thon

unread,
Sep 23, 2022, 4:02:57 AM9/23/22
to gwe...@gmail.com, Quarkus Development mailing list
A while ago, I wanted to start a SmallRye Feature Flags project, but dropped it because of other higher-priority work. Some notes are here: https://github.com/smallrye/smallrye/issues/50

I'd like to highlight:

- booleans are nice, but other types of values are also important
- global flags are nice, but per-user flags are also important
- in-memory store is good, but being able to use the same API to also talk to an external feature flags service is better (this causes an interesting API design problem, because a nice-to-use feature flags API is necessarily blocking)

I don't necessarily agree that 1 class to define features is enough. That might be true if you only use feature flags for selectively enabling/disabling some parts of code and prune them aggressively, but that's only one use case for features. Other use cases involve long-lived features (those are often per-user or other more fine grained kinds).

I talked about this to a few more people and we also briefly debated a declarative approach, but concluded that it would hardly be usable for anything but the most trivial situations. (Though I admit we didn't consider bytecode transformations :-) )

LT

pá 23. 9. 2022 v 1:38 odesílatel gwe...@gmail.com <gwe...@gmail.com> napsal:
--
You received this message because you are subscribed to the Google Groups "Quarkus Development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to quarkus-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/quarkus-dev/a17e4e7a-928c-47a1-a618-8329283c49c7n%40googlegroups.com.

Andy Damevin

unread,
Sep 23, 2022, 4:20:29 AM9/23/22
to Ladislav Thon, gwe...@gmail.com, Quarkus Development mailing list
That sounds great!

It's going to rock alongside Renarde or Quinoa.



--
Andy Damevin

Georgios Andrianakis

unread,
Sep 23, 2022, 4:51:15 AM9/23/22
to adam...@redhat.com, Ladislav Thon, gwe...@gmail.com, Quarkus Development mailing list
On Fri, Sep 23, 2022 at 11:20 AM Andy Damevin <adam...@redhat.com> wrote:
That sounds great!

It's going to rock alongside Renarde or Quinoa.

On Fri, Sep 23, 2022 at 10:03 AM Ladislav Thon <lad...@gmail.com> wrote:
A while ago, I wanted to start a SmallRye Feature Flags project, but dropped it because of other higher-priority work. Some notes are here: https://github.com/smallrye/smallrye/issues/50

I'd like to highlight:

- booleans are nice, but other types of values are also important

+1
 
- global flags are nice, but per-user flags are also important

When you say per user, you mean actual logged in user? What is the use case for this? Don't our current security features cover this?
 
- in-memory store is good, but being able to use the same API to also talk to an external feature flags service is better (this causes an interesting API design problem, because a nice-to-use feature flags API is necessarily blocking)

I assume the use case for this is to be able to control some system-wide feature that span multiple microservices? Do you have examples of this?

I don't necessarily agree that 1 class to define features is enough. That might be true if you only use feature flags for selectively enabling/disabling some parts of code and prune them aggressively, but that's only one use case for features. Other use cases involve long-lived features (those are often per-user or other more fine grained kinds).

I talked about this to a few more people and we also briefly debated a declarative approach, but concluded that it would hardly be usable for anything but the most trivial situations. (Though I admit we didn't consider bytecode transformations :-) )

Any chance you folks have notes on the use cases you had in mind and how the various approaches cover them (or fall short)?

Ladislav Thon

unread,
Sep 23, 2022, 6:12:25 AM9/23/22
to Georgios Andrianakis, adam...@redhat.com, gwe...@gmail.com, Quarkus Development mailing list
pá 23. 9. 2022 v 10:51 odesílatel Georgios Andrianakis <gand...@redhat.com> napsal:
On Fri, Sep 23, 2022 at 11:20 AM Andy Damevin <adam...@redhat.com> wrote:
On Fri, Sep 23, 2022 at 10:03 AM Ladislav Thon <lad...@gmail.com> wrote:
A while ago, I wanted to start a SmallRye Feature Flags project, but dropped it because of other higher-priority work. Some notes are here: https://github.com/smallrye/smallrye/issues/50

I'd like to highlight:

- booleans are nice, but other types of values are also important

+1
 
- global flags are nice, but per-user flags are also important

When you say per user, you mean actual logged in user? What is the use case for this? Don't our current security features cover this?

I do mean logged in user, yes, but also not only. There are other levels of granularity that make sense. A logged in user may be present in a group, and that group may have defined features. This is useful for customizing software to multiple customers, for example (in other words, this is a form of multi-tenancy). If you have a user that is not logged in, you may still want to distinguish them from other not logged in users (e.g. based on <remote IP address, year, month, day> or something). This is useful to conduct experiments in an A/B fashion or in other forms.

In one of my previous jobs, we had a system like this and were able to customize our service pretty heavily to multiple customers (from things like per-company color palette down to things like specialized HTML templates) with very little maintenance cost. The only difference is that we called it "capabilities" instead of "features" :-)

I have no idea if our current security features cover anything like this.
  
- in-memory store is good, but being able to use the same API to also talk to an external feature flags service is better (this causes an interesting API design problem, because a nice-to-use feature flags API is necessarily blocking)

I assume the use case for this is to be able to control some system-wide feature that span multiple microservices? Do you have examples of this?

Indeed I'm thinking systems that span multiple services (though I have no experience with that, the system I mentioned above was part of a monolithic service), but I'm also thinking additional capabilities that a lightweight in-memory solution likely wouldn't have (or it wouldn't be lightweight in-memory anymore). Things like auditing, access control, gradual rollouts or dashboards.
 
I don't necessarily agree that 1 class to define features is enough. That might be true if you only use feature flags for selectively enabling/disabling some parts of code and prune them aggressively, but that's only one use case for features. Other use cases involve long-lived features (those are often per-user or other more fine grained kinds).

I talked about this to a few more people and we also briefly debated a declarative approach, but concluded that it would hardly be usable for anything but the most trivial situations. (Though I admit we didn't consider bytecode transformations :-) )

Any chance you folks have notes on the use cases you had in mind and how the various approaches cover them (or fall short)?

Not really, no. But I was mostly thinking about CDI intereptors, and that doesn't allow much (most probably just call/don't call). More interesting things would likely be possible with bytecode generation or transformation (e.g. a call to a method could be replaced with a conditional call of that method or other method, maybe?). We didn't spend much time thinking about it, or at least I certainly didn't. From my experience mentioned above, I'm not sure a declarative approach would be enough -- having to fit into the prescribed pattern would likely often require restructuring code for no other reason.

But as I said, I had to abandon that project very soon, so I didn't even get to building a prototype. All I have is a few ideas.

LT

Georgios Andrianakis

unread,
Sep 23, 2022, 8:12:39 AM9/23/22
to Ladislav Thon, adam...@redhat.com, gwe...@gmail.com, Quarkus Development mailing list
On Fri, Sep 23, 2022 at 1:12 PM Ladislav Thon <lad...@gmail.com> wrote:
pá 23. 9. 2022 v 10:51 odesílatel Georgios Andrianakis <gand...@redhat.com> napsal:
On Fri, Sep 23, 2022 at 11:20 AM Andy Damevin <adam...@redhat.com> wrote:
On Fri, Sep 23, 2022 at 10:03 AM Ladislav Thon <lad...@gmail.com> wrote:
A while ago, I wanted to start a SmallRye Feature Flags project, but dropped it because of other higher-priority work. Some notes are here: https://github.com/smallrye/smallrye/issues/50

I'd like to highlight:

- booleans are nice, but other types of values are also important

+1
 
- global flags are nice, but per-user flags are also important

When you say per user, you mean actual logged in user? What is the use case for this? Don't our current security features cover this?

I do mean logged in user, yes, but also not only. There are other levels of granularity that make sense. A logged in user may be present in a group, and that group may have defined features. This is useful for customizing software to multiple customers, for example (in other words, this is a form of multi-tenancy). If you have a user that is not logged in, you may still want to distinguish them from other not logged in users (e.g. based on <remote IP address, year, month, day> or something). This is useful to conduct experiments in an A/B fashion or in other forms.

In one of my previous jobs, we had a system like this and were able to customize our service pretty heavily to multiple customers (from things like per-company color palette down to things like specialized HTML templates) with very little maintenance cost. The only difference is that we called it "capabilities" instead of "features" :-)

I have no idea if our current security features cover anything like this.
  
- in-memory store is good, but being able to use the same API to also talk to an external feature flags service is better (this causes an interesting API design problem, because a nice-to-use feature flags API is necessarily blocking)

I assume the use case for this is to be able to control some system-wide feature that span multiple microservices? Do you have examples of this?

Indeed I'm thinking systems that span multiple services (though I have no experience with that, the system I mentioned above was part of a monolithic service), but I'm also thinking additional capabilities that a lightweight in-memory solution likely wouldn't have (or it wouldn't be lightweight in-memory anymore). Things like auditing, access control, gradual rollouts or dashboards.

But is a feature-flag library/extension really the place to implement these kind of cross-cutting concerns?
 
I don't necessarily agree that 1 class to define features is enough. That might be true if you only use feature flags for selectively enabling/disabling some parts of code and prune them aggressively, but that's only one use case for features. Other use cases involve long-lived features (those are often per-user or other more fine grained kinds).

I talked about this to a few more people and we also briefly debated a declarative approach, but concluded that it would hardly be usable for anything but the most trivial situations. (Though I admit we didn't consider bytecode transformations :-) )

Any chance you folks have notes on the use cases you had in mind and how the various approaches cover them (or fall short)?

Not really, no. But I was mostly thinking about CDI intereptors, and that doesn't allow much (most probably just call/don't call). More interesting things would likely be possible with bytecode generation or transformation (e.g. a call to a method could be replaced with a conditional call of that method or other method, maybe?). We didn't spend much time thinking about it, or at least I certainly didn't. From my experience mentioned above, I'm not sure a declarative approach would be enough -- having to fit into the prescribed pattern would likely often require restructuring code for no other reason.

Yeah, I see your point here.

Martin Kouba

unread,
Sep 23, 2022, 8:53:46 AM9/23/22
to lad...@gmail.com, Georgios Andrianakis, adam...@redhat.com, gwe...@gmail.com, Quarkus Development mailing list
On 23. 09. 22 12:12, Ladislav Thon wrote:
> pá 23. 9. 2022 v 10:51 odesílatel Georgios Andrianakis
> <gand...@redhat.com <mailto:gand...@redhat.com>> napsal:
The togglz library has a concept of Activation Strategies [1] where each
strategy is used to evaluate whether a specific feature is active or
not. We could introduce something similar. A simple impl for the logged
in user could then inject the current SecurityIdentity and check the
current value for a specific user.

[1]
https://www.togglz.org/documentation/activation-strategies.html
> <mailto:gwe...@gmail.com> <gwe...@gmail.com
> <mailto:gwe...@gmail.com>> napsal:
>
> Hi everyone,
>
> On @geoand's suggestion, I'm starting this conversation
> to talk about quarkus#28032
> <https://github.com/quarkusio/quarkus/issues/28032>
> which is an extension proposal to introduce lightweight
> feature flags in Quarkus. To save you from switching
> between this conversation and #28032, I'll put here
> everything I already wrote in #28032. This post will
> contain ideas that are all open for suggestions and
> opinions. Some of them may not be compatible with each
> other.
>
> Why lightweight? Because the extension wouldn't rely on
> any external feature flags library/framework/server,
> unlike quarkus-unleash
> <https://github.com/quarkiverse/quarkus-unleash> or any
> other similar extension.
>
> Why would a project depend on lightweight feature flags
> instead of Unleash <https://www.getunleash.io/> (or
> similar)? Well, Unleash is an amazing tool but it also
> comes with some constraints that may not be acceptable
> for all projects, such as deploying and maintaining the
> Unleash server and its underlying DB for example.
> Projects that won't use Unleash because of these
> constraints could benefit from a simpler feature flags
> implementation.
>
> I'm part of a console.redhat.com
> <https://console.redhat.com> team that uses a lot of
> <https://github.com/gwenneg/quarkus-feature-flag>. Feel
> free to take a look at it!
> That POC contains the @FeatureFlags annotation and
> identifies the features flags fields at build time using
> Jandex. It logs the flags at startup using generated
> bytecode (with Gyzmo) and a synthetic observer (thanks
> @mkouba for helping me with this!). It exposes the flags
> using generated bytecode (Gyzmo again) and an HTTP
> endpoint at /q/featureflags using a Vert.x route
> (resteasy is not required). This is only the beginning
> but it already covers most of the things that we use in
> our apps at console.redhat.com <https://console.redhat.com>.
>
> One major aspect of our custom-made features flags is
> the flexibility they offer during the tests execution.
> Our flags can be overridden from the test code at any
> time (before, after or in the middle of a test). We
> simply check that the active Quarkus profile is a test
> profile before allowing the flags overrides. That kind
> of flexibility cannot be achieved while setting system
> properties from tests or using Quarkus test profiles,
> which is why we implemented our own feature flags in the
> first place. There's no rocket science behind this, as
> we simply rely on Java boolean fields and change their
> values at run time. However, I think it'd be great to
> have a section in the extension doc that would explain
> how to run tests with feature flags efficiently.
>
> Now I'd like to know what you think about this :)
>
> Thanks for reading this!
>
> Gwenneg
>
> --
> You received this message because you are subscribed to
> the Google Groups "Quarkus Development mailing list" group.
> To unsubscribe from this group and stop receiving emails
> from it, send an email to
> quarkus-dev...@googlegroups.com
> <mailto:quarkus-dev...@googlegroups.com>.
> <https://groups.google.com/d/msgid/quarkus-dev/a17e4e7a-928c-47a1-a618-8329283c49c7n%40googlegroups.com?utm_medium=email&utm_source=footer>.
>
> --
> You received this message because you are subscribed to the
> Google Groups "Quarkus Development mailing list" group.
> To unsubscribe from this group and stop receiving emails
> from it, send an email to
> quarkus-dev...@googlegroups.com
> <mailto:quarkus-dev...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/quarkus-dev/CALbocO%3DqUPf5bdi5qsgzEOtG9%2BkY6_%3DTy-ywNXCQe_iS%2BYQuAw%40mail.gmail.com
> <https://groups.google.com/d/msgid/quarkus-dev/CALbocO%3DqUPf5bdi5qsgzEOtG9%2BkY6_%3DTy-ywNXCQe_iS%2BYQuAw%40mail.gmail.com?utm_medium=email&utm_source=footer>.
>
>
>
> --
> Andy Damevin
>
> --
> You received this message because you are subscribed to the
> Google Groups "Quarkus Development mailing list" group.
> To unsubscribe from this group and stop receiving emails from
> it, send an email to quarkus-dev...@googlegroups.com
> <mailto:quarkus-dev...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/quarkus-dev/CAE_u_P5obypRKiBU%3DxOgUS1WWVLoeQ%2BMPjgvUgjHpdXVqy2_yQ%40mail.gmail.com
> <https://groups.google.com/d/msgid/quarkus-dev/CAE_u_P5obypRKiBU%3DxOgUS1WWVLoeQ%2BMPjgvUgjHpdXVqy2_yQ%40mail.gmail.com?utm_medium=email&utm_source=footer>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "Quarkus Development mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to quarkus-dev...@googlegroups.com
> <mailto:quarkus-dev...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/quarkus-dev/CALbocOn-3nJ6j-ogWucH%3DRfJXPWyFKhRUyqGNccKe4heRyGEWA%40mail.gmail.com
> <https://groups.google.com/d/msgid/quarkus-dev/CALbocOn-3nJ6j-ogWucH%3DRfJXPWyFKhRUyqGNccKe4heRyGEWA%40mail.gmail.com?utm_medium=email&utm_source=footer>.

--
Martin Kouba
Software Engineer
Red Hat, Czech Republic

Ladislav Thon

unread,
Sep 23, 2022, 9:06:36 AM9/23/22
to gand...@redhat.com, adam...@redhat.com, gwe...@gmail.com, Quarkus Development mailing list
pá 23. 9. 2022 v 14:12 odesílatel Georgios Andrianakis <gand...@redhat.com> napsal:
On Fri, Sep 23, 2022 at 1:12 PM Ladislav Thon <lad...@gmail.com> wrote:
pá 23. 9. 2022 v 10:51 odesílatel Georgios Andrianakis <gand...@redhat.com> napsal:
On Fri, Sep 23, 2022 at 11:20 AM Andy Damevin <adam...@redhat.com> wrote:
On Fri, Sep 23, 2022 at 10:03 AM Ladislav Thon <lad...@gmail.com> wrote:
A while ago, I wanted to start a SmallRye Feature Flags project, but dropped it because of other higher-priority work. Some notes are here: https://github.com/smallrye/smallrye/issues/50

I'd like to highlight:

- booleans are nice, but other types of values are also important

+1
 
- global flags are nice, but per-user flags are also important

When you say per user, you mean actual logged in user? What is the use case for this? Don't our current security features cover this?

I do mean logged in user, yes, but also not only. There are other levels of granularity that make sense. A logged in user may be present in a group, and that group may have defined features. This is useful for customizing software to multiple customers, for example (in other words, this is a form of multi-tenancy). If you have a user that is not logged in, you may still want to distinguish them from other not logged in users (e.g. based on <remote IP address, year, month, day> or something). This is useful to conduct experiments in an A/B fashion or in other forms.

In one of my previous jobs, we had a system like this and were able to customize our service pretty heavily to multiple customers (from things like per-company color palette down to things like specialized HTML templates) with very little maintenance cost. The only difference is that we called it "capabilities" instead of "features" :-)

I have no idea if our current security features cover anything like this.
  
- in-memory store is good, but being able to use the same API to also talk to an external feature flags service is better (this causes an interesting API design problem, because a nice-to-use feature flags API is necessarily blocking)

I assume the use case for this is to be able to control some system-wide feature that span multiple microservices? Do you have examples of this?

Indeed I'm thinking systems that span multiple services (though I have no experience with that, the system I mentioned above was part of a monolithic service), but I'm also thinking additional capabilities that a lightweight in-memory solution likely wouldn't have (or it wouldn't be lightweight in-memory anymore). Things like auditing, access control, gradual rollouts or dashboards.

But is a feature-flag library/extension really the place to implement these kind of cross-cutting concerns?

That's exactly why I mentioned that external feature flag services are also important, because they address all these concerns for people who need to use feature flags more extensively. And I think it naturally follows that one would want to have the same API for both a lightweight in-memory implementation and a heavy-weight external service (modulo the blocking vs. non-blocking aspect, that's a major issue). At least that's how I was thinking when I was considering starting a feature flags project.

LT
 

Kevin Viet

unread,
Sep 23, 2022, 9:33:38 AM9/23/22
to lad...@gmail.com, gand...@redhat.com, adam...@redhat.com, gwe...@gmail.com, Quarkus Development mailing list
Hello,

That's exactly why I mentioned that external feature flag services are also important, because they address all these concerns for people who need to use feature flags more extensively. And I think it naturally follows that one would want to have the same API for both a lightweight in-memory implementation and a heavy-weight external service (modulo the blocking vs. non-blocking aspect, that's a major issue). At least that's how I was thinking when I was considering starting a feature flags project.

+1 

We developed a simple "feature flag" implementation internally for microservices, we got inspired from this blog post https://www.devwithimagination.com/2019/09/16/a-feature-flag-experiment-with-config-and-cdi/
We leaned over a quarkus extension at that time, but nothing was there yet :/

I like the idea of having a simple solution to start with, but it has to be extensible, because digging through feature flags we noticed the following 
- Consistency across microservices or broader applications (active feature flags transmitted through protocol headers) 
- Feature flags definition reload at runtime (based on configmap for example) 
- Request scoped flag resolution (in case of reload) 
- Complex types support (not only boolean)
- Build time checking : if too many flags or too old flags the application cannot be built, it's to maintain the code base clean

But yeah, it starts looking like a full blown solution ... 


Loïc MATHIEU

unread,
Sep 23, 2022, 10:23:44 AM9/23/22
to kevin...@gmail.com, Ladislav Thon, Georgios Andrianakis, Andy Damevin, gwe...@gmail.com, Quarkus Development mailing list
Hi,

Features flipping is a really interesting topic and a simple extension may be a good addition.
In my current mission, we use config properties and booleans injected inside a class, and the extension you describe didn't seems to add a lot more convenience for the declaration (but you provides valuable functionalities).

Instead of asking the developer to create a feature flag class that we can easily generate or made generic maybe we could provide a more easy to use (but more opinionated) API like.

quarkus.feature.enable-header=true

@ApplicationScoped
public class FlipMe  {
     @FeatureFlag("enable-header") boolean enabledHeader;

     @Inject FeatureFlags featureFlags; // provided by the extension for more control over features flippin
     public void someMethod() {
        if(featureFlags.enable("enable-header")) {]
     }
}

We can even validate a build time that the feature exists in the config to avoid developer mistakes ;)

As others noted, features flipping is often dependents on context, it could be cool but not mandatory to support some of them like canary (quarkus.feature.enable-header.canary=0,1 for 10% enabling), A/B testing based on request header or authenticated user group, ... But I know that it may be better to use a full fledged feature flipping tool so the line must be drawn somewhere and not everything should be covered. 

Regards,

Loïc

gwe...@gmail.com

unread,
Sep 23, 2022, 10:58:58 AM9/23/22
to Quarkus Development mailing list
@Loïc:
I like your API suggestion, it is more user-friendly indeed. I started my POC with @FeatureFlags at class level because it was an easy way to enforce the centralization of flags at a single location. Some people consider this a grood practice, others don't. In my experience, it makes the flags maintenance a bit easier but I could totally live without that in the extension. This could still be enforced at build time with your suggestion and without any annotation at class level though.

Defining the scope of the extension and the features that should be included is very important indeed. What I had in mind when I started this conversation was a simpler set of features than a full-fledged solution. Reinventing the wheel is okay when the new wheel is better than the old one. Otherwise, not so much, especially when great and widely used solutions already exist.

gwe...@gmail.com

unread,
Sep 23, 2022, 11:11:11 AM9/23/22
to Quarkus Development mailing list
Thank you all for sharing your experiences, feedbacks and opinions about feature flags!

This is turning into a very interesting conversation with lots of good suggestions.

Emmanuel Bernard

unread,
Sep 27, 2022, 8:13:28 AM9/27/22
to gwe...@gmail.com, Quarkus Development mailing list
Adding my small weight on this.
I have the same experience as KEvin, it's awesome to start with a local / single app solution as it might solve the new comers to feature flag. But it absolutely has to scale and support external feature flag services. A bit like our security have be home made or rely on Vault. So from a consumption experience it should be similar regardless of where the flag choice comes from.

And "runtime fippable" is very important (configmap or even no restart way).

And to align with Loïc, while global feature flag per instance has some use cases, a HTTP header driven one (or another request based data) can be very very valuable too.

Emmanuel


bcl...@gmail.com

unread,
Mar 16, 2023, 9:59:25 AM3/16/23
to Quarkus Development mailing list
Just reigniting this discussion.

A requirement came up on our product to be able to "advertise" to API callers what features are there at runtime (think a rest endpoint like GET /features that returns something like : ["MyNewFeature", "SomeOtherFeature", "ABigFeature"] ). Idea being that API callers (well actually their CI/CD pipelines) can know if some feature is available yet in a certain environment and fail a build or notify that a dependency is not met. 

My vision is that a developer on our team could add some code/annotation/(comment?) deep down in some library (not just in one single place) like this to indicate that this class has this feature

@Feature("MyNewFeature")
boolean myNewFeature";

Then if we had some class at runtime in Quarkus we could call to get a list of features in that Quarkus App:

@Inject
FeatureFlipper featureFlipper;

List<String> features = featureFlipper.getEnabledFeatures();

And we can use that to return the JSON we want.

Is this something that the featureflag plugin could enable or does anyone have any good ideas on how this could be achieved some other way - maybe a mvn plugin that parses annotations? The Quarkus way would be a Quarkus plugin I guess and seeing there is one related to features, it could be the right target for this?

George Gastaldi

unread,
Mar 16, 2023, 10:08:31 AM3/16/23
to bcl...@gmail.com, Quarkus Development mailing list
It seems like what a Feature Flag management solution would do. 

You could use Unleash and the respective extension for that matter I think.

Best Regards,


George Gastaldi

Principal Software Engineer

Red Hat



bcl...@gmail.com

unread,
Mar 16, 2023, 10:20:16 AM3/16/23
to Quarkus Development mailing list
Yea, just seems like overkill for my use case. To have another moving part just for this :-(
Reply all
Reply to author
Forward
0 new messages