O que é trunk based development? Guia prático para SREs

Resumo

Entender o que é trunk based development começa por uma restrição: todos os desenvolvedores integram mudanças pequenas em um único branch, o trunk ou main, pelo menos uma vez por dia, mantendo-o sempre pronto para release. O DORA recomenda no máximo três branches ativos, sem code freeze e com build e testes em poucos minutos. Trabalho inacabado entra escondido atrás de feature flags, e a observabilidade decide entre corrigir para frente e reverter.

Tronco de árvore com galhos curtos que se juntam de volta ao tronco, ilustrando o trunk based development

São três da manhã e a branch de release não faz merge. Quarenta commits, três semanas de vida, tocando nos mesmos arquivos da main. Essa dor é o argumento central do trunk based development. Então, o que é trunk based development? É um modelo de branches em que todos integram mudanças pequenas em um único branch compartilhado, chamado trunk ou main, pelo menos uma vez por dia, e mantêm esse branch sempre pronto para ir para produção.

Este guia é para platform engineers que já dominam Git. Ele mostra o que o modelo exige, do que ele protege você e onde ele costuma quebrar sem aviso.

O que é trunk based development, em termos operacionais?

Vamos reduzir a definição às suas restrições. Todos os desenvolvedores integram em um único branch. Qualquer outro branch vive horas, não semanas. O trunk compila e passa nos testes a cada commit, por isso pode ser liberado a qualquer momento.

O guia de capacidades do DORA coloca números nessa definição: no máximo três branches ativos no repositório, merges no trunk pelo menos uma vez por dia, nenhum code freeze e um ciclo de build e teste que roda em poucos minutos. Esses números são o ponto central. O modelo funciona como um orçamento de ciclo de feedback, e não como uma preferência de estilo de branches.

Mesa escura à noite, com notebook exibindo um terminal e um alerta aceso no celular

Equipes pequenas às vezes fazem commit direto no trunk. Equipes maiores usam branches curtos e pull requests para revisão e checagens de build, mas nunca para segurar trabalho fora da integração. A referência trunkbaseddevelopment.com descreve os dois modos e cita o Google, que mantém cerca de 35.000 desenvolvedores trabalhando em um único trunk, dentro de um monorepo.

Por que branches longos falham e o que o trunk exige antes

Uma branch de feature é um empréstimo. Os juros são conflitos de merge, e eles se acumulam a cada commit que entra na main enquanto você está fora. Quanto mais a branch vive, maior fica o diff, e quanto maior o diff, menos alguém o lê com cuidado.

Veja o efeito disso na sua taxa de falha de mudanças. Um merge de 2.000 linhas recebe uma passada rápida e um aprovado. Um merge de 60 linhas é lido de verdade. Revisores não são preguiçosos, eles racionam atenção. Lotes pequenos são o único mecanismo que escala a qualidade da revisão.

O segundo custo fica invisível até a hora do release. Duas branches que passam no CI podem quebrar uma à outra quando se encontram. Você descobre isso na integração, no pior momento possível, com um prazo colado.

Migrar para o trunk sem as práticas de apoio é o jeito mais comum de as equipes voltarem para feature branches em menos de um trimestre. Quatro coisas precisam existir antes:

Se você pular qualquer um desses itens, o trunk vira o lugar onde a quebra se acumula, em vez do lugar onde ela é pega.

Como integrar trabalho inacabado sem colocá-lo em produção

Essa é a pergunta que todo cético faz, e a resposta é simples: você separa deploy de release. O código chega à produção escondido, e uma flag decide quem vê.

// checkout.ts
import { flags } from "./flags";

export async function renderCheckout(user: User) {
  if (await flags.isEnabled("new-payment-flow", { userId: user.id })) {
    return renderNewPaymentFlow(user); // merged to trunk, dark by default
  }
  return renderLegacyCheckout(user);
}

O novo fluxo entra no trunk no primeiro dia, atrás de uma flag desligada por padrão. Você ativa para usuários internos, depois para 1%, depois para 10%, com um gate de SLO em cada etapa. Se a taxa de erro estourar o orçamento, a flag é desligada e a mudança fica efetivamente revertida, sem novo deploy. Equipes que avaliam serviços de flags gerenciados costumam começar pelo LaunchDarkly, mas o padrão funciona com qualquer provedor ou com um store de configuração interno.

A segunda técnica é o branch by abstraction, para refatorações grandes. Você introduz uma interface, faz os chamadores passarem por ela, constrói a nova implementação por trás dela e troca quando estiver pronta. Não há branch de longa duração nem merge de big-bang.

Fileira de interruptores de parede, alguns ligados e outros desligados, como feature flags

O custo honesto: flags são dívida com meia-vida

Ninguém nas conferências quer falar disso. Cada flag que você adiciona é um condicional em produção que alguém vai precisar remover. Já vimos equipes de 80 engenheiros carregando várias centenas de flags obsoletas, cada uma um caminho de código que ninguém consegue testar por completo.

Trate flags como itens de vida curta por contrato. Dê a cada uma um dono e uma data de expiração na criação. Crie alertas para flags mais antigas que a expiração. Apague o caminho de código morto no mesmo pull request que remove a flag.

