ENG
- Services
- Unser Serviceportfolio
Wir erwecken Ihre digitale Produktvision zum Leben: Vom testbaren Prototypen bis zur fertigen Softwarelösung.
- Kooperationsmodelle
Kooperationsmodelle passend zu Ihren Bedürfnissen: Komplette Nearshoring Teams, deutschsprachige Experten vor Ort mit Nearshoring-Teams oder gemischte Teams mit unseren Partnern.
- Arbeitsweise
Durch enge Zusammenarbeit mit Ihrem Unternehmen schaffen wir maßgeschneiderte Lösungen, die auf Ihre Anforderungen abgestimmt sind und zu nachhaltigen Ergebnissen führen.
- Unser Serviceportfolio
- Über uns
- Wer wir sind
Wir sind ein Full-Service Nearshoring-Anbieter für digitale Softwareprodukte, ein perfekter Partner mit deutschsprachigen Experten vor Ort, Ihre Business-Anforderungen stets im Blick
- Unser Team
Das ProductDock Team ist mit modernen Technologien und Tools vertraut und setzt seit 15 Jahren zusammen mit namhaften Firmen erfolgreiche Projekte um.
- Unsere Standorte
Wir sind ProductDock, ein Full-Service Nearshoring-Anbieter für Softwareprodukte mit Hauptsitz in Berlin und Entwicklungs-Hubs in Lissabon, Novi Sad, Banja Luka und Doboj.
- Wozu Nearshoring
Wir kombinieren Nearshore- und Fachwissen vor Ort, um Sie während Ihrer gesamten digitalen Produktreise optimal zu unterstützen. Lassen Sie uns Ihr Business gemeinsam auf das nächste digitale Level anheben.
- Wer wir sind
- Unser Leistungen
- Karriere
- Arbeiten bei ProductDock
Unser Fokus liegt auf der Förderung von Teamarbeit, Kreativität und Empowerment innerhalb unseres Teams von über 120 talentierten Tech-Experten.
- Offene Stellen
Begeistert es dich, an spannenden Projekten mitzuwirken und zu sehen, wie dein Einsatz zu erfolgreichen Ergebnissen führt? Dann bist du bei uns richtig.
- Info Guide für Kandidaten
Wie suchen wir unsere Crew-Mitglieder aus? Wir sehen dich als Teil unserer Crew und erklären gerne unseren Auswahlprozess.
- Arbeiten bei ProductDock
- Newsroom
- News
Folgen Sie unseren neuesten Updates und Veröffentlichungen, damit Sie stets über die aktuellsten Entwicklungen von ProductDock informiert sind.
- Events
Vertiefen Sie Ihr Wissen, indem Sie sich mit Gleichgesinnten vernetzen und an unseren nächsten Veranstaltungen Erfahrungen mit Experten austauschen.
- News
- Blog
- Kontakt

