A integração contínua é uma prática, no desenvolvimento de software, onde os programadores integram as alterações que fazem ao código frequentemente e cujo objetivo é a deteção rápida de erros.

Este é o primeiro de uma série de artigos, onde apresentamos como criar um servidor de integração contínua para projetos PHP. Neste primeiro artigo fazemos uma análise às ferramentas que vamos usar.

Introdução

Uma boa explicação acerca do que é Integração Contínua foi dada pelo Martin Fowler neste artigo (em inglês).

O objetivo deste artigo não é explicar o que é nem quais os benefícios da utilização de integração contínua. Vamos, sim, explicar que ferramentas usamos para um projeto PHP e, nos seguintes artigos, como instalar e configurar essas ferramentas. No final, o nosso processo de desenvolvimento vai ter este fluxo:

Ferramentas para servidor de integração continua (CI) images/08-ferramentas-servidor-integracao-continua-ci/152-continuous-integration-flow-process.png

Neste primeiro artigo apresentamos uma breve descrição das ferramentas que iremos usar ao longo desta série de artigos. Cada tipo de software e cada aplicação daria um artigo e o objetivo desta descrição é perceber sucintamente o que é que cada ferramenta faz e porque é que a vamos usar.

Fica a nota: com base nas vossas necessidades, é possível que existam outras ferramentas mais adequadas e é recomendado que analisem todos os prós e contras de cada ferramenta.

Sistema de controlo de versões

Começamos por falar do sistema de controlo de versões, que é quase “obrigatório” em qualquer equipa de desenvolvimento de software, mesmo tendo apenas um membro. De forma simples, um sistema de controlo de versões regista todas as alterações feitas aos ficheiros do projeto (nomeadamente ficheiros de código), em que data foram feitas e qual o utilizador que efetuou essas alterações.

No momento de escolher uma solução é importante perceber a diferença entre um DVCS (Distributed Version Control System) e um CVS (Concurrent Version System).

Os sistemas DCVS têm um repositório central de código e esse repositório é “replicado” em cada cliente (programador). Com um sistema DCVS é possível várias pessoas trabalharem simultaneamente no mesmo ficheiro e, no momento do commit (registo de alterações no repositório) é feito um merge das alterações feitas pelos utilizadores. Outra das vantagens destes sistemas é a possibilidade de trabalhar sem a obrigatoriedade de estar ligado ao repositório central.

Já os CVS obrigam a que apenas um programador possa alterar um ficheiro num determinado momento (o conceito de checkout) e é necessário estar ligado ao repositório central para registar alterações feitas ao código (checkin).

As soluções mais comuns são:

Nesta série iremos implementar e usar o sistema Git porque:

  • É um sistema distribuído (DVCS)
  • Tem, provavelmente, a maior comunidade e, com isso, mais informação online
  • É simples de utilizar

Gestão de projeto, tarefas e defeitos

Um sistema de gestão de tarefas e defeitos (bugs) permite controlar e registar todas as alterações ao software do ponto de vista funcional. Isto é, permite controlar as alterações que são feitas sem necessidade de deambular pelo histórico do código fonte.

Entre as várias vantagens do uso destes sistemas está a possibilidade de controlar todas as alterações que são feitas numa determinada versão do software e, em alguns casos, permitir que os próprios clientes criem ou visualizem as alterações programadas para a aplicação.

Existem várias soluções, livres e comerciais, para fazer esta gestão, sendo as mais conhecidas:

Nesta série iremos implementar o Redmine, uma solução livre desenvolvida em Ruby on Rails, que:

  • Permite criar vários projetos
  • Tem bastantes plugins para estender as suas funcionalidades
  • É simples e não é feio
  • Permite a criação de versões e milestones (com plugin)
  • Permite o registo de horas por cada tarefa e por cada utilizador

Ferramentas de Integração Contínua

O software de Integração Contínua é a “cola” que junta todas as partes. A função básica deste tipo de software é:

  1. Ter mecanismos para despoletar uma configuração (build)
  2. Ir buscar a última versão de código ao repositório central
  3. Executar um conjunto de instruções
  4. Produzir métricas e artefactos

Uma “configuração” é um processo, composto por várias etapas, despoletado num determinado momento, que produz determinados artefactos. Um exemplo mais objetivo de uma “configuração” pode ser:

  1. Configurada para ser executada sempre que seja feito um commit por qualquer programador
  2. Quando é despoletada tem início o processo:
    1. Atualização do código na ferramenta de integração continua
    2. Atualização de dependências externas e automatismos (por exemplo, comprimir e juntar todos os Javascripts e CSS)
    3. Execução de todos ou de uma série de testes automáticos
    4. Produção de métricas tendo em conta os testes executados
    5. Produção de artefactos prontos a serem implementados nos servidores ou clientes

