Pipelines de CI/CD: Os Princípios Que Sustentam Entregas Confiáveis
Integração e entrega contínuas não são sobre ferramentas, e sim sobre princípios: build único, testes em pirâmide, fast feedback, artefato imutável e promoção.
Neste artigo
Toda empresa de software diz que tem CI/CD. Poucas têm de verdade. Ter um arquivo de pipeline no repositório que roda alguns testes e faz um deploy não é a mesma coisa que praticar integração e entrega contínuas. A diferença está nos princípios, não nas ferramentas. Você pode montar um CI/CD excelente com qualquer runner moderno, e pode montar um CI/CD medíocre com o mais caro deles. A ferramenta executa; os princípios é que decidem se o resultado é confiável.
Este artigo trata desses princípios, que são notavelmente estáveis ao longo do tempo. As ferramentas mudam de nome a cada poucos anos, mas as ideias que fazem uma esteira de entrega ser rápida, confiável e reversível são as mesmas há mais de uma década. Entendê-las é o que permite avaliar qualquer pipeline, construir um bom do zero e corrigir um ruim.
Integração contínua não é rodar testes#
Comece desfazendo o mal-entendido mais comum. Integração contínua não significa "ter um servidor que roda testes". Significa uma prática de trabalho: cada desenvolvedor integra suas mudanças ao ramo principal com frequência, idealmente várias vezes ao dia, e cada integração é verificada automaticamente.
O inimigo que a CI combate é o merge tardio. Quando alguém trabalha isolado numa branch por duas semanas e só então tenta integrar, a fusão vira um pesadelo: o código divergiu tanto do principal que os conflitos são enormes e os bugs de integração aparecem todos de uma vez, no pior momento possível. A CI existe para tornar a integração pequena e frequente, de modo que cada fusão seja trivial e cada problema apareça cedo, quando ainda é barato de resolver.
Isso tem uma implicação cultural que nenhuma ferramenta resolve: o ramo principal precisa estar sempre em estado saudável. Se o build quebra, consertá-lo vira prioridade da equipe, porque um principal quebrado bloqueia todo mundo. A disciplina de manter o principal verde é o coração da integração contínua, e é comportamento humano, não configuração de YAML.
O build único: construa uma vez, promova o artefato#
Um dos princípios mais violados e mais importantes: construa o artefato uma única vez e promova o mesmo artefato por todos os ambientes.
O anti-padrão é reconstruir a aplicação em cada estágio: um build para testar, outro build para homologação, outro build para produção. O problema é que cada build pode produzir um artefato ligeiramente diferente, por causa de uma dependência que mudou de versão, de uma variável de ambiente distinta, de um cache diferente. Você testa uma coisa e coloca outra em produção. O que passou nos testes não é necessariamente o que rodou para o usuário.
A prática correta é construir uma vez, gerar um artefato imutável, tipicamente uma imagem de container com uma tag única, e promover exatamente esse artefato através dos ambientes. A imagem que passou nos testes é a mesma imagem que vai para homologação e a mesma que vai para produção. A configuração, essa sim, muda por ambiente e é injetada em tempo de execução, nunca embutida no artefato. Assim o que você validou é literalmente o que roda, byte por byte. Uma imagem enxuta e determinística é a base disso, e as práticas para produzi-la merecem cuidado próprio.
A pirâmide de testes: rápido embaixo, lento no topo#
Uma pipeline sem testes automatizados não é CI/CD, é deploy automatizado, o que é bem diferente e bem mais perigoso. Mas simplesmente ter muitos testes não basta; a forma como eles se distribuem determina se o feedback é rápido ou insuportavelmente lento.
O modelo de referência é a pirâmide de testes. Na base, larga, ficam os testes unitários: rápidos, isolados, aos milhares, verificando pequenas unidades de lógica em milissegundos. No meio ficam os testes de integração: em menor número, verificando que componentes conversam corretamente, tocando banco de dados, filas, APIs. No topo, estreito, ficam os testes de ponta a ponta: poucos, lentos, caros, exercitando o sistema inteiro do ponto de vista do usuário.
A geometria da pirâmide não é estética; é economia. Testes unitários dão o retorno mais rápido pelo menor custo, então você tem muitos. Testes de ponta a ponta são valiosos mas frágeis e lentos, então você tem poucos, cobrindo os fluxos críticos. Inverter a pirâmide, ter poucos testes unitários e muitos testes de ponta a ponta, produz uma suíte que demora horas, falha por motivos aleatórios e todo mundo aprende a ignorar. Uma suíte que ninguém confia é pior que suíte nenhuma, porque dá falsa segurança.
Fast feedback: falhe cedo, falhe barato#
O valor de um pipeline é diretamente proporcional à velocidade com que ele diz que algo deu errado. Um pipeline que leva quarenta minutos para reprovar uma mudança destrói o fluxo de trabalho: o desenvolvedor já mudou de tarefa, perdeu o contexto, e voltar custa caro. Um pipeline que reprova em três minutos mantém o problema fresco e a correção barata.
O princípio que operacionaliza isso é fail fast: coloque as verificações rápidas e mais prováveis de falhar no começo, e as lentas no fim. A ordem típica é lint e checagens de formato primeiro, porque são quase instantâneos; depois compilação e testes unitários; depois testes de integração; e só então os testes de ponta a ponta, mais lentos. Se o lint quebra, o pipeline para em segundos sem gastar minutos rodando testes que nem vão importar. Você paga o custo caro apenas quando o barato já passou.
Paralelizar também ajuda, rodando estágios independentes ao mesmo tempo. Mas a ordenação por custo e probabilidade de falha vem antes: não adianta paralelizar bem uma ordem ruim. O objetivo é sempre o mesmo, encurtar o tempo entre cometer um erro e descobrir que o cometeu.
Entrega contínua versus implantação contínua#
Dois termos que compartilham a sigla CD e significam coisas diferentes, e confundi-los gera discussões inúteis.
Entrega contínua (continuous delivery) significa que todo artefato que passa no pipeline está pronto para produção a qualquer momento, mas o passo final, colocar de fato em produção, é acionado por decisão humana. Você tem confiança de que pode implantar quando quiser, com um clique, mas escolhe quando.
Implantação contínua (continuous deployment) vai um passo além: toda mudança que passa em todo o pipeline vai automaticamente para produção, sem intervenção humana. Não há botão; passou, subiu.
Nenhuma das duas é universalmente superior. A implantação contínua exige uma maturidade enorme de testes, observabilidade e capacidade de reverter, porque não há um humano no caminho para pegar o que os testes deixaram passar. Muitas equipes maduras escolhem deliberadamente a entrega contínua para produtos onde uma implantação errada tem custo alto, mantendo o gatilho humano como último ponto de controle. O importante é que a decisão seja consciente, e não resultado de um pipeline que ninguém confia o suficiente para automatizar.
Segurança e qualidade dentro do pipeline#
Um pipeline moderno não valida apenas funcionalidade; ele é o lugar natural para embutir verificações de segurança e qualidade que, feitas cedo, custam pouco.
Vale rodar análise estática de código para pegar bugs e vulnerabilidades sem executar nada. Vale escanear dependências em busca de vulnerabilidades conhecidas, porque a maior parte do código que você entrega não foi você que escreveu. Vale escanear as imagens de container em busca de pacotes vulneráveis na base. E vale, acima de tudo, nunca colocar segredos no pipeline em texto plano: chaves e tokens vêm de um gerenciador de segredos, injetados no momento do uso, nunca commitados no repositório nem impressos em log, onde ficariam para sempre.
O princípio geral é o shift left: mover as verificações para o mais cedo possível no ciclo. Um problema de segurança encontrado na análise estática custa minutos; o mesmo problema encontrado em produção custa um incidente. O pipeline é a barreira onde esses problemas devem morrer, de forma automática e consistente, sem depender de alguém lembrar de checar.
Trunk-based, feature flags e o desacoplamento entre deploy e release#
Há uma tensão aparente no coração da integração contínua: se todo mundo integra ao principal várias vezes ao dia, como lidar com funcionalidades que ainda não estão prontas para os usuários? Colocar código pela metade no principal parece perigoso. A resposta madura resolve isso separando dois conceitos que costumam ser tratados como um só.
Deploy é colocar o código no ambiente de produção. Release é tornar uma funcionalidade visível e ativa para os usuários. Parecem a mesma coisa, mas desacoplá-los muda tudo. Com feature flags, interruptores que ligam e desligam funcionalidades sem novo deploy, você pode fazer deploy de código incompleto ou novo com a flag desligada: o código está em produção, exercitado, mas invisível ao usuário. Quando estiver pronto, você liga a flag e faz o release, sem tocar no deploy. E se algo der errado, desliga a flag, revertendo a funcionalidade sem reverter o deploy.
Isso viabiliza o trunk-based development, a prática de integrar tudo num único ramo principal com branches de vida curtíssima, que é o casamento natural da integração contínua. Em vez de branches de funcionalidade que vivem semanas e divergem perigosamente, o trabalho vai para o principal em pequenos incrementos frequentes, protegido por flags quando ainda não está pronto para os olhos do usuário. O merge doloroso desaparece porque não há divergência acumulada, e a funcionalidade é revelada por uma decisão de release, não por uma fusão de branch. É a diferença entre integrar continuamente de verdade e apenas dizer que se faz CI.
O pipeline como fonte da verdade#
Reunindo os princípios: integre com frequência mantendo o principal verde; construa o artefato uma vez e promova o mesmo por todos os ambientes; estruture os testes em pirâmide para feedback rápido; falhe cedo e barato; escolha conscientemente entre entrega e implantação contínua; e embuta segurança desde o começo. Nenhum desses princípios depende de uma ferramenta específica, e todos sobrevivem à próxima moda de tooling.
Há uma evolução natural desses princípios que vale conhecer. Quando o estado desejado da infraestrutura e das aplicações passa a viver inteiramente em um repositório Git, e um agente reconcilia o ambiente com esse repositório de forma automática, o pipeline ganha uma propriedade nova de auditabilidade e reversibilidade. Essa é a promessa do GitOps como modelo de entrega, que leva o princípio do artefato imutável e da fonte única da verdade às últimas consequências. Mas mesmo sem chegar lá, uma equipe que internaliza os princípios deste artigo já entrega com uma confiança que ferramenta nenhuma, sozinha, é capaz de dar.