O risco combinatório também é real. Dez flags booleanas independentes geram 1.024 configurações possíveis, e você nunca vai testar todas. Mantenha poucas interações entre flags e separe flags de release de toggles operacionais de longa duração, como kill switches.

Estratégias de release sobre o trunk

Existem duas formas comuns de cortar um release a partir do trunk, e nenhuma exige branch de longa duração.

A escolha depende do seu tempo de detecção. Se você percebe um deploy ruim em cinco minutos e reverte em dois, corrija para frente. Se o seu tempo médio de detecção é de uma hora, uma branch de release lhe dá um lugar para se apoiar.

Pequenos desvios de trilho que se juntam em uma única linha férrea principal

Observabilidade é a outra metade do acordo

O trunk based development aumenta a frequência de deploy, e isso aumenta o número de momentos em que algo pode dar errado. O modelo só funciona se você conseguir enxergar uma regressão em minutos depois de um merge. Isso significa taxas de erro, percentis de latência e saturação ligados a um release específico, e não a um dashboard que alguém confere na segunda-feira.

Um teste útil: depois de um merge, você consegue responder "essa mudança alterou o p99 ou a taxa de erro?" sem abrir cinco abas? Se não, você não está pronto para fazer merge dez vezes por dia.

Qualquer que seja a stack, o requisito é o mesmo: marcadores de deploy nos gráficos, alertas de burn rate de SLO e um caminho de revert que uma pessoa cansada consiga executar às 3 da manhã sem pensar.

Meça as métricas DORA antes de começar, ou você vai discutir com base em sensação depois. A frequência de deploy e o lead time para mudanças reagem primeiro, porque lotes menores atravessam o pipeline mais rápido. A taxa de falha de mudanças e o tempo de restauração vêm depois, e dependem mais da observabilidade e do caminho de revert do que da estratégia de branches. Não transforme esses números em boletim individual. Eles descrevem um sistema. Quando o lead time sobe, olhe a fila de revisão e a duração do CI antes de olhar para as pessoas.

Trunk based development vs GitFlow vs GitHub Flow

Os três são confundidos com frequência, então separe-os por uma propriedade: quanto tempo o trabalho fica fora do branch compartilhado.

Se a sua equipe já usa GitHub Flow com branches que vivem menos de dois dias, você está mais perto do trunk do que imagina. A distância costuma estar na disciplina com flags e na latência da revisão, não nas ferramentas.

Quando é a escolha errada, e como começar

Não adote, ou pelo menos adie, em alguns casos. Seja honesto sobre em qual deles você está.

Também não existe garantia de resultado. A conclusão do DORA é uma correlação, vinda de dados de 2016 e 2017, com equipes que seguem essas práticas apresentando melhor desempenho de entrega e de operação. Ela não diz que renomear seus branches conserta o seu pipeline.

Para começar, não anuncie uma política. Meça primeiro e depois reduza.

  1. Registre o tempo de vida atual dos branches e o tamanho mediano dos pull requests. Essa é a sua linha de base.

  2. Defina um limite, por exemplo nenhum branch com mais de dois dias, e deixe-o visível em um dashboard.

  3. Conserte a parte mais lenta do CI. Se o build leva 30 minutos, nada mais importa ainda.

  4. Introduza uma flag para uma feature real. Entregue escondida. Remova a flag dentro de uma sprint.

  5. Remova os code freezes por último, quando o caminho de revert já tiver sido testado sob pressão.

Reavalie depois de um mês. A taxa de falha de mudanças demora mais para responder e, às vezes, piora antes de melhorar, porque você finalmente enxerga as quebras mais cedo.

O que o seu post-mortem diria? Essa é a pergunta útil antes de subir qualquer mudança. Se o seu último incidente teve origem em um merge que ninguém conseguiu revisar, em uma branch que divergiu por três semanas ou em um release que empacotou quarenta mudanças, você já sabe onde a dívida vence. Olhe para os últimos três incidentes. Quantos envolveram uma integração grande e tardia? Esse número é o seu argumento.

Perguntas frequentes

O que é trunk based development em uma frase?
É um modelo em que todos os desenvolvedores integram mudanças pequenas em um único branch, pelo menos uma vez por dia, mantendo esse branch sempre pronto para release.
Trunk based development é o mesmo que GitHub Flow?
Não exatamente. Os dois usam branches curtos, mas o trunk based development é mais rigoroso quanto ao tempo de vida dos branches e costuma depender de feature flags ou branch by abstraction para trabalho que não cabe em uma mudança pequena.
Quantos branches ativos o DORA recomenda?
O guia de capacidades do DORA indica três ou menos branches ativos no repositório, com merges no trunk pelo menos uma vez por dia.
Preciso de feature flags para adotar trunk based development?
Para trabalho que não pode ser entregue em uma única mudança pequena, sim. Flags ou branch by abstraction permitem integrar código incompleto sem expô-lo aos usuários.
Quando não vale a pena adotar trunk based development?
Quando a suíte de testes não pode ser paralelizada e leva horas, quando há artefatos versionados com clientes em versões antigas, quando não existe sistema de flags ou quando a equipe não confia no build.
Como começar sem uma migração grande?
Meça o tempo de vida atual dos branches, defina um limite visível, reduza o tempo do CI, introduza uma flag para uma feature real e só depois remova os code freezes.