Você está na página 1de 12

PRÁTICAS ÁGEIS

INTEGRAÇÃO CONTÍNUA

O texto abaixo é a uma tradução autorizada do artigo escrito pelo Martin Fowler. Para acessar a versão
original em inglês, clique aqui . Caso você tenha sujestões para tornar a tradução melhor, compartilhe
através da seção de comentários no final da página.

The text bellow is an authorized translation of the article written by Martin Fowler. To access the original
english version, click here . If you have any sujestion to make the translation better, share it via comments
section at the end of the page.

Construindo um componente usando Integração Continua

Para mim, a forma mais fácil de explicar o que Integração Contínua (IC) é e como trabalha é mostrando um
pequeno exemplo de como isso funciona com o desenvolvimento de uma pequena parte do sistema. Vamos
assumir que eu tenho que fazer alguma coisa para uma parte do sistema, não importa realmente que tarefa é
- por enquanto vou supor que isso é pequeno e que pode ser feito um poucas horas ( vamos explorar tarefas
maiores e outros problemas mais tarde ). Começo pegando uma cópia atual do código fonte e colocando na
minha máquina de desenvolvimento. Faço isso utilizando um sistema de controle de código para ter uma
cópia de trabalho a partir do código principal.

O parágrafo acima irá fazer sentido para pessoas que usam sistema de controle de código, mas não será
para aqueles que não usam. Então deixe-me explicar rapidamente: um sistema de controle de código
mantém todo o código fonte de um projeto em um repositório. O estado atual do sistema geralmente é
chamado de mainline( ou linha principal). Em qualquer momento um desenvolvedor pode fazer uma cópia
da versão principal em sua máquina, e isso é chamado de check out. A cópia em uma máquina de um
desenvolvedor é chamada de cópia de trabalho (na maior parte de tempo você estará atualizando sua cópia
de trabalho junto a principal).

Agora eu pego minha cópia de trabalho e faço o que preciso para completar minha tarefa. Isso irá consistir
em alterar o código de produção e também adicionar ou alterar os testes automatizados. Integração
Contínua assume um alto nível de testes que são automatizados no software: uma facilidade que eu chamo
de self-testing code ( ou código auto-testável). Frequentemente estes usam uma versão da popular
framework de teste xUnit.

Um vez que eu terminei (e isso geralmente acontece em vários lugares quando eu estou trabalhando), eu
faço uma build (ou desenvolvimento de uma versão) automatizada na minha máquina de desenvolvimento.
Assim, o código fonte em minha cópia de trabalho é pego, compilado e transformado em um executável - e
então é executado os testes automáticos. Somente se todas as builds e testes não tiverem erros que tudo será
considerado bom.

Com uma boa build, eu posso então pensar em colocar minhas alterações no repositório. A questão é, claro,
que outras pessoas podem fazer (e geralmente fazem) mudanças na versão principal antes de eu ter a
chance de fazer um commit ( ou atualizar o repositório principal com a minha versão do código). Sendo
assim, primeiro eu atualizo minha cópia de trabalho com as mudanças feitas pelos outros e crio uma nova
build. Se as mudanças deles chocarem com as minhas mudanças, será exibido erros tanto na compilação
quanto nos testes. Neste caso é minha a responsabilidade de corrigir estes erros e repetir o processo até que
minha cópia local esteja sincronizada com a versão principal.

Uma vez que tenho as alterações na minha própria build de uma cópia devidamente sincronizada eu posso
finalmente fazer o commit na versão principal, que atualiza o repositório. Entretanto meu commit não
termina meu trabalho. Nós fazemos uma build novamente, mas agora em uma maquina de integração
baseada na versão principal do código. Somente com o sucesso desta build poderemos dizer que as minhas
alterações foram feitas. Sempre existe uma chance de eu ter esquecido alguma coisa na minha máquina e o
repositório não ser atualizado corretamente. Somente quando minha build de alterações for lançada com
sucesso na máquina de integração é que o meu trabalho terminou. A build de integração pode ser executada
manualmente por mim ou ser feita automaticamente usando o Cruise.

Se um choque ocorrer entre as versões de dois desenvolvedores, isso geralmente é pego quando o segundo
desenvolvedor atualizar sua cópia local com as builds feitas pelos outros. Caso não, a build de integração
deve falhar. De qualquer modo o erro é detectado rapidamente. Nesse momento a tarefa mais importante é
consertar os problemas, e fazer sua build voltar a funcionar corretamente. Em um ambiente de Integração
Contínua você nunca deve ter uma build de integração com falhas por muito tempo. Um bom time deve ter
muitas builds corretas por dia. Más builds podem ocorrer de tempos em tempos, mas devem ser
consertadas rapidamente.

Práticas da Integração Contínua

A história anterior é uma apresentação da Integração Contínua e de como ela funciona diariamente.
Colocar isso tudo pra funcionar sem problemas envolve obviamente mais coisas do que foi dito. Eu vou
focar agora em práticas chaves que efetivarão a IC .

Manter um único repositório de código.

