Feature Flags e Trunk-Based Development: Lançamentos em 1 Segundo
A Ilusão do GitFlow: Como as Branches Longas Destroem a Tua Produtividade
Durante anos, muitas equipas de desenvolvimento seguiram à risca o modelo clássico do GitFlow:
- Crias uma branch específica (
feature/novo-carrinho) a partir dadevelop. - Ficas a trabalhar isolado nessa branch durante quatro semanas.
- Entretanto, outros cinco colegas fazem dezenas de alterações e melhorias na
develop. - No final do mês, tentas juntar a tua branch de volta.
O resultado é o conhecido Inferno de Merges: dezenas de conflitos de código ficheiro a ficheiro, testes unitários que deixam de passar e dias inteiros perdidos apenas a tentar reconciliar código divergente.
E quando finalmente fazes o lançamento para produção, o risco é gigantesco. Como estás a publicar cinco semanas de trabalho com dezenas de funcionalidades misturadas, se algo correr mal é quase impossível descobrir qual foi a linha exata que partiu o sistema. Fazer rollback significa anular o trabalho da equipa inteira, gerando frustração geral.
O LABIRINTO DE BRANCHES DO MODELO GITFLOW
- main ● ● (Lançamento Arriscado!) develop ● ● ● ● ● ● ● ● (Conflitos de Merge sem fim!) feature ● ● (Isolado há 1 mês: código divergente!)
Para aumentares a frequência de entrega com segurança psicológica absoluta, a engenharia de software moderna prefere o Trunk-Based Development combinado com Feature Flags (ou Feature Toggles).
O Conceito Central: Separar a Publicação Técnica do Lançamento de Negócio
A grande mudança de mentalidade consiste em perceber que Fazer Deploy e Lançar uma Funcionalidade são coisas completamente diferentes:
- Fazer Deploy (Ação Técnica): Enviar os contentores e os ficheiros para os servidores de produção. Isto deve acontecer continuamente, várias vezes por dia, sempre que um Pull Request pequeno é aprovado na branch
main. - Lançar (Decisão de Negócio): Disponibilizar a funcionalidade aos clientes. Pode acontecer gradualmente, por percentagem de utilizadores, para clientes beta ou num dia específico de campanha.
Ao protegeres os novos blocos de código com verificações booleanas dinâmicas, podes ter código em desenvolvimento a correr nos servidores de produção sem que nenhum cliente comum se aperceba.
SEPARAR O DEPLOY DO LANÇAMENTO REAL
- Pipeline de Integração Contínua
- Commit na main → Testes CI → Imagem Docker → Deploy em Produção (10x ao dia)
- CÓDIGO EM EXECUÇÃO NO SERVIDOR if (flags.ativa(“checkout_novo”, utilizador)) { return desenharNovoCheckout(); // APENAS PARA 5% DOS CLIENTES!
- } else { return desenharCheckoutAntigo(); // 95% CONTINUA NA VERSÃO ATUAL
Esta abordagem cumpre os princípios de anti-over-engineering: código simples, branches que duram poucas horas e zero conflitos gigantescos de Git.
Implementar Feature Flags com Redis e Memória Local em Node.js
Uma implementação amadora de feature flags faz uma consulta à base de dados ou uma chamada de rede a cada if (flags.ativa()), tornando a API extremamente lenta.
Nas nossas web apps e websites de alta performance, as flags devem ser avaliadas em frações microscópicas de milissegundo diretamente na memória RAM:
// src/services/featureFlags.ts
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL || 'redis://127.0.0.1:6379');
// Cache local em memória RAM sincronizada por Pub/Sub
const cacheLocalFlags = new Map<string, boolean>();
export async function inicializarFlags() {
// Carrega o estado atual do Redis para a RAM no arranque
const todasFlags = await redis.hgetall('app:feature_flags');
for (const [chave, valor] of Object.entries(todasFlags)) {
cacheLocalFlags.set(chave, valor === 'true');
}
// Escuta atualizações instantâneas em tempo real
const sub = new Redis(process.env.REDIS_URL || 'redis://127.0.0.1:6379');
await sub.subscribe('canal:atualizacao_flags');
sub.on('message', (_canal, mensagem) => {
const { chave, ativa } = JSON.parse(mensagem);
cacheLocalFlags.set(chave, ativa);
console.log(`[Flags] Atualizada '${chave}' para ${ativa} na memória RAM!`);
});
}
export function isFeatureAtiva(chaveFlag: string, padrao = false): boolean {
if (cacheLocalFlags.has(chaveFlag)) {
return cacheLocalFlags.get(chaveFlag)!;
}
return padrao;
}
Avaliar isFeatureAtiva("novo_design") demora apenas 0.002 milissegundos no Node.js. Quando um gestor de produto ativa uma novidade no painel administrativo, o Redis Pub/Sub avisa todos os servidores e contentores Docker em menos de 10 milissegundos.
Lançamentos Progressivos por Hash Determinístico de Utilizador
As tuas flags não precisam de ser apenas um botão de ligar/desligar global. Podes fazer lançamentos graduais em percentagem (canary release) sem guardares tabelas complexas na base de dados.
Ao calculares o hash MD5 do identificador do cliente, o utilizador cai sempre no mesmo grupo de forma determinística:
// src/utils/distribuicaoPercentagem.ts
import crypto from 'node:crypto';
export function utilizadorNaPercentagem(
chaveFeature: string,
utilizadorId: string,
percentagemAlvo: number // 0 a 100
): boolean {
if (percentagemAlvo <= 0) return false;
if (percentagemAlvo >= 100) return true;
// Gera o hash combinando a funcionalidade com o ID do utilizador
const hash = crypto
.createHash('md5')
.update(`${chaveFeature}:${utilizadorId}`)
.digest('hex');
// Converte os primeiros 8 caracteres num número inteiro
const valorNumerico = parseInt(hash.substring(0, 8), 16);
const balde = valorNumerico % 100; // Devolve um valor entre 0 e 99
return balde < percentagemAlvo;
}
Se definires percentagemAlvo = 10, exatamente 10% da tua base de dados verá a novidade. O mesmo utilizador continuará a ver a nova versão em todas as páginas, evitando comportamentos estranhos.
DISTRIBUIÇÃO DETERMINÍSTICA DE CLIENTES
- Utilizador ID: 104 → Hash(flag + id) % 100 → Grupo: 05 (Vê a NOVA versão!)
- Utilizador ID: 890 → Hash(flag + id) % 100 → Grupo: 72 (Vê a versão ANTIGA)
- Utilizador ID: 412 → Hash(flag + id) % 100 → Grupo: 58 (Vê a versão ANTIGA)
Se o sistema de monitorização detetar um erro inesperado, basta mudar a percentagem para 0% e o rollback acontece em 1 segundo, sem necessidade de novo deploy. Podes analisar soluções de código aberto como o Unleash no GitHub.
Boas Práticas Operacionais: Evitar Dívida Técnica de Flags Esquecidas
Seguindo as normas de engenharia praticadas na WebXtek, aplica estas três recomendações para não acumulares lixo no código:
- Classifica as Tuas Flags com Rigor: Distingue entre Flags de Lançamento (temporárias, apagadas após 2 semanas), Flags de Experiência (testes A/B) e Disjuntores Operacionais (permanentes, para desligar rotas pesadas se a base de dados sofrer picos).
- Define Prazos de Remoção Obrigatórios: Se uma flag de lançamento estiver no código há mais de 30 dias, bloqueia a pipeline de CI até o programador remover a condição e apagar o código velho.
- Regista o Estado das Flags nos Erros: Quando ocorrer uma exceção na aplicação, anexa a lista de flags ativas aos registos estruturados. Saber que o erro só acontece quando
novo_carrinho = truepermite isolar o problema num instante.
Ao adotares o Trunk-Based Development com feature flags, permites que a tua equipa publique código diariamente sem receio de quebrar o negócio e ganhas a capacidade de reverter qualquer falha num piscar de olhos.
Na prática, aplicas exatamente estes padrões operacionais em setores exigentes como saas empresarial b2b e especialistas em devops e arquitetura cloud. Quando alinhas a tua estrutura através de web apps e websites de alta performance, transformas boas práticas técnicas numa vantagem competitiva real e mensurável para o teu negócio.
[+] [ INDEX_DIRECTORY ] 13 tópicos ▼
- A Ilusão do GitFlow: Como as Branches Longas Destroem a Tua Produtividade
- O Conceito Central: Separar a Publicação Técnica do Lançamento de Negócio
- Implementar Feature Flags com Redis e Memória Local em Node.js
- Lançamentos Progressivos por Hash Determinístico de Utilizador
- Boas Práticas Operacionais: Evitar Dívida Técnica de Flags Esquecidas
- Autor
- Perguntas Frequentes
- O que significa separar o deploy do lançamento da funcionalidade?
- Como é que o Trunk-Based Development acaba com os conflitos de merge no Git?
- Porque é que reverter uma alteração por feature flag é 100x mais rápido do que um git revert?
- Como evitas que o código fique cheio de lixo e flags antigas esquecidas?
- Nós Relacionados
- Sequência do Caminho
Perguntas Frequentes
O que significa separar o deploy do lançamento da funcionalidade?
O deploy é uma ação técnica: colocar o código compilado nos servidores de produção. O lançamento é uma decisão de negócio: tornar essa funcionalidade visível para os utilizadores. Com feature flags, fazes deploy de código inacabado para produção sem que ninguém o veja até estar pronto.
Como é que o Trunk-Based Development acaba com os conflitos de merge no Git?
Em vez de manteres branches longas abertas durante semanas, a equipa junta alterações pequenas e frequentes diretamente no ramo principal (main) várias vezes por dia. As novidades incompletas ficam escondidas atrás de flags, eliminando conflitos de código.
Porque é que reverter uma alteração por feature flag é 100x mais rápido do que um git revert?
Um git revert tradicional exige criar um novo commit, esperar pela pipeline de CI/CD, gerar novas imagens e reiniciar servidores (demorando 15 a 30 minutos). Com uma feature flag, basta alterares um booleano no painel ou Redis, desligando o erro em menos de 1 segundo.
Como evitas que o código fique cheio de lixo e flags antigas esquecidas?
As flags de lançamento devem ter prazos de vida rigorosos. Assim que uma novidade for libertada para 100% dos utilizadores e estiver estável durante duas semanas, cria-se obrigatoriamente uma tarefa para remover as condições if/else e apagar o código antigo.
[ RELATED_NODES ]
> INICIAR_PROJETO
Precisa de um website que transmita confiança, apareça na pesquisa e dê mais força à sua presença digital? Comece a conversa aqui.