22. Feb. 2024 •2 minutes read
Exploring vendor agnostic feature management with OpenFeature
Jovica Zorić
Chief Technology Officer
Feature flags have become a cornerstone of modern software development, empowering developers to modify system behavior without rewriting code. By placing conditional statements, usually if-else cases, around sections of code, developers can control the activation or deactivation of features in real time.
Feature flags are not just tools for developers; they have far-reaching benefits across various business functions. They enable continuous deployment, incremental rollouts, A/B testing, risk mitigation, and feature experimentation. Their versatility extends beyond the coding realm to impact sales, customer support, marketing, and more. While feature flags may appear straightforward to implement and comprehend, it’s important to understand that they introduce additional code and complexity to your existing codebase. If a feature is eventually made accessible to all users, the additional code associated with it should be removed.
In this blog post, we’ll explore the transformative power of feature flags and introduce OpenFeature, a vendor-agnostic solution designed to work with any feature flag management tool or in-house solution.
Alright, let’s kick things off. In the vast sea of tools and software options, we have contenders like LaunchDarkly, Rollout, ConfigCat, Optimizely, Toggled, DevCycle, Unleash, and the list goes on. Personally, I lean towards standards and the freedom to experiment with various providers and solutions until I discover the one that best aligns with my needs. This is where OpenFeature steps in, as it allows you to explore different providers seamlessly.
Use case
Let’s delve into a practical use case. We aim to leverage feature flags to determine if a user, identified by their email address, has access to a new feature. I’ve chosen three providers—flagd, ConfigCat, and DevCycle—but for a comprehensive ecosystem overview, feel free to visit this page.
The example is written in Quarkus and you can find the source code here.
flagd
Let’s create a simple API for our use case.
@Path("/api")
public class PdAPI {
@Inject()
@FlagdQualifier
OpenFeatureAPI openFeatureAPI;
@GET()
@Path("/check/{email}")
@Produces(MediaType.APPLICATION_JSON)
public Response checkFeature(@PathParam("email") String email) {
final var client = openFeatureAPI.getClient();
client.addHooks(new PDTrackerHook());
var ctx = new MutableContext();
ctx.setTargetingKey("isfromproductdock");
ctx.add("Email", email);
if (client.getBooleanValue("isfromproductdock", false, ctx)) {
return Response.ok(new FeatureFlagResponse("This feature is enabled! User is from ProductDock.")).build();
}
return Response.ok(new FeatureFlagResponse("This feature is disabled! User is not from ProductDock.")).build();
}
}
record FeatureFlagResponse(String message) {}
We have a simple API with a GET method that, depending on the email provided, will return a message if the feature is enabled or disabled. To be able to inject and use OpenFeatureAPI, we need to create an instance and set our flagd provider. Don’t mind the Qualifier annotations, we will use different Qualifiers to distinguish between different implementations.
@ApplicationScoped
public class FlagdAPI {
@Produces
@FlagdQualifier
public OpenFeatureAPI getApi() {
final OpenFeatureAPI openFeatureAPI = OpenFeatureAPI.getInstance();
openFeatureAPI.setProvider(new FlagdProvider());
return openFeatureAPI;
}
}
Now that we have our instance in place, we need to run flagd. Visit this link to explore different installation options and their documentation. For this demo, we just run a Docker container:
docker run --rm -it --name flagd -p 8013:8013 -v $(pwd)/flagd-docker:/etc/flagd ghcr.io/open-feature/flagd:latest start --uri file:./etc/flagd/flagd.json
and provide the following config:
{
"flags": {
"isfromproductdock": {
"state": "ENABLED",
"variants": {
"on": true,
"off": false
},
"defaultVariant": "off",
"targeting": {
"if": [
{
"$ref": "isFromProductDock"
},
"on",
null
]
}
}
},
"$evaluators": {
"isFromProductDock": {
"in": [
"@productdock.com",
{
"var": ["Email"]
}
]
}
}
}
It’s easy to understand, and flagd docs are awesome.
After running the application, we can use curl to test our API:
curl http://localhost:8080/api/check/example@productdock.com
or
curl http://localhost:8080/api/check/example@gmail.com
How difficult is it to change to another provider? Let’s try ConfigCat.
ConfigCat
We created a ConfigCat account and an SDK key that we will be using in our configuration.
Here is what the flag looks like in ConfigCat.
Next, we need to configure the OpenFeatureAPI instance to use ConfigCat as the provider.
@ApplicationScoped
public class ConfigCat {
@ConfigProperty(name = "configcat.sdkkey")
public String configCatKey;
@Produces
@ConfigCatQualifier
public OpenFeatureAPI getApi() {
final OpenFeatureAPI openFeatureAPI = OpenFeatureAPI.getInstance();
var configCat = ConfigCatProviderConfig.builder()
.sdkKey(configCatKey)
.build();
openFeatureAPI.setProviderAndWait(new ConfigCatProvider(configCat));
return openFeatureAPI;
}
}
Finally, we change the qualifier in our PdAPI so that our DI container knows which OpenFeatureAPI instance to use.
@Path("/api")
public class PdAPI {
@Inject()
// @FlagdQualifier
@ConfigCatQualifier
OpenFeatureAPI openFeatureAPI;
@GET()
@Path("/check/{email}")
@Produces(MediaType.APPLICATION_JSON)
public Response checkFeature(@PathParam("email") String email) {
final var client = openFeatureAPI.getClient();
client.addHooks(new PDTrackerHook());
var ctx = new MutableContext();
ctx.setTargetingKey("isfromproductdock");
ctx.add("Email", email);
if (client.getBooleanValue("isfromproductdock", false, ctx)) {
return Response.ok(new FeatureFlagResponse("This feature is enabled! User is from ProductDock.")).build();
}
return Response.ok(new FeatureFlagResponse("This feature is disabled! User is not from ProductDock.")).build();
}
}
record FeatureFlagResponse(String message) {
}
Everything else stays the same.
DevCycle
For DevCycle, it’s the same story, almost. They use “email” instead of “Email” for their user object, but that’s an easy fix.
Before we continue, you should have a DevCycle account and your SDK key.
The following image shows the DevCycle UI for defining targeting rules.
Once again, we configure the OpenFeatureAPI instance, but now with the DevCycle provider.
@ApplicationScoped
public class DevCycle {
@ConfigProperty(name = "devcycle.sdkkey")
public String devCycleKey;
@Produces
@DevCycleQualifier
public OpenFeatureAPI getApi() {
final OpenFeatureAPI openFeatureAPI = OpenFeatureAPI.getInstance();
DevCycleLocalOptions options = DevCycleLocalOptions.builder().build();
DevCycleLocalClient devCycleClient = new DevCycleLocalClient(devCycleKey, options);
// This is wild. Should be handled by the client.
// https://github.com/DevCycleHQ/java-server-sdk/pull/111/files/4e21dc9a8f7d5d4d063528b355fc5c6125d9c78b#r1381707824
for (int i = 0; i < 10; i++) {
if (devCycleClient.isInitialized()) {
break;
}
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
openFeatureAPI.setProvider(devCycleClient.getOpenFeatureProvider());
return openFeatureAPI;
}
}
We change the Qualifier and the email field casing for the context.
@Path("/api")
public class PdAPI {
@Inject()
// @FlagdQualifier
// @ConfigCatQualifier
@DevCycleQualifier
OpenFeatureAPI openFeatureAPI;
@GET()
@Path("/check/{email}")
@Produces(MediaType.APPLICATION_JSON)
public Response checkFeature(@PathParam("email") String email) {
final var client = openFeatureAPI.getClient();
client.addHooks(new PDTrackerHook());
var ctx = new MutableContext();
ctx.setTargetingKey("isfromproductdock");
// ctx.add("Email", email);
ctx.add("email", email);
if (client.getBooleanValue("isfromproductdock", false, ctx)) {
return Response.ok(new FeatureFlagResponse("This feature is enabled! User is from ProductDock.")).build();
}
return Response.ok(new FeatureFlagResponse("This feature is disabled! User is not from ProductDock.")).build();
}
}
record FeatureFlagResponse(String message) {
}
Hooks
You might have noticed the addHooks code. I like the idea of tracking, and the hooks are a perfect place to set this up. I haven’t done anything special, just wanted to see how it behaves.
public class PDTrackerHook implements BooleanHook {
private static final Logger LOG = Logger.getLogger(PDTrackerHook.class);
@Override
public void after(HookContext<Boolean> ctx, FlagEvaluationDetails<Boolean> details, Map<String, Object> hints) {
LOG.info(details.getFlagKey() + " : " + details.getValue());
}
}
More on hooks, visit this page.
What’s next
As you can see in the examples above, OpenFeature gives you flexibility with feature management providers. The team behind OpenFeature is actively working on further improvements, and I’m eagerly anticipating the exciting development ahead.
While this article primarily focuses on the server-side implementation, it’s important to note that OpenFeature also has robust client-side capabilities. If you’re keen to dive in, I recommend beginning with exploring their documentation. From there, feel free to explore any direction that aligns with your goals and preferences.
Tags:
Jovica Zorić
Chief Technology OfficerJovica is a techie with more than ten years of experience. His job has evolved throughout the years, leading to his present position as the CTO at ProductDock. He will help you to choose the right technology for your business ideas and focus on the outcomes.