Projetos de softwares envolvem vários arquivos que precisam serem "orquestrados" juntos para se construir
um produto. Manter todos esse arquivos exige um grande esforço, particularmente quando existem várias
pessoas envolvidas. Logo não é surpresa que através de anos equipes de desenvolvimento tem construído
ferramentas para gerenciar tudo isso. Estas ferramentas - chamadas de ferramentas de gerenciamento de
código fonte, gerenciamento de configuração, sistema de controle de versão, repositórios ou outros nomes -
são uma parte integrante na maioria dos projetos de desenvolvimento. A triste e surpreendente questão é
que essas ferramentas não fazem parte de todos os projetos. Isto é raro, mas eu participo de projetos que
não usam algo como um sistema mas usam um combinação confusa de drivers locais e compartilhados.

Portanto, como um passo fundamental, tenha certeza de usar um sistema decente de controle de código
fonte. Custo não é um problema por causa da boa qualidade das ferramentas open-source disponíveis. O
repositório open-source atual que escolho é o Subversion ( o antigo CVS continua sendo usado largamente,
e ainda é bem melhor que nada, mas o Subversion é uma escolha moderna). É interessante como eu
converso com desenvolvedores e descubro que a maioria dos gerenciadores de código fonte comerciais são
menos aceitos que o Subversion. A única ferramenta que eu tenho ouvido pessoas falarem que é digna de
ser paga é o Perforce.

Uma vez que você tenha um sistema de gerenciamento de código fonte, tenha certeza de que isso esteja em
um lugar conhecido por todos, para pagarem o código fonte. Ninguém deve sequer perguntar "Onde estão
os arquivos?". Tudo deve estar no repositório.

Embora muitos times usem repositórios, um erro comum que vejo é que eles não colocam tudo no
repositório. Se as pessoas usam um repositório, eles vão por o código lá, mas tudo que você precisa para
fazer uma build deve estar incluído la: scripts de teste, arquivos de configuração, esquema de banco de
dados, scripts de instalação e bibliotecas de terceiros. Eu conheci projetos que colocavam seus
compiladores no repositório (importante nos dias antigos de vários compiladores de C++). O regra básica é
que você consiga por o projeto em uma máquina virgem, fazer um checkout (ou pegar uma cópia de todo o
código) e conseguir rodar o sistema completamente. Somente poucas coisas devem ser feitas na máquina
virgem - geralmente coisas que são estáveis, grandes e complicadas de instalar . Um sistema operacional,
ambiente de desenvolvimento Java ou sistema básico de banco de dados são exemplos típicos.
Você precisa por tudo que a build precisa no sistema de controle de código, entretanto você pode por
também outros materiais com que as pessoas geralmente trabalham. Configurações de IDE são boas para
colocar lá porque este é um modo fácil para as pessoas compartilharem as mesmas configurações.

Outra característica dos sistemas de controle de versão é que eles permitem você criar múltiplos branches
(ou linhas de desenvolvimento) , para manipular diferentes fluxos de desenvolvimento. Isso é uma
característica útil, quer dizer essencial - mas frequentemente é usada de maneira abusiva o que coloca as
pessoas em problemas. Reserve-se a usar os branches ao mínimo. Tenha uma versão principal: um único
branch do projeto atualmente em desenvolvimento. Basicamente todos devem trabalhar fora desta linha
principal a maior parte do tempo ( um número considerável de branches são correção de bugs de uma
versão futura e experimentos temporários).

Geralmente você deve guardar no controle de código tudo que você precisa para executar tudo, mas nada
do que você já executou. Algumas pessoas guardam os produtos das builds no controle de código, mas eu
considero que isso é um sinal, uma indicação de um problema mais profundo, geralmente uma
incapacidade para recriar as builds confiantemente.

Automatize a Build

Frequentemente pegar os fontes e transformá-los em um sistema rodando é um processo complicado


envolvendo compilação, movimentação de arquivos, carregar schemas nas bases de dados e por ai vai.
Entretanto, boa parte das tarefas nesta parte do desenvolvimento de software pode ser automatizada - e
portanto deve ser automatizada. Pedir pessoas para digitarem comandos estranhos ou clicar em caixas de
dialogo é uma perda de tempo e uma forma suscetível a reprodução de erros.

Ambientes automatizados de builds são características comuns de sistemas. O mundo Unix tem feito isso
há décadas, a comunidade Java desenvolveu o Ant, a comunidade .NET desenvolveu o Nant e agora tem o
MSBuild. Esteja certo de que você pode gerar e lançar o seu sistema rodando os scripts em um único
comando. Um erro comum é não colocar tudo na build automatizada. A build deve incluir pegar o schema
do banco de dados do repositório e colocá-lo no ambiente de execução. Eu vou elaborar minha regra
anterior: qualquer um deve ser capaz de ir para uma máquina virgem, pegar as fontes do repositório, emitir
um único comando e ter um sistema rodando na sua máquina.

Scripts de build podem ter varias formas e frequentemente são particulares a uma plataforma ou
comunidade, mas eles não necessariamente ter que ser assim. Embora a maioria dos nossos projetos são em
Java e usam o Ant, alguns tem usando Ruby ( o sistema Ruby Rake é um script build muito bom). Nós
tivemos bons resultados automatizando um projeto anterior usando Microsoft COM com o Ant.

