DEV Community

Marcus Dorbação
Marcus Dorbação

Posted on

Feature Flags - Thinking

Sistema de Feature Flags — Documentação Técnica

Documentação em construção. Público-alvo: devs do time (uso técnico/API).
Sistema avançado: rollout percentual, segmentação de usuários e A/B test.

Índice

  1. Visão geral
  2. Core de flags
  3. Targeting e segmentação
  4. Rollout progressivo
  5. A/B testing / Experimentação
  6. SDKs e integração técnica
  7. Autenticação (SDK Key)
  8. Sincronização em tempo real
  9. Eventos de conexão
  10. Webhooks (integração externa)

Visão geral

Sistema de feature flags construído do zero, com suporte a:

  • Flags booleanas e multivariáveis
  • Segmentação por atributos de usuário
  • Rollout percentual com bucketing consistente
  • A/B testing com múltiplas variantes
  • SDKs client-side e server-side

Core de flags

  • Tipos de flag: boolean (on/off) e multivariável (string/número/JSON), permitindo retornar variantes diferentes, não só ligar/desligar
  • Ambientes: dev, staging, produção — cada um com seu próprio estado de flag
  • Kill switch: desligar uma flag instantaneamente em produção, sem deploy

Targeting e segmentação

  • Regras de segmentação: por atributo do usuário (país, plano, versão do app, device, etc.)
  • Targeting individual: ligar a flag para usuários específicos (por ID, email)
  • Grupos/coortes: listas de usuários (ex: beta testers, funcionários internos)

Rollout progressivo

  • Rollout percentual: liberar gradualmente para uma fatia da base (5%, 10%, 50%...)
  • Sticky bucketing: garante que o mesmo usuário sempre caia na mesma variante entre sessões
  • Hash consistente: normalmente hash do user ID + flag key para decidir o bucket

A/B testing / Experimentação

  • Múltiplas variantes com pesos configuráveis (ex: A 33%, B 33%, C 34%)
  • Integração com analytics: disparar eventos de exposição (quem viu qual variante)
  • Significância estatística geralmente delegada a uma ferramenta de análise externa, mas o sistema de flags precisa expor os dados de exposição

SDKs e integração técnica

SDK client-side vs server-side

A diferença não é só "onde roda o código" — é uma questão de segurança e vazamento de informação.

Server-side SDK

  • Roda em ambiente confiável (backend)
  • Pode ter acesso a todas as flags, incluindo as não lançadas, regras de segmentação completas e segredos usados no targeting
  • Comunica-se direto com a API central ou via um Relay Proxy (serviço intermediário que reduz chamadas repetidas)

Client-side SDK (browser, mobile, apps)

  • Roda em ambiente não confiável — qualquer um pode inspecionar o payload
  • Nunca deve receber a lista completa de flags. O backend avalia a flag para aquele usuário específico e envia só o payload já resolvido (ex: flag X = true, flag Y = variante B)
  • Isso é feito via endpoint do tipo /sdk/eval?context={user}, retornando um payload minimalista
  • Regra crítica: nunca usar a SDK key server-side (completa) dentro de um app client — isso vazaria todas as flags e regras internas

Avaliação local vs remota

Abordagem Latência Frescor dos dados
Remota (thin client) Alta — chamada de rede a cada checagem Sempre atualizado
Local (thick client, recomendada) Baixa — avaliação em memória Depende da estratégia de sync

Estratégias de atualização do cache local:

  • Polling: SDK pergunta "tem mudança?" a cada N segundos
  • Streaming: servidor empurra updates em tempo real assim que uma flag muda

Muitos SDKs combinam os dois: streaming como canal principal + polling como fallback caso a conexão caia.

Fallback / default values

  • Todo flag check exige um valor default obrigatório na chamada (nunca deixar o SDK "adivinhar")
  • Hierarquia de fallback:
    1. Valor em cache local (último snapshot conhecido)
    2. Se nunca conectou → default fornecido no código de chamada
  • Falha do serviço de flags nunca deve travar a aplicação — deve ser silenciosa e logada
  • Timeout de inicialização: tempo máximo de espera no boot para o primeiro fetch (ex: 5s); depois disso, segue com defaults e atualiza quando possível
  • Emitir métrica/log quando o SDK cai em modo fallback, para sinalizar degradação do serviço

Autenticação (SDK Key)

A SDK key funciona como um bearer token:

Authorization: Bearer sdk-a1b2c3d4...
Enter fullscreen mode Exit fullscreen mode
Elemento Papel
SDK key (bearer token) Autentica + resolve escopo (projeto/ambiente) — não participa da decisão de segmentação
Context (key, plan, country...) Fornece os dados para a decisão de segmentação e rollout