Normalmente estas etapas são sequenciais e exclusivos. Ou seja, se uma das etapas não for executada com sucesso, as etapas seguintes não serão executadas.

Existem várias ferramentas de integração continua, comerciais ou de livre uso, cada uma com os seus prós e contras. No momento de escolha é preciso saber qual a linguagem de programação do projeto e quais as suas restrições. Por exemplo, nem todas as ferramentas suportam PHP, mas a grande maioria suporta projetos Java e .net.

Para projetos PHP existem algumas alternativas e talvez a mais comum seja o Jenkins. No entanto, nesta série vamos optar pelo TeamCity, da JetBrains por três motivos:

  1. Interface: os olhos também comem e o Jenkins pode ser uma boa opção, mas a interface não é intuitiva
  2. É gratuito: o TeamCity é gratuito desde que não se exceda o limite de 20 configurações (builds) e 3 agentes
  3. IDE: o TeamCity tem integração com o IDE PHPStorm (também da JetBrains), que uso e considero o melhor IDE para PHP

Como disse, cada configuração (build) tem um conjunto de etapas que devem ser executadas e o TeamCity, para o usarem gratuitamente, tem um limite de 20 configurações. Exemplos de configurações:

  • Configuração para correr os testes unitários a cada commit
  • Configuração para correr todos os testes (unitários, funcionais e de aceitação) uma vez por dia
Ferramentas para servidor de integração continua (CI) images/08-ferramentas-servidor-integracao-continua-ci/160-teamcity-build-steps.png

Os agentes são as máquinas (computadores) onde serão executadas as etapas das builds e para a versão livre podem usar no máximo dois agentes. É possível instalarem um agente no próprio servidor onde reside o TeamCity, mas podem instalar em máquinas independentes.

Como exemplo, se desenvolverem projetos PHP que tenham de funcionar em Windows e Linux, com Apache e IIS, é uma boa ideia criar dois agentes:

  • Uma máquina Linux com Apache
  • Uma máquina Windows com IIS

Desta forma, se usarem o Selenium para executar testes de aceitação, podem garantir que a interface é igual independentemente do sistema operativo do servidor e independente do servidor web.

A utilização de vários agentes é útil para qualquer projeto, porque permite emular o funcionamento do software com configurações diferentes. Se programarem aplicações para Windows, é possível preverem o funcionamento em diferentes versões do sistema operativo (por ex, Windows Vista e Windows 8).

Métricas e qualidade

O principal objetivo do CI é a garantia da qualidade do software. Mas é insuficiente correr testes se não se tiver uma noção geral do estado do software.

Para isso, iremos implementar o SonarQube, que permite fazer a análise de vários projetos (entre outros, Java, .net e PHP). A informação que se pretende retirar do SonarQube é:

  • Code Coverage: qual a percentagem de código de todo o projeto que está coberta por testes
  • Número de linhas, classes e ficheiros
  • Quantidade de código comentado (número de linhas de comentários)
  • Quantidade de código repetido
  • Dívida do projeto (Technical debt)
  • E, mais importante, o que é necessário fazer para melhorar o projeto

A dívida (technical debt) representa o tempo necessário para corrigir e melhorar o projeto. Ou seja, se o vosso código for demasiado complexo (demasiados ciclos entreligados, métodos demasiado extensos, …) ou se não cumprirem as boas práticas (coding standards) em uso, vão ter divida técnica alta. A menos que vão retificando o código, esta dívida vai aumentar.

Como compreendem, quanto menos dívida existir, mais fácil é a manutenção do projeto.

Ferramentas para servidor de integração continua (CI) images/08-ferramentas-servidor-integracao-continua-ci/163-sonarqube-info.png

Existem outras alternativas como o Squale. Eu fiquei adepto do SonarQube assim que comecei a trabalhar com ele porque acho que é uma ferramenta simples, poderosa e intuitiva e é esse o motivo pelo qual vamos usar esta ferramenta.

Instalações e funcionamento

Resta dizer que para o servidor irei usar o Linux Mint 17.1. Se quiserem usar o servidor em produção recomendo que usem o CentOS e que escolham uma versão LTS (Long Term Support), para não terem dificuldades com os repositórios de updates passado uns meses.

  Este artigo faz parte da série Como criar um servidor de integração contínua