Dependendo do que você precisa, você pode querer que diferentes tipos de coisas estejam na build. Você
lançar um sistema com ou sem código de teste, ou com diferentes conjuntos de testes. Alguns componentes
podem ser construídos isoladamente. Um script de build deve permitir você usar métodos alternativos em
casos diferentes.
Muitos de nós usamos IDEs, e a maioria das IDEs tem algum tipo de processo de gerenciamento de build
dentro delas. Entretanto esses arquivos são sempre proprietários a IDE e frequentemente frágeis. Além
disso eles necessitam da IDE para funcionar. Não existe problema se os usuários da IDE configurarem seus
próprios arquivos de projetos e usarem para o desenvolvimento individual. Entretanto é essencial ter uma
build principal que é usável em um servidor e executável a partir de outros scripts. Logo, em um projeto
Java nós estamos livres para ter desenvolvedores fazendo a build em seus IDEs, mas a build principal deve
usar o Ant para assegurar que isso possa rodar um servidor de desenvolvimento.

Faça sua Build ser auto-testável

Tradicionalmente uma build significa compilação, linkagem e todo o material adicional necessário para ter
um programa executando. Um programa pode rodar, mas isso não significa que foi feito da maneira certa.
Linguagens modernas estaticamente tipadas podem achar muitos bugs, mas alguma coisa pode acabar
passando desapercebida. Um bom modo para pegar erros mais rápida e eficientemente é incluir testes
automáticos no processo de build. Testes não são perfeitos (claro), mas eles podem pegar muitos bugs - o
suficiente para ser útil.

Leitores regulares do meu trabalho irão notar que sou um grande fã de TDD e XP, entretanto eu quero
ressaltar que nenhuma dessas abordagens são necessárias para ganhar os benefícios de um código auto-
testável. Ambas as abordagens acertam que se escreva testes antes que você escreva o código, para então
fazer os testes passarem - desta forma os testes exploram muito mais o design do sistema do que capturam
erros. Isto é uma coisa boa, mas não é necessariamente do propósito da IC, onde nós temos requisitos mais
fracos de código auto-testável (embora TDD é minha maneira preferida de produzir código auto-testável).

Para ter o código auto-testável você necessitará de uma suite de testes automatizados que possa checar uma
grande parte da base do código para achar problemas. Os testes necessitam estar aptos para rodarem com
um simples comando e serem checados automaticamente. O resultado da suite dos testes em execução deve
indicar se estes falharam. Para uma build ser auto-testável a falha de um teste deve fazer com que a build
falhe.
Através dos últimos anos em que o TDD tem crescido, ele popularizou a família de ferramentas open-
source xUnit que são ideais para esse tipo de teste. As ferramentas xUnit tem sido muito valorosa para nós
na ThoughtWorks e eu sempre sugiro as pessoas que as usem. Estas ferramentas, que teve Kent Beck como
pioneiro, tornam fácil para você configurar um ambiente completo para testes automatizados.

Ferramentas xUnit são certamente o ponto inicial para tornar seu código auto-testável. Você deve também
procurar por outras ferramentas que focam em testes mais voltados ao software em funcionamento.
Atualmente, existem um grande número delas, incluindo FIT, Selenium, Sahi, Watir, FITnesse e muitas
outras que eu não vou listar aqui.

Cada um lança suas modificações todos os dias.

Integração antes de tudo trata sobre comunicação. Integração permite os desenvolvedores dizerem uns aos
outros sobre as alterações que eles fizeram. Frequentemente comunicação permite pessoas descobrirem
rapidamente como as alterações aconteceram.

O único pré-requisito para um desenvolvedor lançar suas alterações na versão principal é que ele ele
consiga executar perfeitamente o código. Isso claro, inclui passar pelos testes da build. Como com qualquer
ciclo de lançamento de código, o desenvolvedor primeiro atualiza sua cópia de trabalho para coincidir com
a versão principal, resolve qualquer conflito e então gera a build em sua máquina local. Se a build passar,
então ele estará liberado para lançar suas alterações na versão principal.

Fazendo isso frequentemente, os desenvolvedores irão encontrar rapidamente se existe algum conflito entre
as versões. O segredo para solucionar problemas rapidamente é encontrá-los rapidamente. Com
desenvolvedores lançando suas alterações a cada hora, um conflito pode ser detectado dentro de poucas
horas desde seu acontecimento, e em um ponto não muito avançado - o que o torna fácil de ser
solucionado. Conflitos que não são detectados por semanas podem ser difíceis de serem resolvidos.

O fato de que você gerou uma build quando você atualizou sua cópia de trabalho significa que você
detectou os problemas de compilação como também conflitos textuais. Desde que a build seja auto-
testável, você também detecta conflitos no código em execução. Os últimos conflitos são conflitos
particularmente incômodos de se encontrar se eles persistirem não detectados por um longo tempo em seu
código. Desde que existam apenas algumas horas de diferença entre os commits, existem apenas alguns
locais onde o problema pode estar se escondendo. Além disso, desde que muita coisa não tenha sido
mudada, você pode usar um diff-debugging para lhe ajudar a encontrar o problema.
Minha regra geral é que cada desenvolvedor deve atualizar o repositório todo dia. Na prática, geralmente é
útil os desenvolvedores lançarem suas atualizações com mais frequência que uma vez ao dia. Quanto mais
frequentemente você fizer um commit, menos lugares você terá que procurar por erros de conflito, e mais
rapidamente você os consertará.

