Imagine duas equipes de desenvolvimento.
A primeira prepara uma nova versão da aplicação.
O desenvolvedor conclui a tarefa. Alguém revisa o código. Depois é preciso executar os testes. Alguém prepara o pacote. Outra pessoa faz login no servidor. Em seguida é necessário realizar algumas ações manuais, verificar a configuração e observar o sistema após a implantação. Se tudo correr bem, a nova versão fica disponível.
A segunda equipe trabalha de outra forma.
O código vai para o repositório. Testes, análise de qualidade e verificações de segurança são executados automaticamente. O sistema constrói a versão da aplicação, implanta-a no ambiente de teste, realiza novas verificações e, após o cumprimento de determinadas condições, pode implantá-la em produção. Se algo der errado, a implantação é interrompida ou o sistema pode voltar para a versão anterior.
As duas equipes criam software.
Mas apenas uma delas construiu um processo repetível de entrega de software.
E é exatamente disso que trata o CI/CD.
"Funciona em produção" ainda não é um processo maduro
Muitas empresas medem o sucesso por um critério muito simples: a aplicação funciona.
Claro, esse é um requisito básico.
Mas, à medida que o sistema cresce, surgem novas perguntas:
- Com que rapidez podemos implantar uma correção?
- Com que frequência podemos publicar novos recursos?
- Quantas ações manuais executamos em cada implantação?
- Todo desenvolvedor pode iniciar o processo de implantação seguindo as mesmas regras?
- Sabemos qual versão está em execução agora?
- Conseguimos voltar para a versão anterior?
- Depois da implantação, verificamos automaticamente se o sistema está funcionando corretamente?
- Temos monitoramento?
- Sabemos que a implantação causou um problema antes que o cliente o reporte?
Essas são perguntas sobre software delivery, e não apenas sobre programação em si.
CI e CD - dois elementos de um único processo
CI, ou Continuous Integration, significa integração contínua das mudanças.
Na prática, trata-se de fazer com que as mudanças cheguem frequentemente ao repositório comum e sejam verificadas automaticamente.
Um pipeline típico pode executar, entre outras coisas:
-
compilação ou build da aplicação,
-
testes unitários,
-
testes de integração,
-
linting,
-
análise estática de código,
-
verificação de dependências,
-
verificações de segurança,
-
build de artefatos de implantação.
Assim, um problema pode ser detectado antes que o código chegue à produção.
CD, ou Continuous Delivery ou Continuous Deployment, diz respeito à próxima etapa - a entrega das mudanças.
Dependendo do modelo adotado, o sistema pode preparar uma versão pronta para implantação ou implantá-la automaticamente após passar por determinadas verificações.
Essa é uma distinção importante.
Continuous Delivery não precisa significar a implantação automática de cada mudança em produção.
Pode significar simplesmente que cada versão é preparada de forma repetível para ser implantada.
Por que implantações manuais se tornam um problema?
Uma implantação manual não precisa ser ruim.
Em um projeto pequeno, ela pode ser totalmente suficiente.
O problema começa quando o processo cresce junto com a aplicação.
Primeiro temos uma pessoa que sabe como implantar o sistema. Depois vem um segundo servidor. Mais tarde, o ambiente de teste. Depois, banco de dados, cache, filas, storage, vários serviços e APIs externas. Além disso, surgem diferentes configurações para desenvolvimento, testes e produção.
Depois de alguns anos, o processo pode parecer mais ou menos assim:
"Primeiro execute X, depois altere o parâmetro Y, em seguida reinicie o serviço Z, mas antes faça um backup do banco. E se aparecer um erro, ligue para a pessoa que fez a última implantação."
Isso já não é um processo. Isso é conhecimento escondido na cabeça de uma pessoa. E é justamente aí que o risco aumenta.
Automatização não serve apenas para a conveniência dos desenvolvedores
Muitas vezes o CI/CD é apresentado como uma ferramenta para aumentar o conforto dos developers. Isso é verdade, mas é apenas parte do quadro.
A automação da entrega aumenta прежде de tudo a repetibilidade do processo.
Se a implantação é feita por uma pessoa, existe a possibilidade de que a cada vez ela faça algo um pouco diferente.
Se é o pipeline que faz isso, é possível definir uma sequência exata de etapas.
A mesma versão.
Os mesmos testes.
As mesmas verificações.
As mesmas regras.
Isso é especialmente importante em projetos desenvolvidos por várias pessoas ou várias equipes.
Os testes antes da implantação são mais importantes do que a velocidade da implantação
Automatização sem testes pode apenas fazer com que os erros apareçam mais rápido.
Por isso, um pipeline bem projetado não deve ser apenas um mecanismo: "código → produção".
Ele deve ser um sistema de controle de qualidade.
Dependendo do projeto, ele pode incluir:
- Testes unitários - verificando elementos individuais da lógica.
- Testes de integração - verificando a interação entre componentes.
- Testes end-to-end - simulando cenários reais de usuário.
- Testes de segurança - verificando, entre outras coisas, dependências e vulnerabilidades conhecidas.
- Testes de desempenho - necessários onde é importante suportar uma determinada carga.
Nem toda aplicação precisa de todas essas camadas na mesma medida.
E isso é importante.
CI/CD não consiste em colocar o maior número possível de ferramentas no pipeline.
Trata-se de escolher os controles adequados ao risco de um sistema específico.
O que acontece quando um teste falha?
Essa é uma das perguntas mais importantes de todo o processo.
Um pipeline maduro deve ter regras claramente definidas.
Se um teste crítico falha, a versão não deve ser considerada pronta para implantação.
Se uma análise de segurança detecta um determinado nível de risco, o pipeline pode interromper o processo.
Se o build falha, não há nada para implantar.
Isso parece banal. Mas são exatamente esses "portões" automáticos que fazem com que a qualidade não dependa apenas da memória e da precisão humana.
E se a implantação mesmo assim falhar?
Mesmo o melhor processo não elimina todos os erros. Por isso, o segundo elemento de uma entrega madura é a possibilidade de reverter a mudança de forma controlada.
Rollback pode significar voltar para o artefato anterior, a imagem do contêiner ou a versão da aplicação. Mas aqui surge um problema importante. Rollback de código nem sempre significa rollback de dados.
Se a nova versão alterou a estrutura do banco de dados, a situação se torna mais complicada.
Por isso, as migrações de base de dados devem ser concebidas de forma a que todo o processo seja o mais seguro e reversível possível, ou pelo menos compatível com a versão anterior da aplicação.
Este é um dos exemplos que mostram que o CI/CD profissional é um problema arquitetural, e não apenas uma configuração de ferramenta.
Blue-green, canary e outras estratégias de implementação
Em sistemas mais exigentes, não é necessário mudar logo todos os utilizadores para a nova versão. Podem ser aplicadas diferentes estratégias de deployment.
Blue-green deployment
Duas versões do ambiente funcionam ao mesmo tempo.
Uma trata o tráfego, a outra é preparada para assumir o tráfego.
Após uma verificação positiva, ocorre a mudança.
A vantagem é a possibilidade de regressar rapidamente ao ambiente anterior.
A desvantagem pode ser um maior consumo de infraestrutura.
Canary deployment
A nova versão é primeiro disponibilizada a uma pequena parte dos utilizadores ou do tráfego.
Se a monitorização não indicar problemas, o âmbito da implementação pode ser gradualmente aumentado.
Isto limita o potencial alcance do erro.
No entanto, exige a infraestrutura adequada, monitorização e uma forma de gerir o tráfego.
Feature flags
Uma funcionalidade pode ser implementada no sistema, mas permanecer desativada para os utilizadores.
Desta forma, a implementação do código e a ativação da funcionalidade tornam-se dois processos separados.
Isto dá mais controlo, especialmente em mudanças grandes.
No entanto, isso não significa que as feature flags sejam uma solução para todos os projetos. O seu excesso também pode aumentar a complexidade do sistema.
Monitorização após o deployment
Podem ser realizados todos os testes. Pode haver um pipeline excelente. Pode ser implementada uma nova versão sem qualquer erro. E alguns minutos depois a aplicação pode começar a comportar-se de forma diferente sob carga real.
Por isso, o processo não deve terminar no deployment. É necessária observability, ou seja, a capacidade de compreender o que acontece no interior do sistema em funcionamento.
Dependendo da arquitetura, isto inclui, entre outros:
-
logs,
-
métricas,
-
tracing,
-
monitorização da infraestrutura,
-
monitorização da aplicação,
-
alertas,
-
informações sobre erros,
-
indicadores de negócio.
Não se trata de recolher tudo. Trata-se de conseguir responder a perguntas importantes com base em dados.
A aplicação está a funcionar?
Está a funcionar mais devagar do que antes?
O número de erros aumentou?
Que serviço está a causar o problema?
O problema afeta todos os utilizadores ou apenas uma parte?
100 implementações por dia nem sempre é o objetivo
O título deste artigo fala de 100 implementações por dia, mas não se trata de estabelecer esse número como objetivo.
Num sistema interno atualizado uma vez por mês, não faz sentido procurar artificialmente chegar a centenas de deployments. Num sistema desenvolvido muito intensamente, essa frequência pode, no entanto, ser tecnicamente possível.
O que é fundamental é a capacidade de entregar alterações com segurança, e não o número de implementações. Esta é uma diferença fundamental.
A maturidade do processo mede-se não pela frequência das implementações, mas por quão previsivelmente e com quão segurança conseguimos fazê-lo.
Quando é que CI/CD pode ser excesso de forma sobre conteúdo?
Nem toda a aplicação precisa de uma infraestrutura de deployment complexa.
Se tivermos uma pequena aplicação, uma equipa reduzida e algumas implementações por ano, um pipeline elaborado pode custar mais do que os problemas que resolve.
O mesmo se aplica a sistemas muito específicos, em que a implementação exige controlo manual por razões de segurança, regulamentação ou pela natureza da infraestrutura.
Por isso, a arquitetura de delivery deve resultar das necessidades do sistema. Não da moda.
Quando é que a automatização de implementações traz especialmente muito valor?
Vale a pena considerá-la sobretudo quando:
-
o sistema é desenvolvido regularmente,
-
várias pessoas trabalham no código,
-
existe mais do que um ambiente,
-
as implementações são frequentes,
-
as implementações manuais geram erros,
-
o sistema é crítico para o negócio,
-
precisamos de rollback rápido,
-
a aplicação tem muitos componentes,
-
são necessárias auditorias ou rastreio de alterações,
-
o tempo de entrega da funcionalidade tem importância para o negócio.
Nesses casos, um pipeline bem concebido pode ser um dos elementos mais importantes do processo de desenvolvimento de software.
CI/CD não corrige uma má arquitetura
Isto também vale a pena sublinhar.
É possível criar um excelente pipeline para uma má aplicação.
Testar automaticamente código mau.
Implementar automaticamente uma má arquitetura.
Escalar automaticamente um sistema mal concebido.
A automatização não substitui, portanto, a arquitetura, os testes nem a competência da equipa.
Ela reforça o processo existente.
Se o processo for bom, ajuda a escalá-lo.
Se o processo for mau, pode simplesmente executar coisas más mais depressa.
Como é um processo maduro?
Não existe um pipeline universal.
Mas um processo maduro deve ter várias características básicas.
Repetibilidade - a implementação é executada segundo passos definidos.
Automatização - as máquinas executam a maior parte possível do trabalho repetitivo.
Testabilidade - as alterações são verificadas automaticamente.
Segurança - o processo inclui controlos de segurança adequados.
Observabilidade - após a implementação, sabe-se o que está a acontecer com o sistema.
Reversibilidade - existe uma forma planeada de reagir a uma alteração sem sucesso.
Rastreio de alterações - sabe-se que versão foi implementada e de onde surgiu.
Controlo de acesso - nem todos podem implementar livremente tudo em produção.
É precisamente a partir destes elementos que nasce um processo profissional de software delivery.
A mudança mais importante começa com uma pergunta diferente
As empresas perguntam frequentemente: "Quão rapidamente conseguimos criar esta funcionalidade?"
Vale a pena acrescentar uma segunda pergunta: "Quão rapidamente e com quanta segurança conseguiremos entregar as próximas 50 funcionalidades?"
Porque uma única implementação pode ser feita manualmente. Pode até ser possível implementar manualmente uma aplicação durante vários anos. Mas à medida que o produto, a equipa, o número de utilizadores e o número de alterações crescem, também aumenta o custo dessa abordagem.
Por isso, CI/CD, testes automáticos, monitorização e deployments controlados não são apenas soluções para grandes corporações.
São elementos da infraestrutura do processo que permitem desenvolver software sem acrescentar risco desnecessário a cada alteração seguinte.
E, no fim de contas, é exatamente disso que se trata.
Não de 100 implementações por dia.
Não de ferramentas da moda.
Não sobre o pipeline mais complicado.
Apenas sobre poder dizer:
"Temos uma mudança. Nós a revisamos. Sabemos o que vamos implantar. Sabemos como observá-la. E sabemos o que faremos se algo der errado."
