Continuous-Integration

O que é deploy?

Em termos gerais, deploy significa colocar em posição. Na prática, geralmente falamos de disponibilizar um sistema para uso, seja num ambiente de desenvolvimento, para testes ou em produção.

O termo deploy pode significar muitas coisas, dependendo do ambiente e da tecnologia. Um desenvolvedor pode fazer o deploy da aplicação web no seu Tomcat local. Pode também fazer o deploy no Weblogic em produção, usado pelos usuários finais.

Nível de automação

O deploy pode ser “manual”, parcialmente automatizado ou completamente automatizado.

O processo manual pode consistir em exportar um WAR no Eclipse, acessar a página de administração do Tomcat e fazer o upload do WAR.

Um processo automatizado pode consistir em comitar o código no repositório, sendo que esta ação dispara automaticamente o processo de construção (build) do “executável” da aplicação e possivelmente sua disponibilização em um servidor.

Personalização

Embora o ciclo de vida de uma aplicação possa estar 100% automatizado, não significa que um commit qualquer vai acabar em produção. O importante é que todos os passos mais trabalhosos estejam automatizados, disponíveis a um comando do desenvolvedor ou responsável.

Desenvolvedores e administradores devem configurar todo esse ambiente da forma que seja mais adequada ao projeto, minimizando retrabalho, tarefas repetitivas e erro humano em todo o ciclo de vida de uma aplicação, que vai desde a especificação até a aceitação do usuário final.

Por exemplo, nem sempre faz sentido um código comitado gerar uma versão do sistema em produção. Então vários critérios podem ser adotados para que novas funcionalidades implementadas sejam devidamente entregues ao usuário final. A principal estratégia aqui é o uso correto de ramificações (branches) de desenvolvimento.

Integração Contínua (CI – Continuous Integration)

Toda essa automatização não visa apenas evitar trabalho repetitivo. Ela na verdade permite aos desenvolvedores alcançaram um nível muito maior de produtividade e qualidade.

Um problema recorrente no desenvolvimento de software é que os erros ocultos nos programas que desenvolvemos são cada vez mais caros e difíceis de corrigir na medida em que o tempo passa.

Qualquer pessoa que trabalha com programação já deve ter passado pela situação de achar que um programa estava quase pronto e “só faltava testar”, para então descobrir que, na verdade, muito coisa ainda estava errada ou mesmo faltando no código.

Outra situação recorrente é a “preguiça” de testar o software, ou pelo menos a prática de postergar os testes. Sem testes e deploy automatizados, o desenvolvedor tende a escrever uma grande quantidade de código antes de realmente colocar o programa para executar, afinal se o processo é trabalhoso e toma muito tempo, ele vai evitar de fazer isso ao máximo. Só que no final gasta-se muito tempo para corrigir todos os “detalhes” que não estavam corretos.

Para mitigar todos esses problemas, surgiu o conceito de Integração Contínua. A ideia é justamente automatizar o processo para que, com bastante frequência, uma ou mais vezes ao dia, seja possível integrar todas as alterações de todos os desenvolvedores envolvidos no projeto e realizar um teste geral.

Automação do ciclo de vida de uma aplicação

Fazer Integração Contínua nem sempre é uma tarefa simples e existem muitas formas de fazer isso.

Construção (Build)

O build é o processo que transforma seu código-fonte em um “executável”, como um Jar ou War em Java. É claro que você pode usar um script próprio executando o javac, mas existem ferramentas mais avançadas como Ant ou Maven.

Um dos métodos mais comuns de fazer isso em Java é a utilização de alguma ferramenta como o Maven. O Maven gerencia a construção (build) dos projetos através do uso de convenções e padrões. Por exemplo, os projetos que usam Maven geralmente seguem a seguinte estrutura de diretórios:

Estruturas de diretório do maven

Basicamente, você coloca os códigos-fonte da aplicação em src/main/java e os testes automatizados em src/test/java.

O Maven também define uma série de fases da construção do projeto. Veja a imagem abaixo:

Fases de construção do projeto

Vamos analisar as fases principais:

  • Compile: faz a compilação do código dos diretórios src/*/java.
  • Test: executa os testes encontrados no diretório src/test/java
  • Package: empacota as classes e outros arquivos em um JAR ou WAR, por exemplo.

Há também uma fase de deploy que pode ser configurada para disponibilizar o “executável” gerado em um servidor. No entanto, cada tipo de servidor precisa de um plugin diferente do Maven.

Enfim, seguindo os padrões definidos, que podem também ser personalizados, o Maven permite automatizar todo o processo de build ou construção do projeto. Há também uma fase

Se quiser saber mais sobre o Maven, sugiro a leitura do artigo:

Instalando, configurando e usando o Maven para gerenciar suas dependências e seus projetos Java

Gerenciando em alto nível

Construir o projeto é o passo mais importante, mas a Integração Contínua precisa levar em conta todo o ambiente da empresa. Afinal, nem sempre o desenvolvedor pode ou deve ter acesso direto para fazer o deploy de sua máquina local.

Nesses casos, o ambiente de desenvolvimento de uma empresa pode dividir o trabalho entre diversos servidores contendo serviços especializados. Aqui entram aplicações omo o Jenkins para “colocar ordem na bagunça”.

Considere a ilustração abaixo:

Integração Contínua com Jenkins

Em resumo, os passos ilustrados são:

  1. Check in: é quando o desenvolvedor faz o commit ou merge do código na branch configurada para releases do projeto no sistema de versionamento (VCS – Version Control System). A branch principal geralmente é chamada de HEAD no CVS, Trunk no SVN e master no Git, mas pode ser qualquer outra arbitrariamente definida.

  2. A alteração no seu VCS dispara então um processo no seu Servidor de Integração Contínua (CI Server), que pode ser o próprio Jenkins. O servidor irá disparar o build do projeto nos servidores de build (build servers).

  3. Se o projeto usa Maven, por exemplo, o build server irá então compilar, testar e empacotar o projeto usando essa ferramenta. Primeiro ele recupera o código-fonte (check out) do VCS e depois, por exemplo, executa o comando mvn package.

  4. Após o término do build o CI Server (nosso Jenkins) recupera o relatório da compilação e dos testes e verifica se tudo ocorreu bem.

  5. O CI Server atualiza então o status do projeto.

  6. O CI Server, de acordo com a configuração, notifica os interessados no resultado do processo.

Dentro do processo acima, opcionalmente, poderia haver um passo para fazer o deploy da aplicação em um servidor. Uma forma seria através do próprio build do Maven. Outra seria configurar o Jenkins para executar o deploy após o build (passo #4).

No entanto, considero mais interessante a abordagem de promover determinados builds concluídos com sucesso de forma manual. O processo ainda seria todo automatizado, mas ao final o responsável pelo projeto pode selecionar um determinado build que acabou de sair de desenvolvimento e, com um clique, promovê-lo para o ambiente de testes ou mesmo para produção.


Este artigo foi baseado na minha resposta no Stack Overflow em Português.