Commits frequentes encorajam os desenvolvedores a quebrar seus trabalhos em pequenos pedaços de


poucas horas cada. Isso ajuda a dividir o progresso e causa um senso de progresso. Frequentemente as
pessoas começam sentir que não conseguem fazer alguma coisa significativa em poucas horas, mas nós
temos encontrado que esta teoria e prática ajudam os desenvolvedores a aprender.

Cada commit deve atualizar o repositório principal em uma máquina de integração

Usando commits diariamente, um time tem builds frequentemente testadas. Isso deveria significar que o
repositório principal esta em um estado saudável. Na prática, entretanto, coisas continuam dando errado.
Um razão é a disciplina: pessoas não estão atualizando suas versões e fazendo uma build antes de fazerem
seus commits. Outra é que existem diferenças de ambiente entre as máquina dos desenvolvedores. Como
uma possível solução você deve assegurar que as builds ocorram em uma máquina de integração e somente
se a build de integração passar com sucesso é que o commit deve ser considerado feito. Levando em
consideração que o desenvolvedor que realiza o commit deve ser responsável pelo mesmo, ele precisa
monitorar o repositório principal para que possa corrigir qualquer problema que possa ocorrer. A
consequência desta responsabilidade é que ele não deve ir para casa até que a build do repositório principal
tenha passado por qualquer commit ele tenha realizado durante o dia.

