Executando verificação de segurança...
1

Feature Flags sem Vendor Lock-in: Implementação Própria com TypeScript e Zero Dependência de SaaS

O problema real: sua release depende de um SDK que você não controla

Feature flags resolvem um problema concreto: separar deploy de release. Você faz merge na main, o código vai para produção, mas a funcionalidade só aparece para quem você decide. O problema começa quando a implementação amarra o código inteiro a um provider específico.

LaunchDarkly cobra por seat e por flag evaluation. Unleash tem versão open source, mas o hosted exige plano pago para funcionalidades como métricas e audit log. Split, Flagsmith, ConfigCat: cada um com SDK próprio, formato de configuração próprio e API própria. Trocar de provider significa reescrever cada ponto do código onde uma flag é avaliada.

A solução é uma camada de abstração fina entre o código de negócio e o mecanismo de avaliação. Não é over-engineering: são menos de 200 linhas de código que eliminam a dependência direta de qualquer vendor.

Arquitetura: porta e adaptador para flags

O padrão é simples. Uma interface define o contrato. Adaptadores implementam essa interface para cada backend (JSON local, banco de dados, Redis, variáveis de ambiente, ou qualquer SaaS). O código de negócio depende só da interface.

// src/flags/types.ts

// FlagValue aceita os tipos reais que flags assumem em produção.
// Booleano cobre toggle simples. String cobre variantes (A/B test).
// Number cobre rollout percentual.
export type FlagValue = boolean | string | number;

export interface FlagContext {
  userId?: string;
  email?: string;
  country?: string;
  plan?: "free" | "pro" | "enterprise";
  [key: string]: unknown;
}

export interface FlagProvider {
  get(flagName: string, context?: FlagContext): Promise<FlagValue>;
  getAllFlags(): Promise<Record<string, FlagValue>>;
  dispose(): Promise<void>;
}

A interface FlagProvider tem três métodos. get avalia uma flag para um contexto. getAllFlags retorna o estado completo (útil para debug e dashboards internos). dispose libera conexões, algo que providers baseados em Redis ou WebSocket precisam.

Adaptador 1: JSON local para desenvolvimento

O adaptador mais simples lê de um arquivo JSON. Serve para desenvolvimento local e para testes de integração onde você quer controle total sobre o estado das flags.

// src/flags/providers/json-provider.ts
import { readFile } from "node:fs/promises";
import type { FlagProvider, FlagValue, FlagContext } from "../types.js";

export class JsonFlagProvider implements FlagProvider {
  private flags: Record<string, FlagValue> = {};
  private loaded = false;

  constructor(private readonly filePath: string) {}

  private async load(): Promise<void> {
    if (this.loaded) return;
    const raw = await readFile(this.filePath, "utf-8");
    this.flags = JSON.parse(raw);
    this.loaded = true;
  }

  async get(flagName: string, _context?: FlagContext): Promise<FlagValue> {
    await this.load();
    // Retorna false para flags inexistentes em vez de undefined.
    // Flag inexistente = funcionalidade desligada. Fail-safe.
    return this.flags[flagName] ?? false;
  }

  async getAllFlags(): Promise<Record<string, FlagValue>> {
    await this.load();
    return { ...this.flags };
  }

  async dispose(): Promise<void> {
    this.flags = {};
    this.loaded = false;
  }
}

O arquivo JSON correspondente:

{
  "new_checkout_flow": true,
  "dark_mode": false,
  "max_upload_size_mb": 50,
  "pricing_variant": "control"
}

Adaptador 2: variáveis de ambiente para containers

Em ambientes containerizados, variáveis de ambiente são o mecanismo de configuração mais portável. Funciona com Docker, Kubernetes ConfigMaps, Cloudflare Workers e qualquer plataforma serverless.

// src/flags/providers/env-provider.ts
import type { FlagProvider, FlagValue, FlagContext } from "../types.js";

// Prefixo evita colisão com variáveis do sistema.
const FLAG_PREFIX = "FF_";

function parseValue(raw: string): FlagValue {
  if (raw === 

---

Leia o artigo completo em [https://www.vivodecodigo.com.br/backend/feature-flags-sem-vendor-lock-in-typescript-implementacao-propria](https://www.vivodecodigo.com.br/backend/feature-flags-sem-vendor-lock-in-typescript-implementacao-propria)
Carregando publicação patrocinada...