Exemplo de request:

POST /evaluate
Headers: { "Authorization": "Bearer sdk-a1b2c3d4..." }

Body: {
  "flagKey": "cancelar-nota-fiscal",
  "context": {
    "key": "user-12345",
    "plan": "enterprise",
    "country": "BR"
  }
}
Enter fullscreen mode Exit fullscreen mode

Por que não expor projectId/environment como parâmetros públicos

Alternativa descartada: passar ?project=app-mobile&env=production abertamente, sem token.

Problemas dessa abordagem:

  1. Enumeração — projectId previsível permite testar/descobrir outros projetos/ambientes
  2. Sem autenticação — impossível distinguir chamada legítima de bisbilhotagem
  3. Vazamento de lógica de negócio — testar contexts publicamente permite reconstruir regras de segmentação por engenharia reversa
  4. Sem revogação/rotação — sem token não há "chave" para cortar acesso; seria preciso mudar a própria estrutura da API
  5. Sem rate limiting/billing por cliente — impossível medir uso ou isolar consumidores
  6. DoS mais fácil — sem identificação, não dá para aplicar throttling seletivo
  7. Mistura acidental de ambientes — sem credencial vinculante, é mais fácil um client de produção acessar staging por engano

Sincronização em tempo real

Por que webhook não serve como mecanismo de sync do SDK

Webhook exige que o servidor inicie uma conexão de saída até o cliente — o que não funciona para a maioria dos consumidores reais de SDK:

  • Frontend/browser: sem endereço público
  • App mobile: sem IP público, sem porta aberta
  • Backend atrás de NAT/firewall corporativo: porta não exposta
  • Serverless/Lambda: função só existe durante a execução
  • Múltiplas réplicas atrás de load balancer: ambíguo para qual réplica enviar

Por isso, o padrão adotado (como na maioria dos sistemas de feature flag do mercado) é o inverso: o cliente inicia a conexão de saída (streaming ou polling) e mantém ela aberta.

SSE como alternativa ao WebSocket

WebSocket é bidirecional e mais pesado que o necessário — o caso de uso aqui é apenas server → client.

SSE (Server-Sent Events) cobre esse caso:

  • Conexão HTTP simples, unidirecional
  • Reconexão automática nativa
  • Funciona sobre HTTP/1.1 comum, sem upgrade de protocolo
  • Mais simples de implementar mantendo tempo real

fluxo de autenticação SSE

Eventos de conexão

SdkConnected

Dispara quando o SDK abre a conexão de streaming (SSE/WebSocket) e o token é validado com sucesso. Não é só "TCP conectou" — é "conexão autenticada e pronta para receber updates daquele escopo (org/app/ambiente)".

SdkDisconnected

Dispara quando a conexão cai, por um de três motivos (importante diferenciar no payload):

  1. Fechamento gracioso — shutdown, deploy, scale-down
  2. Timeout/heartbeat perdido — SDK parou de responder ao keep-alive
  3. Erro de rede — queda abrupta

Diferenciar o motivo importa para observabilidade: uma queda maciça de conexões pode ser "todo mundo fez deploy ao mesmo tempo" (normal) ou "o serviço de streaming caiu" (crítico).

Pontos de atenção:

  • Reconexões automáticas com backoff podem gerar ruído (SdkDisconnected → SdkConnected repetidos) — considerar debounce/agregação nas métricas
  • Incluir um connectionId único por sessão de streaming para correlacionar conexão/desconexão e calcular duração

Usos práticos:

  • Observabilidade — quantos SDKs ativos por ambiente
  • Detecção de degradação — queda anormal indica problema no Sync service
  • Billing/capacity planning — se cobrança for por conexões simultâneas

Webhooks (integração externa)

Webhook não é o mecanismo de sincronização do SDK, mas é útil como feature de integração opcional, quando o receptor é um serviço backend do próprio cliente, controlado por eles, com endpoint público de propósito.

Exemplos de uso:

  • Notificar o sistema de CI/CD do cliente quando uma flag mudar em produção
  • Sincronizar com um sistema de config interno do cliente

Modelo proposto: URL de webhook registrada no momento da autenticação (junto com organização/aplicação/ambiente), salva em uma tabela de webhooks associada à chave/token.


Em aberto

  • [ ] Detalhar payload dos eventos SdkConnected/SdkDisconnected
  • [ ] Fluxo completo de evaluate() (resolução de token → busca da flag → segmentação → rollout → resultado)
  • [ ] Desenho do schema de dados completo
  • [ ] Desenho detalhado da tabela de webhooks como feature de integração

Top comments (0)

The discussion has been locked. New comments can't be added.