Existem duas formas principais que eu vejo para assegurarmos que isso ocorra: usando um processo
manual de build ou um servidor de integração contínua. Descrever a abordagem da build manual é simples.
Essencialmente ela é similar a build local que um desenvolvedor faz antes de lançar suas alterações no
repositório. O desenvolvedor vai para a máquina de integração, checa a versão do repositório principal
( que é o último commit feito da casa) e faz a build de integração. Ele verifica todo este processo, e se a
build for feita com sucesso ele finaliza seu commit (veja também a descrição de Jim Shore's).

Um servidor de integração contínua age como um monitor para o repositório. Toda vez que um commit é
feito no repositório o servidor automaticamente checa as fontes na máquina de integração, inicia a build, e
notifica para quem fez o commit o resultado da build. Quem fez a build não a considera terminada
enquanto ele não recebe uma notificação - geralmente por e-mail. Na ThoughWorks, nós somos grandes
fãs de servidores de integração contínua - na verdade nós gerenciamos o desenvolvimento original do
CruiseControl e do CruiseControl.NET, um servidor open-source de IC largamente usado. Desde então nós
também construímos o servidor de IC comercial chamado Cruise. Nós usamos um servidor de IC quase que
com todos os projetos que nós fazemos, e temos sido muito felizes com os resultados.

Nem todos preferem usar um servidor de IC. Jim Shore deu uma boa descrição do porquê ele prefere uma
abordagem manual. Eu concordo com ele que IC é muito mais que somente a instalação de qualquer
software. Todas as práticas citadas aqui são feitas efetivamente na IC. Mas igualmente muitos times que
fazem IC acharão bom um servidor de IC para ser uma ferramenta útil.Muitas organizações fazem builds
regulares em um tempo marcado, tipo toda noite. Isso não é a mesma coisa como uma build contínua e não
é o suficiente para a IC. O ponto principal da IC é ajudar a encontrar os problemas o mais rápido possível.
Builds noturnas significam que os erros ficam desapercebidos durante um dia inteiro antes que qualquer
um os descubram. Uma vez que eles ficam muito tempo no sistema, eles demoram um longo tempo para
serem encontrados e removidos.

O ponto chave de se ficar fazendo a build de integração é que se a build do repositório principal falhar, ela
será corrigida no jeito certo. A idéia central de se estar trabalhando com a IC é que você sempre desenvolve
em uma base conhecida e estável. Não é uma coisa ruim a build do repositório principal falhar, embora se
isso acontecer o tempo todo é sinal que as pessoas não estão sendo cuidadosas o suficiente em atualizar e
realizar a build localmente antes de realizarem o commit. Quando a build do repositório principal quebrar,
entretanto, é importante que seja corrigida rapidamente. Para ajudar a evitar o quebramento do repositório
principal, você pode considerar usar uma pending head.

Quanto as equipes que são iniciantes na IC, frequentemente esta é uma das coisas mais difíceis para se
resolver. Uma equipe deve lutar para o quanto antes conseguir ter o hábito de trabalhar em builds da versão
principal, particularmente se ela estiver trabalhando sobre uma base existente de código. Paciência e
constância geralmente são boas dicas, portanto não desista.

Mantenha a Build rápida

O foco da IC é prover um feedback rápido. Nada é mais prejudicial as atividades da IC que uma build que
toma muito tempo. Neste ponto eu tenho que admitir que existia um pouco de velho cara que considerava
que uma build tinha que ser longa. A maior parte dos meus colegas consideram que uma build de uma hora
é totalmente sem sentido. Eu me lembro de equipes sonhando que poderiam fazer isso tudo muito rápido e
que ocasionalmente eles continuam rodando certos casos onde é muito difícil ter builds nesta velocidade.

Para a maior parte dos projetos, entretanto, a linha de build do XP de 10 minutos é, com razão, perfeita. A
maioria dos nossos projetos modernos conseguem atingir isso. Isto é digno de se concentrar esforços para
fazer com que aconteça, porque a cada minuto que você reduz o tempo da build é um minuto salvo para
cada desenvolvedor a cada momento que ele realiza um commit. Uma vez que a IC demanda commits
frequentes, ela economiza muito tempo.

Se você estiver começando com uma build de uma hora, começar a fazer a build cada vez mais rápido pode
parecer intimidante. Isso pode até mesmo ser assustador começar a trabalhar em um projeto novo e pensar
em manter as coisas rápidas. Para aplicações empresariais, ao menos, nos temos visto que o principal
gargalo é testar - particularmente testes que envolvam serviços externos como uma base de dados.

Provavelmente o ponto mais importante é começar trabalhando na configuração de uma staged build (ou
build por estágios, ou também build encadeada). A idéia por trás de uma staged build é que existe de fato
multiplos builds feitas em sequência. O commit no repositório principal aciona a primeira build, que eu
chamo de commit build. A commit build é a build que necessitou ser executada quando alguém atualizou o
repositório principal. A commit build é a que tem que ser feita rapidamente, como consequência esta
tomará alguns atalhos que diminuirão a capacidade de se achar bugs. O truque é balancear a necessidade de
procurar bugs e a velocidade para que haja uma commit build estável o suficiente para que outras pessoas
possam trabalhar.

Uma vez que a commit build é boa, então outras pessoas podem trabalhar no código com confiança.
Entretanto existem testes novos e lentos que você pode começar a fazer. Máquinas adicionais podem rodar
novas rotinas de testes na build que precisa de mais tempo.

Um exemplo simples disto é uma build de dois estágios. O primeiro estágio deve realizar a compilação e
rodar os testes que são mais focados nos testes unitários com a base de dados vazia. Tais testes podem
rodar muito rápido, dentro da linha de 10 minutos. Entretanto qualquer problema que envolva uma escala
maior de interações, particularmente aqueles envolvendo a base de dados real, não serão encontrados. O
segundo estágio roda em uma suite diferente de testes que acessam a base de dados real e envolve um
comportamento de ponta-a-ponta. Essa suite pode tomar algumas horas para rodar.

Neste cenário as pessoas usam o primeiro estágio com a commit build e a usam para os seus ciclos
principais da IC. O segundo estágio é formado por uma build secundária que roda quando possível,
pegando os executáveis da ultima build válida para novos testes. Se a build secundária falhar, então isto
não terá o mesmo "pare tudo", mas o time precisa ter o objetivo de corrigir os problemas tão rápido quando
possível, enquanto mantem funcionando a build de commit. Na verdade a build secundária não tem que ser
sempre boa, tão logo os problemas sejam identificados e tratados em poucos dias. Como neste exemplo, as
builds secundárias são frequentemente testes puros, desde que estes testes causem lentidão.
Se a build secundária detectar um problema, isso é um sinal que a commit build poderia fazer outro teste.
Assegure-se o tanto quanto possível que qualquer falha na build secundária te leve a novos testes na
commit build onde você deve pegar o problema, para que os problemas fiquem corrigidos na commit build.
Desta forma os testes de commit são reforçados sempre que alguma coisa passar por eles. Existem casos
onde não existem como construir um teste que rode rápido e que exponha o erro, então você pode decidir
somente testar aquela condição na build secundária. Felizmente, na maior parte do tempo, você pode
adicionar testes apropriados para a commit build.

Este exemplo é de uma build de dois estágios, mas o principio básico pode ser extendido para qualquer
número de builds posteriores a principal. As builds posteriores a commit build pode também serem feitas
em paralelo, então se você tem duas horas de testes secundários você pode melhorar o tempo e resposta do
processo tendo duas máquinas que rodam metade dos testes cada. Usando builds secundárias paralelas
desta forma você pode introduzir todos tipo de novos testes automáticos, incluindo teste de performance,
dentro do processo regular de build (eu tenho rodado muitas técnicas interessantes como essa assim que
visitei muitos projetos da ThoughtWorks nos últimos anos - e estou esperançoso para incentivar alguns dos
desenvolvedores a escreve-las).

Teste em uma cópia do ambiente de produção

O ponto central dos testes é trazer a tona, dentro de condições controladas, qualquer problema que o
sistema vai ter em produção. Um parte significante disto é que o ambiente onde eles irão rodar deve ser
como o de produção. Se você testar em um ambiente diferente, toda diferença resultará no risco das
situações sob teste não acontecerem em produção.

Uma solução para isso é que você configure seu ambiente de teste, dentro possível, para ser uma cópia
exata do seu ambiente de produção. Use o mesmo software de banco de dados, com as mesmas versões,
use a mesma versão do sistema operacional. Bote todas as bibliotecas que estão no ambiente de produção
para o ambiente de teste, mesmo que o sistema atualmente não as use. Use o mesmo endereço IP e portas,
rodando no mesmo hardware.

Bom, na verdade existem limites. Se você esta escrevendo um software desktop não é prático testar em
uma cópia em todos os desktops possíveis com todas as partes terceirizadas do software que as diferentes
pessoas estão rodando. Da mesma forma, alguns ambientes de produção podem ser caras demais para
serem duplicadas (embora eu tenho encontrado frequentemente falsas economias não duplicando ambientes
nem tão caros assim). Apesar destes limites, seu objetivo deve continuar sendo duplicar o ambiente de
produção tanto quanto possível e entender que os riscos que você estará aceitando por cada diferença entre
os ambientes de teste e produção.

Se você tem uma configuração boa e simples, sem ter que fazer muitas comunicações incomodas, você
pode rodar sua commit build em um ambiente copiado. Frequentemente, entretanto, você necessitará fazer
testes duplos, porque os sistemas responderão lenta ou intermitentemente. Como um resultado, é comum
ter um ambiente muito artificial para os tests de commit, e usar uma cópia da produção para os testes
secundários.

Eu tive notícias em um crescente interesse em usar virtualização para tornar fácil juntar ambientes de
testes. Máquinas virtuais podem ser salvas com todos os elementos necessários juntos na virtualização. É
relativamente simples instalar a última build e rodar os testes. Além disso, isto permite a você rodar
multiplos testes em uma máquina, ou simular várias máquinas em uma rede com uma única máquina.
Como o ônus da performance tem diminuido, esta opção faz cada vez mais sentido.

Torne fácil para qualquer um ter o último executável.

Uma das partes mais difíceis de desenvolvimento de software é ter certeza de que você esta construindo o
software certo. Nós temos visto que é muito difícil especificar adiantadamente o que você quer e estar
correto. Pessoas acham mais fácil ver algo que não é bom o bastante e dizer como isto precisa ser alterado.
Os processos de desenvolvimento ágeis incentiva explicitamente e tomam vantagem desta parte do
comportamento humano.

Para ajudar a fazer este trabalho, qualquer um envolvido com um projeto de software deve ser hábil para
ter a última versão executável e ser capaz de roda-la: para demonstrações, testes exploratórios ou
simplesmente ver o que mudou esta semana.

Faça isto ser bem simples: tenha certeza que existe um bom lugar conhecido onde as pessoas possam pegar
o último executável. Pode ser útil pôr muitos executáveis em um lugar comum. Para a versão mais recente
você deve por o último executável que passou nos testes de commit - como um executável, ele deve ser
estável.

Se você estiver seguindo um processo com iterações bem definidas, geralmente é sábio por também junto o
resultado final das builds da iteração. Demostrações, em particular, precisam do software cuja as
características são familiares, então geralmente vale a pena por a última versão para alguma coisa
necessária para quem estiver mostrando o software

Todos pode ver o que esta acontecendo.

Tudo sobre Integração Contínua esta relacionado a comunicação, então você precisa ter certeza que todos
possam facilmente ver o estado do sistema e as mudanças que tem sido feitas nele.

Uma das coisas mais importantes para se comunicar é o estado da build da versão principal. Se você estiver
usando o Cruise existe uma ferramenta embutida no site dele que irá mostrar a você se existe uma build em
progresso e o qual foi o estado da última build da versão principal. Muitos times gostam de fazer esta
informação chamar mais a atenção colocando um display mostrando o sistema de build - com as populares
luzes verde (quando a build funciona) e vermelha (quando ela falha). Um jeito particular é por algo como
as lampadas de lava verde e vermelha - não somente para indicar o estado da build mas também para
indicar por quanto tempo tem permanecido cada estado. Bolhas em uma lâmpada vermelha indica que a
build tem quebrado por muito tempo. Cada time faz suas próprias escolhas sobre esses sensores da build - é
bom ser informal com sua escolha (recentemente eu vi alguém experimentando por um coelho dançando).

Se você estiver usando um processo de IC manual, a visibilidade deste continua sendo essencial. O monitor
da máquina de build pode mostrar o status da build da versão principal. Frequentemente você tem algo para
ser posto na mesa de qualquer um que esteja fazendo atualmente a build (novamente alguma coisa boba
como uma galinha de borracha é uma boa opção). Geralmente as pessoas gostam de fazer um som simples
avisando boas builds, como um som de um sino.

As páginas dos servidores de IC pode trazer mais informações que estas, claro. Cruise oferece um
indicador não somente de quem esta fazendo a build, mas quais mudanças ele fez. Cruise também provê
um histórico de mudanças, permitindo membros da equipe ter uma boa informação das recentes atividades
no projeto. Eu conheço equipes que gostam de usar isto para ter um senso do que as pessoas tem feito e
manter uma idéia das mudanças feitas no sistema.

Outra vantagem de usar um site é para aqueles que não estão próximos fisicamente poderem ter uma idéia
do status do projeto. Normalmente eu prefiro ter todos que estão trabalhando ativamente no projeto juntos,
mas geralmente existem pessoas longes onde seja bom que tenham idéia de como as coisas estão. O site
também é útil para as equipes para manter junto informações de builds de vários projetos - gerando um
status simples e automático dos diferentes projetos.

Um bom painel de informações não são somente aqueles em uma tela de computador. Um dos meus
painéis favoritos foi de um projeto que estava começando na IC. Ele tinha uma história longa de problemas
em fazer builds estáveis. Nós colocamos um calendário na parede que mostrava um ano inteiro com um
pequeno quadrado para cada dia. Todo dia o grupo de controle de qualidade (QA) colocaria um adesivo
verde quando recebia uma build estável que passou nos testes, ou, colocaria um adesivo vermelho. Com o
passar do tempo o calendário revelou que o estado do processo de build mostrava um crescimento estável
até que os quadrados verdes eram tão comuns que o calendário desapareceu - com seu propósito cumprido.

Automatize a Implantação do Sistema

Para fazer a Integração Contínua você precisará de multiplos ambientes, um para rodar os testes de commit
(ou commit build), um ou mais para rodar os testes secundários. Uma vez que você esteja movendo os
executáveis entre estes ambientes várias vezes por dia, você vai querer fazer isso automaticamente. Então é
importante ter scripts que permitam você implantar a aplicação dentro de qualquer ambiente facilmente.
Uma consequência natural disto é que você deve ter scripts que permitam você implantar o software dentro
do ambiente de produção tão facilmente quanto nos outros ambientes. Você pode não implantar o software
no ambiente de produção todos os dias (embora em tenho rodado projetos em que isso aconteça), mas
implantações automáticas ajudam tanto a tornar o processo mais rápido quanto a reduzir erros. E isto é
também uma opção barata desde que você use somente as mesmas configurações que você usa nos deploys
dos ambientes de teste .

Se você implantar alguma função extra no ambiente de produção você deve checar se isto terá um rollback
(ou reverter) automático. Coisas ruins podem acontecer de tempos em tempos, e se algo não der certo é
bom ser capaz de desfazer rapidamente tudo para a última versão boa conhecida. Ser capaz de reverter
automaticamente também reduz muita tensão durante a implantação, encorajando as pessoas a realizarem
deploy ( entrega e implantação de uma versão) com mais frequência e assim ter novas funcionalidades para
entregarem para os usuários rapidamente. ( A comunidade Ruby on Rails desenvolveu uma ferramenta
chamada Capistrano que é um bom exemplo de uma ferramenta que faz esse tipo de coisa).

Em ambientes em cluster nós temos visto processos de implantação acontecerem onde um novo software é
implantando em um nó por vez, substituindo gradualmente a aplicação durante o curso de poucas horas.
Veja o artigo relacionado Evolutionary Database Design.

Um empecilho para muitas pessoas que fazem releases frequentes é a migração de banco de dados.
Mudanças na base de dados são dolorosas porque você não pode simplesmente mudar os schemas do banco
de dados, você tem também que assegurar que os dados migraram corretamente. Este artigo descreve
técnicas usadas por meu colega Pramod Sadalage para fazer a refatoração automática e a migração dos
bancos de dados. O artigo é uma tentativa rápida de captar a informação descrita em maiores detalhes pelo
livro do Pramod e Scott Amblers sobre refatoração de banco de dados.

Uma variação particular e interessante disto que eu tenho visto surgir com a aplicação web pública é a idéia
de implantar uma versão limitada para um grupo menor de usuários. O time então vê como essa versão
limitada é usada antes de decidir se implantada o sistema para todos os usuários. Isto permite você testar
novas funcionalidades de interfaces com o usuário antes de prosseguir para uma versão final. Implantação
automatizada aliada a uma boa disciplina de IC é essencial para fazer isso funcionar.

Benefícios da Integração Contínua

Olhando isso tudo eu penso que o maior e mais abrangente benefício da Integração Contínua é a redução de
riscos. Minha mente continua flutuando de volta para aquele projeto de software anterior que eu mencionei
no meu primeiro paragrafo. La as pessoas estavam no final (ao menos acreditavam) de um longo projeto,
sem ainda uma idéia real de quão longo isto deveria ser antes de terem terminado.

O problema com aquela forma de integração narrada é que é muito difícil saber o quão longa ela será, e o
pior é que é muito difícil saber o quão longe você terá que ir neste processo. O resultado é que você esta
pondo completamente a si mesmo em um ponto cego justamente em uma das partes mais tensas do projeto
- mesmo que você esteja em um dos raros casos de ainda não estar atrasado. Integração Contínua reduz
completamente este problema. Não existe uma integração longa, você elimina completamente o ponto
cego. Em todo tempo você sabe onde você esta, o que funciona, o que não funciona e os bugs pendentes
que você tem em seu sistema.

Bugs - estes são as coisas sórdidas que destroem a confiança, bagunçam os cronogramas e as reputações.
Bugs no software implantando fazem os usuários ficarem com raiva de você. Bugs no trabalho em
progresso entram em seu caminho, tornando difícil ter o resto do software funcionando corretamente.

Integração Contínua não nos livra dos bugs, mas os tornam dramaticamente mais fáceis de encontrar e
remover. O grande responsável por este aspecto é o código auto-testável. Se você introduzir um problema e
detecta-lo rapidamente, é mais fácil remover os problemas. Desde que você modificou somente uma parte
pequena do sistema, você não tem que olhar muita coisa. Desde que aquele pedaço do sistema é o pedaço
com que você trabalhou, ele ainda esta fresco em sua memória, novamente tornando fácil de encontrar o
problema. Você também pode usar um diff debugging (ou um avaliador de diferenças) - comparando a
versão corrente do sistema com uma versão anterior que não tinha o bug.

O bugs também são cumulativos. Quanto mais bugs você tiver, mais difíceis são se serem removidos. Em
parte isto acontece porque você tem interações entre os bugs, onde as falhas são apresentadas como o
resultado de múltiplos erros - tornando cada erro cada vez mais difícil de ser encontrado. E isto também é
psicológico - pessoas tem menos energia para encontrar e eliminar os bugs quando existem vários deles -
um fenômeno que os programadores pragmaticos chamam de síndrome da Janela Quebrada.

Para uma resposta a isso, projetos com IC tendem a ter dramaticamente menos bugs, tanto em produção
quanto em desenvolvimento. Entretanto eu devo ressaltar que o grau deste benefício esta diretamente
amarrado a quão boa sua suite de testes é. Você deve entender que não tão difícil construir uma suite de
teste que faça uma diferença notável. Geralmente, entretanto, leva um tempo antes que o time consiga
chegar ao mesmo nível dos bugs que eles tem que procurar. Avançar este nível envolve trabalhar
constantemente e melhorar seus testes.

Se você trabalha com IC, este remove uma das maiores barreiras na implantação frequente. As frequentes
implatações são valorosas porque elas permitem seus usuários terem as novas funcionalidades mais
rapidamente, para darem feedback mais rapidamente sobre estas funcionalidades e geralmente se tornarem
mais colaborativos no ciclo de desenvolvimento. Isto ajuda a quebrar as barreiras entre os desenvolvedores
e os clientes - barreiras que eu acredito serem as maiores barreiras para desenvolvimento de software com
sucesso.

Introduzindo a Integração Contínua

Então você imagina tentar a Integração Contínua - por onde você começa? Eu mostrei acima todo o
conjunto de práticas para te mostrar todos os benefícios - mas você não precisa começar com tudo isso.

Não existe uma aqui receita fixa - muita coisa depende da natureza do seu ambiente e do seu time. Mas
aqui estão algumas coisas que nós temos aprendido pra ter as coisas funcionando. Um dos primeiros passos
é ter uma build automatizada. Ter todo que você precisa dentro do seu controle de código para que você
possa então ter todo o sistema com um único comando. Para muitos projetos isto não é uma coisa pequena -
isso é na verdade essencial para qualquer uma das outras coisas funcionarem. Inicialmente você pode fazer
a build sob demanda, ou simplesmente fazer uma build noturna automatizada. Enquanto ainda não tem um
Integração Contínua, ter uma build noturna automatizada é um bom passo.

Introduza alguns testes automatizados na sua build. Tente identificar as áreas onde geralmente as coisas
dão erradas e faça testes automáticos que exponham estas falhas. Particularmente, em um projeto existente
é difícil ter realmente uma boa suite de testes funcionando rapidamente - leva tempo para construir os
testes. Você deve começar com o pensamento em algum lugar especifico.

Tente agilizar a commit build. Integração Contínua com uma build de poucas horas é melhor do que nada,
mas diminuir para o número mágico de 10 minutos é bem melhor. Isto geralmente requer algumas cirurgias
sérias em sua base de código, como quebrar as dependências das partes lentas do sistema.

Se você estiver começando em um projeto novo, comece com a Integração Contínua desde o início.
Mantenha os olhos nos tempos da build e tome alguma ação logo quando quando começar a ficar mais
lento que a regra dos 10 minutos. Agindo rapidamente você irá fazer as reestruturações necessárias antes
que a base de código fique tão grande que isso se transforme em um problema maior.

Acima de tudo tenha alguma ajuda. Encontre alguém que tenha feito integração contínua antes que possa
ajudar você. Como qualquer técnica nova, é difícil introduzi-la quando você não sabe como o resultado
final deve parecer. Pode custar algum dinheiro ter um mentor, mas você pode também pagar por tempo e
produtividade perdidos se você não sabe fazer isso. ( Aviso: sim, nós da ThoughtWorks fazemos algumas
consultorias nesta área. Afinal de contas nós cometemos a maior parte dos erros que podem ser feitos).

Pensamentos Finais

Desde que Matt e eu escrevemos a versão original desde artigo, a Integração Contínua tem se tornado a
principal técnica para o desenvolvimento de software. Dificilmente qualquer projeto da ThoughWorks
acontece sem isso - e nós temos visto outros usando IC ao redor do mundo. Dificilmente eu ouço coisas
negativas sobre esta abordagem - ao contrário de algumas das mais controversas práticas do Extreme
Programming.

Se você não estiver usando Integração Contínua eu recomento fortemente você a tentar. Se você você
estiver usando, talvez algumas idéias pode ajudar a você fazer isso mais efetivamente. Nós temos
aprendido muito sobre Integração Contínua nos últimos anos, e eu espero que possamos continuar
aprendendo e melhorando isso ainda mais.

Leitura Indicada

Um ensaio como este pode somente cobrir por alto algumas coisas. Para explorar a Integração Contínua em
maiores detalhes, eu sugiro dar uma olhada no livro do Paul Duvall sobre este tema (que ganhou um
prêmio Jolt - mais do que eu já tenha alcançado). Não existem muitas coisas sendo escritas sobre builds por
estágios mas existe um ensaio escrito por Dave Farley na The ThoughtWorks Anthology que é útil
(também disponível aqui).
TDD (Test-driven Development)

Você também pode gostar