Feature flags em Go: Implantando mudanças sem medo e sem downtime

Você já passou por isso: uma nova funcionalidade pronta, mas o time inteiro suando para fazer o deploy. “E se der errado?” “Precisamos esperar a madrugada.” “Vamos rezar para não precisar reverter.” O medo de implantar é um dos maiores freios à inovação em software.

A solução não é testar mais (embora testes ajudem). A solução é feature flags – também conhecidas como toggles de funcionalidade. Com elas, você pode liberar uma mudança para 1% dos usuários, testar em produção, e reverter em segundos se algo der errado. Tudo sem novo deploy.

Neste post, vamos mostrar como implementar feature flags em Go, desde uma solução simples até integração com ferramentas maduras, e como a Jacobus Software usa essa técnica para fazer deploys sem sustos – mesmo às 15h de uma sexta-feira.

O que são feature flags?

Feature flags são condicionais no código que controlam se uma funcionalidade está ativa ou não, sem precisar alterar o código novamente. A decisão pode ser baseada em:

  • Percentual de usuários (10%, 50%, 100%)
  • Lista branca (apenas usuários internos ou beta)
  • Regras de negócio (apenas na região Sul, apenas para clientes premium)
  • Data/hora (ativar automaticamente em 01/06/2026)
if featureFlags.IsEnabled("novo_checkout") {
    // novo fluxo de checkout
} else {
    // fluxo antigo
}

Com um simples toggle, você pode:

  • Testar em produção – liberar para um grupo pequeno e validar métricas
  • Fazer canary deploy – aumentar gradualmente até 100%
  • Reverter instantaneamente – desligar a flag sem rollback de código
  • Desacoplar deploy de lançamento – código no ar, funcionalidade desligada até a data de marketing

Implementação simples: feature flags com map em memória

Para começar, uma implementação minimalista (não recomendada para produção, mas ótima para entender o conceito):

type FeatureFlag struct {
    Name    string
    Enabled bool
}

var flags = map[string]bool{
    "novo_checkout": false,
    "relatorio_novo": true,
}

func IsEnabled(name string) bool {
    return flags[name]
}

Problemas: precisa recompilar para mudar, não funciona em múltiplos servidores.

Implementação para produção: flags no Redis com Go

Uma solução prática: armazenar flags no Redis e cachear em memória para performance.

import (
    "context"
    "sync"
    "time"
    "github.com/redis/go-redis/v9"
)

type FlagService struct {
    rdb    *redis.Client
    mu     sync.RWMutex
    cache  map[string]bool
    ttl    time.Duration
}

func NewFlagService(rdb *redis.Client) *FlagService {
    s := &FlagService{
        rdb:   rdb,
        cache: make(map[string]bool),
        ttl:   10 * time.Second,
    }
    go s.refreshCache()
    return s
}

func (s *FlagService) IsEnabled(ctx context.Context, flagName string) bool {
    s.mu.RLock()
    val, ok := s.cache[flagName]
    s.mu.RUnlock()
    if ok {
        return val
    }

    // fallback para Redis
    enabled, err := s.rdb.Get(ctx, "flag:"+flagName).Bool()
    if err == nil {
        s.mu.Lock()
        s.cache[flagName] = enabled
        s.mu.Unlock()
        return enabled
    }
    return false // default
}

func (s *FlagService) refreshCache() {
    ticker := time.NewTicker(s.ttl)
    for range ticker.C {
        // recarrega todas as flags
    }
}

Vantagens: atualização em tempo real (TTL pequeno), compartilhado entre múltiplas instâncias, fácil integração com painel de admin.

Feature flags por percentual de usuários

Nem toda flag é liga/desliga. Muitas vezes você quer liberar gradualmente, por exemplo, 10% dos usuários.

