Otevřený standard nezávislý na poskytovateli pro feature flagging, který funguje s libovolným nástrojem pro správu feature flagů.
V nejjednodušším případě je to if/else, který lze ovládat za běhu aplikace. Umožňuje měnit chování aplikace bez nasazení nového kódu.
Java · server-sideif (client.getBooleanValue("new-checkout", false)) {
renderNewCheckout(); // zapnuto za běhu, bez redeploye
} else {
renderLegacyCheckout();
}
Flagy jsou dynamické (vyhodnocují se za běhu) a context-aware (rozhodnutí závisí např. na konkrétním uživateli).
Postupné zpřístupnění nové funkce malé skupině uživatelů.
Měření dopadu varianty na chování a engagement uživatelů.
Rozpracovaná funkcionalita skrytá před uživateli, dostupná pro interní testy.
Bezpečné vypnutí části systému během výpadku.
Omezení funkcí podle geografie, IP, licence či compliance.
Méně dlouhožijících feature branchí — trunk-based development.
Plné využití flagů vyžaduje flagging systém — samostatnou službu plus klientskou knihovnu.
OpenFeature poskytuje jednotné, standardizované SDK, do kterého se zapojují různí poskytovatelé (providers). Aplikační kód zůstává stejný — měníte jen provider.
Vývojář pracuje pouze s Evaluation API. Provider mapuje volání na konkrétní flagging systém — vyměnitelný bez zásahu do aplikační logiky.
Rozhraní, se kterým pracuje autor aplikace. Vyhodnocuje flagy a vrací typované hodnoty (boolean, string, number, object).
Java · server-sideOpenFeatureAPI api = OpenFeatureAPI.getInstance();
// registrace poskytovatele (blokující, počká na READY)
api.setProviderAndWait(new YourProvider());
// získání klienta a vyhodnocení flagu
Client client = api.getClient();
boolean v2 = client.getBooleanValue("v2_enabled", false);
Druhý argument je default — hodnota při nedostupnosti provideru. Flag tedy nikdy „nespadne".
„Překladová vrstva" mezi Evaluation API a konkrétním flagging systémem. Mapuje argumenty na ekvivalent v daném systému.
FeatureProvider stačí doplnit metody pro vyhodnocení jednotlivých typů (boolean, string, number, object)// migrace mezi providery bez zásahu do volání flagů
MultiProvider multi = new MultiProvider(
List.of(newProvider, oldProvider) // nový se ptá první
);
api.setProviderAndWait(multi);
Kontejner dat, na jejichž základě probíhá cílení. Skládá se ze čtyř vrstev, každá s jiným životním cyklem — od statických faktů o aplikaci po data jednoho requestu.
// 1) GLOBAL — statické, jednou při startu
api.setEvaluationContext(new ImmutableContext(Map.of(
"region", new Value("eu-central-1"),
"tier", new Value("standard")))); // výchozí
// 2) CLIENT — společné pro modul/doménu
Client checkout = api.getClient("checkout");
checkout.setEvaluationContext(new ImmutableContext(
Map.of("module", new Value("checkout"))));
// 3) INVOCATION — data jednoho requestu
EvaluationContext req = new ImmutableContext(
session.getId(), // targetingKey
Map.of("email", new Value(email),
"country", new Value("CZ")));
checkout.getBooleanValue("new-payment", false, req);
Fakta o prostředí — region, verze, prod/staging. Nastavíš jednou.
Společné pro modul/doménu — checkout vs. billing mají jiný module.
Data requestu/uživatele — targetingKey, e-mail, země, IP. Mění se při každém volání.
Automatické obohacení odvozenými daty — viz další slide.
Kód zapojený do životního cyklu vyhodnocení flagu. Registruje se ve třech úrovních (scope) — pozor, „client" = OpenFeature Client objekt, ne frontend.
// globálně — všechny klienty v procesu
api.addHooks(new LoggingHook());
// na klientovi — jeden Client (modul/doména)
Client checkout = api.getClient("checkout");
Client billing = api.getClient("billing");
checkout.addHooks(new AuditHook()); // jen checkout
// jen pro jedno vyhodnocení
checkout.getBooleanValue("v2", false, ctx,
FlagEvaluationOptions.builder()
.hook(new ExampleHook()).build());
Před vyhodnocením — např. doplní či upraví evaluation context.
Po úspěšném vyhodnocení — validace hodnoty, telemetrie, tracking.
Při chybě během vyhodnocení — fallback, alerting.
Vždy na konci, bez ohledu na úspěch či chybu — úklid.
SDK vrstvy před vyhodnocením sloučí. Before hook doplní data, která nechceš tahat ručně u každého volání — typicky dotažená z jiné služby.
class EnrichmentHook implements Hook {
public Optional<EvaluationContext> before(
HookContext ctx, Map hints) {
String userId = ctx.getCtx().getTargetingKey();
String plan = subscriptions.lookupPlan(userId);
return Optional.of(new ImmutableContext(
Map.of("tier", new Value(plan)))); // "premium"
}
}
api.addHooks(new EnrichmentHook());
{
targetingKey: "<session-id>", // invocation
region: "eu-central-1", // global
module: "checkout", // client
email: "...", // invocation
country: "CZ", // invocation
tier: "premium" // hook přepsal
}
Priorita (pozdější přebíjí): global → client → invocation → before-hook. Proto tier = "premium".
Pointa: statická data nastavíš jednou, proměnná předáš per request, odvozená zařídí hook — místo kopírování do každého volání. Flag pak cílí na kteroukoli vlastnost, např. tier=premium v region=eu-central-1.
Reakce na změny stavu provideru nebo flagging systému — připravenost, chyby, nebo (nejzajímavěji) změna konfigurace flagů.
Java · server-sideClient client = api.getClient();
// reakce na změnu konfigurace flagů
client.onProviderConfigurationChanged(e -> {
// flagy se změnily v systému správy
});
// globální handler na zastarání cache provideru
api.onProviderStale(e -> { /* … */ });
Standardní události: PROVIDER_READY, PROVIDER_ERROR, PROVIDER_CONFIGURATION_CHANGED.
Pro testy nepotřebujete běžící flagging systém. SDK obsahuje In-Memory Provider — flagy definujete přímo v kódu a vyhodnocení běží lokálně, bez sítě.
Map<String, Flag<?>> flags = new HashMap<>();
flags.put("v2_enabled", Flag.builder()
.variant("on", true)
.variant("off", false)
.defaultVariant("on").build());
api.setProviderAndWait(new InMemoryProvider(flags));
const flags = {
v2_enabled: {
variants: { on: true, off: false },
disabled: false,
defaultVariant: 'on',
},
} as const;
OpenFeature.setProvider(new TypedInMemoryProvider(flags));
Varianty jsou pojmenované možné hodnoty flagu (on → true, off → false); defaultVariant určuje, která se vrátí bez targetingu. Jména jsou libovolná a flag nemusí být jen boolean — varianty mohou nést stringy či čísla.
Hodnoty lze měnit za běhu — ideální pro unit testy obou větví if/else. Pro jeden test stačí vyměnit provider, aplikační kód zůstává beze změny.
SDK přicházejí ve dvou variantách. Liší se hlavně v tom, jak modelují evaluation context.
Kontext se mění často, klidně při každém vyhodnocení (IP, session, e-mail). Předává se jako parametr volání.
Java// kontext při každém vyhodnocení
boolean v = client.getBooleanValue(
"beta", false, reqCtx);
Kontext odpovídá jednomu uživateli a mění se zřídka. Při změně probíhá context reconciliation — provider přepočítá cache flagů.
TypeScript// kontext globálně (async), mění se zřídka
await OpenFeature.setContext({ targetingKey: userId });
// vyhodnocení je synchronní (z cache)
const v = client.getBooleanValue("beta", false);
Local evaluation — stáhne definice flagů i segmenty a vyhodnocuje lokálně v procesu, bez sítě na každý flag.
Remote evaluation — stáhne jen vyhodnocené flagy pro klienta do cache (bez pravidel segmentů) a čte z ní synchronně.
Jinými slovy: je to garance, že OpenFeature není marketingový nástroj jednoho poskytovatele, ale férový oborový standard se stabilním zázemím.
openfeature.dev/docs
openfeature.dev/ecosystem
github.com/open-feature
Děkuji za pozornost — dotazy?