func (s *FlagService) IsEnabledForUser(flagName string, userID string) bool {
    // Primeiro, flag global está ativa?
    if !s.IsGlobalEnabled(flagName) {
        return false
    }

    // Percentual configurado (ex: "novo_checkout:20" = 20% dos usuários)
    percentage := s.GetPercentage(flagName) // 0-100

    // Hashing consistente para o mesmo usuário sempre cair no mesmo grupo
    hash := fnv.New32a()
    hash.Write([]byte(flagName + userID))
    bucket := hash.Sum32() % 100

    return bucket < uint32(percentage)
}

Assim, o mesmo usuário vê a mesma experiência sempre, mesmo entre requisições.

Feature flags com SDKs profissionais

Para necessidades mais complexas (paineis web, segmentação avançada, auditoria), use soluções prontas:

FerramentaGo SDKIdeal para
LaunchDarklySim, maduroEmpresas com time de produto dedicado
FlagsmithSim, open-sourceTimes que querem self-hosted
UnleashSimOpen-source, boa UI
go-feature-flagNativoSolução 100% Go, simples

Exemplo com LaunchDarkly em Go:

import ld "github.com/launchdarkly/go-server-sdk"

ldClient, _ := ld.MakeClient("sdk-key", 5*time.Second)
enabled, _ := ldClient.BoolVariation("novo-checkout", ldUser, false)

Feature flags + CI/CD: o fluxo completo

Na Jacobus, integramos feature flags ao pipeline de entrega contínua:

  1. Desenvolvedor implementa nova funcionalidade protegida por flag "feature_x" (default desligada).
  2. Pull request → merge na main → deploy automático (flag continua desligada).
  3. QA ativa flag via painel para ambiente de staging/homologação.
  4. Testes aprovados → deploy em produção com flag ainda desligada.
  5. Ativação gradual: 1% → 10% → 50% → 100%, monitorando métricas de erro e latência.
  6. Se erro sobe, desliga flag (rollback em segundos, sem novo deploy).
  7. Após 100% estável por uma semana, removemos o código antigo e a flag (cleanup).

Esse fluxo elimina o medo de deploy. Lançamentos deixam de ser eventos de risco e viram rotina.

Cuidados e boas práticas

⚠️ Não use feature flags para tudo

  • Flags aumentam complexidade (caminhos condicionais no código).
  • Remova flags antigas assim que a funcionalidade estiver estável (evite “lixo de flags”).
  • Teste o código com flag ligada e desligada.

⚠️ Atenção a flags em contexto de banco de dados

Se a flag controla um novo schema de banco, você precisa lidar com migrações compatíveis com os dois fluxos.

⚠️ Performance de verificação de flags

Evite consultar flags a cada requisição via rede (Redis, LaunchDarkly) sem cache local. Use TTLs curtos (ex: 10s) e cache em memória.

Exemplo real: checkout dois-passos na Jacobus

Um cliente e-commerce queria migrar o checkout de uma página para duas páginas, mas com medo de impacto na conversão. Implementamos:

  • Flag "checkout_dois_passos" com percentual ajustável.
  • Começamos com 1% dos usuários.
  • Métricas de abandono de carrinho comparadas entre grupos.
  • Com dados positivos, subimos para 10%, 50%, 100% em 2 semanas.
  • Zero incidentes. Conversão final aumentou 8%.

Sem feature flags, seria um deploy monolítico com risco alto – ou meses de protótipo fora de produção.

Conclusão: feature flags são ferramentas de coragem

Deploy não precisa ser um momento de tensão. Com feature flags em Go, você ganha a capacidade de testar hipóteses em produção, reduzir risco e acelerar a entrega de valor.

Na Jacobus Software, feature flags são padrão em todos os nossos projetos. Porque acreditamos que inovação não pode esperar pela madrugada.


🚦 Quer deploy sem medo no seu sistema Go?

Nossos especialistas implementam feature flags com cache distribuído (Redis) ou SDKs profissionais, e integram ao seu CI/CD para que você lance novas funcionalidades a qualquer momento, com segurança.

👉 Fale com a Jacobus Software

Rolar para cima